//===--- 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 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 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 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 { // Reuse all the ctors using llvm::ArrayRef::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 args() const { return drop_front(); } }; /// Represents a debug info expression in SIL class SILDebugInfoExpression { friend class TailAllocatedDebugVariable; llvm::SmallVector Elements; public: SILDebugInfoExpression() = default; explicit SILDebugInfoExpression(llvm::ArrayRef 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 elements() { return llvm::make_range(element_begin(), element_end()); } llvm::iterator_range 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 NewElements) { if (NewElements.size()) Elements.append(NewElements.begin(), NewElements.end()); } void append(const SILDebugInfoExpression &Tail) { appendElements(Tail.Elements); } void prependElements(llvm::ArrayRef 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 Remain; void increment(); explicit op_iterator(llvm::ArrayRef 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{}); } llvm::iterator_range 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