mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
We do keep the fragment part of the expression as it is important to identify fragments separately. A variable with less fragments should be considered a superset of variables with more fragments, but that would require to change a lot of code.
319 lines
9.2 KiB
C++
319 lines
9.2 KiB
C++
//===--- SILDebugInfoExpression.h - DIExpression for SIL --------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// This file contains types that model debug info expressions in SIL. Including
|
|
/// (debug info) operator and operand.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_DEBUGINFOEXPRESSION_H
|
|
#define SWIFT_SIL_DEBUGINFOEXPRESSION_H
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "llvm/ADT/APInt.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/Hashing.h"
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <optional>
|
|
|
|
namespace swift {
|
|
|
|
class TailAllocatedDebugVariable;
|
|
|
|
/// Operator in a debug info expression
|
|
enum class SILDIExprOperator : unsigned {
|
|
INVALID = 0,
|
|
/// Dereferences the SSA value
|
|
Dereference,
|
|
/// Specifies that the SSA value is a fragment (sub-field) of the
|
|
/// associated source variable. This operator takes a single
|
|
/// VarDecl operand pointing to the field declaration.
|
|
/// Note that this directive can only appear at the end of an
|
|
/// expression, along with `TupleFragment`.
|
|
Fragment,
|
|
/// Perform arithmetic addition on the top two elements of the
|
|
/// expression stack and push the result back to the stack.
|
|
Plus,
|
|
/// Subtract the top element in expression stack by the second
|
|
/// element. Then push the result back to the stack.
|
|
Minus,
|
|
/// Push an unsigned integer constant onto the stack.
|
|
ConstUInt,
|
|
/// Push a signed integer constant onto the stack.
|
|
ConstSInt,
|
|
/// Specifies that the SSA value is an element of the
|
|
/// associated tuple. This operator takes a TupleType
|
|
/// operand pointing to the tuple type, and the index of the element.
|
|
/// Note that this directive can only appear at the end of an
|
|
/// expression, along with `Fragment`.
|
|
TupleFragment
|
|
};
|
|
|
|
/// Represents a single component in a debug info expression.
|
|
/// Including operator and operand.
|
|
struct SILDIExprElement {
|
|
enum Kind {
|
|
/// A di-expression operator.
|
|
OperatorKind,
|
|
/// An operand that has declaration type.
|
|
DeclKind,
|
|
/// An integer constant value. Note that
|
|
/// we don't specify its signedness here.
|
|
ConstIntKind,
|
|
/// An operand that has `Type` type.
|
|
TypeKind
|
|
};
|
|
|
|
private:
|
|
Kind OpKind;
|
|
|
|
union {
|
|
SILDIExprOperator Operator;
|
|
Decl *Declaration;
|
|
uint64_t ConstantInt;
|
|
Type TypePtr;
|
|
};
|
|
|
|
explicit SILDIExprElement(Kind OpK) : OpKind(OpK) {}
|
|
|
|
public:
|
|
Kind getKind() const { return OpKind; }
|
|
|
|
SILDIExprOperator getAsOperator() const {
|
|
return OpKind == OperatorKind ? Operator : SILDIExprOperator::INVALID;
|
|
}
|
|
|
|
Decl *getAsDecl() const { return OpKind == DeclKind ? Declaration : nullptr; }
|
|
|
|
std::optional<uint64_t> getAsConstInt() const {
|
|
if (OpKind == ConstIntKind)
|
|
return ConstantInt;
|
|
else
|
|
return {};
|
|
}
|
|
|
|
Type getAsType() const { return OpKind == TypeKind ? TypePtr : nullptr; }
|
|
|
|
static SILDIExprElement createOperator(SILDIExprOperator Op) {
|
|
SILDIExprElement DIOp(OperatorKind);
|
|
DIOp.Operator = Op;
|
|
return DIOp;
|
|
}
|
|
|
|
static SILDIExprElement createDecl(Decl *D) {
|
|
SILDIExprElement DIOp(DeclKind);
|
|
DIOp.Declaration = D;
|
|
return DIOp;
|
|
}
|
|
|
|
static SILDIExprElement createConstInt(uint64_t V) {
|
|
SILDIExprElement DIOp(ConstIntKind);
|
|
DIOp.ConstantInt = V;
|
|
return DIOp;
|
|
}
|
|
|
|
static SILDIExprElement createType(Type T) {
|
|
SILDIExprElement DIOp(TypeKind);
|
|
DIOp.TypePtr = T;
|
|
return DIOp;
|
|
}
|
|
};
|
|
|
|
/// Returns the hashcode for the di expr element.
|
|
inline llvm::hash_code hash_value(const SILDIExprElement &elt) {
|
|
return llvm::hash_combine(elt.getKind(), elt.getAsDecl(), elt.getAsDecl(),
|
|
elt.getAsConstInt());
|
|
}
|
|
|
|
/// For a given SILDIExprOperator, provides information
|
|
/// like its textual name and operand types.
|
|
struct SILDIExprInfo {
|
|
StringRef OpText;
|
|
SmallVector<SILDIExprElement::Kind, 2> OperandKinds;
|
|
|
|
static const SILDIExprInfo *get(SILDIExprOperator Op);
|
|
};
|
|
|
|
/// A DIExpr operand is consisting of a SILDIExprOperator and
|
|
/// SILDIExprElement arguments following after.
|
|
struct SILDIExprOperand : public llvm::ArrayRef<SILDIExprElement> {
|
|
// Reuse all the ctors
|
|
using llvm::ArrayRef<SILDIExprElement>::ArrayRef;
|
|
|
|
SILDIExprOperator getOperator() const {
|
|
assert(size() && "empty DIExpr operand");
|
|
const SILDIExprElement &First = front();
|
|
return First.getAsOperator();
|
|
}
|
|
|
|
size_t getNumArg() const {
|
|
assert(size() && "empty DIExpr operand");
|
|
return size() - 1;
|
|
}
|
|
|
|
llvm::ArrayRef<SILDIExprElement> args() const {
|
|
return drop_front();
|
|
}
|
|
};
|
|
|
|
/// Represents a debug info expression in SIL
|
|
class SILDebugInfoExpression {
|
|
friend class TailAllocatedDebugVariable;
|
|
llvm::SmallVector<SILDIExprElement, 2> Elements;
|
|
|
|
public:
|
|
SILDebugInfoExpression() = default;
|
|
|
|
explicit SILDebugInfoExpression(llvm::ArrayRef<SILDIExprElement> EL)
|
|
: Elements(EL.begin(), EL.end()) {}
|
|
|
|
void clear() { Elements.clear(); }
|
|
|
|
size_t getNumElements() const { return Elements.size(); }
|
|
|
|
using iterator = typename decltype(Elements)::iterator;
|
|
using const_iterator = typename decltype(Elements)::const_iterator;
|
|
|
|
iterator element_begin() { return Elements.begin(); }
|
|
iterator element_end() { return Elements.end(); }
|
|
|
|
const_iterator element_begin() const { return Elements.begin(); }
|
|
const_iterator element_end() const { return Elements.end(); }
|
|
|
|
llvm::iterator_range<iterator> elements() {
|
|
return llvm::make_range(element_begin(), element_end());
|
|
}
|
|
|
|
llvm::iterator_range<const_iterator> elements() const {
|
|
return llvm::make_range(element_begin(), element_end());
|
|
}
|
|
|
|
const SILDIExprElement &getElement(size_t index) const {
|
|
assert(index < Elements.size());
|
|
return Elements[index];
|
|
}
|
|
|
|
void push_back(const SILDIExprElement &Element) {
|
|
Elements.push_back(Element);
|
|
}
|
|
|
|
void appendElements(llvm::ArrayRef<SILDIExprElement> NewElements) {
|
|
if (NewElements.size())
|
|
Elements.append(NewElements.begin(), NewElements.end());
|
|
}
|
|
|
|
void append(const SILDebugInfoExpression &Tail) {
|
|
appendElements(Tail.Elements);
|
|
}
|
|
|
|
void prependElements(llvm::ArrayRef<SILDIExprElement> NewElements) {
|
|
Elements.insert(Elements.begin(),
|
|
NewElements.begin(), NewElements.end());
|
|
}
|
|
|
|
void eraseElement(const_iterator It) {
|
|
Elements.erase(It);
|
|
}
|
|
|
|
/// The iterator for SILDIExprOperand
|
|
class op_iterator {
|
|
friend class SILDebugInfoExpression;
|
|
|
|
SILDIExprOperand Current;
|
|
llvm::ArrayRef<SILDIExprElement> Remain;
|
|
|
|
void increment();
|
|
|
|
explicit
|
|
op_iterator(llvm::ArrayRef<SILDIExprElement> Remain): Remain(Remain) {
|
|
increment();
|
|
}
|
|
|
|
public:
|
|
op_iterator() = default;
|
|
op_iterator(const op_iterator &) = default;
|
|
|
|
const SILDIExprOperand &operator*() const { return Current; }
|
|
const SILDIExprOperand *operator->() const { return &Current; }
|
|
|
|
// Pre increment
|
|
op_iterator &operator++() {
|
|
increment();
|
|
return *this;
|
|
}
|
|
|
|
// Post increment
|
|
op_iterator operator++(int) {
|
|
op_iterator This(*this);
|
|
increment();
|
|
return This;
|
|
}
|
|
|
|
bool operator==(const op_iterator &Other) const {
|
|
return (Current.empty() && Other.Current.empty()) ||
|
|
(Current.data() == Other.Current.data() &&
|
|
Current.size() == Other.Current.size());
|
|
}
|
|
bool operator!=(const op_iterator &Other) const {
|
|
return !(Other == *this);
|
|
}
|
|
};
|
|
|
|
op_iterator operand_begin() const {
|
|
return op_iterator(Elements);
|
|
}
|
|
op_iterator operand_end() const {
|
|
return op_iterator(llvm::ArrayRef<SILDIExprElement>{});
|
|
}
|
|
|
|
llvm::iterator_range<op_iterator> operands() const {
|
|
return llvm::make_range(operand_begin(), operand_end());
|
|
}
|
|
|
|
/// Return true if this expression is not empty
|
|
inline operator bool() const { return Elements.size(); }
|
|
|
|
/// Create a `op_fragment` expression
|
|
static SILDebugInfoExpression createFragment(VarDecl *Field);
|
|
|
|
/// Create a `op_tuple_fragment` expression
|
|
static
|
|
SILDebugInfoExpression createTupleFragment(TupleType *TypePtr, unsigned Idx);
|
|
|
|
/// Return true if this DIExpression starts with op_deref
|
|
bool startsWithDeref() const {
|
|
return Elements.size() &&
|
|
Elements[0].getAsOperator() == SILDIExprOperator::Dereference;
|
|
}
|
|
|
|
/// Return the part of this SILDebugInfoExpression corresponding to fragments
|
|
SILDebugInfoExpression getFragmentPart() const {
|
|
for (auto it = element_begin(), end = element_end(); it != end; ++it) {
|
|
if (it->getAsOperator() == SILDIExprOperator::Fragment
|
|
|| it->getAsOperator() == SILDIExprOperator::TupleFragment)
|
|
return SILDebugInfoExpression(ArrayRef(it, element_end()));
|
|
}
|
|
return {};
|
|
}
|
|
};
|
|
|
|
/// Returns the hashcode for the di expr element.
|
|
inline llvm::hash_code hash_value(const SILDebugInfoExpression &elt) {
|
|
return llvm::hash_combine_range(elt.element_begin(), elt.element_end());
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|