| //===- llvm/IR/DebugInfoMetadata.h - Debug info metadata --------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Declarations for metadata specific to debug info. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_IR_DEBUGINFOMETADATA_H |
| #define LLVM_IR_DEBUGINFOMETADATA_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/BitmaskEnum.h" |
| #include "llvm/ADT/None.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/iterator_range.h" |
| #include "llvm/BinaryFormat/Dwarf.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/Metadata.h" |
| #include "llvm/Support/Casting.h" |
| #include <cassert> |
| #include <climits> |
| #include <cstddef> |
| #include <cstdint> |
| #include <iterator> |
| #include <type_traits> |
| #include <vector> |
| |
| // Helper macros for defining get() overrides. |
| #define DEFINE_MDNODE_GET_UNPACK_IMPL(...) __VA_ARGS__ |
| #define DEFINE_MDNODE_GET_UNPACK(ARGS) DEFINE_MDNODE_GET_UNPACK_IMPL ARGS |
| #define DEFINE_MDNODE_GET_DISTINCT_TEMPORARY(CLASS, FORMAL, ARGS) \ |
| static CLASS *getDistinct(LLVMContext &Context, \ |
| DEFINE_MDNODE_GET_UNPACK(FORMAL)) { \ |
| return getImpl(Context, DEFINE_MDNODE_GET_UNPACK(ARGS), Distinct); \ |
| } \ |
| static Temp##CLASS getTemporary(LLVMContext &Context, \ |
| DEFINE_MDNODE_GET_UNPACK(FORMAL)) { \ |
| return Temp##CLASS( \ |
| getImpl(Context, DEFINE_MDNODE_GET_UNPACK(ARGS), Temporary)); \ |
| } |
| #define DEFINE_MDNODE_GET(CLASS, FORMAL, ARGS) \ |
| static CLASS *get(LLVMContext &Context, DEFINE_MDNODE_GET_UNPACK(FORMAL)) { \ |
| return getImpl(Context, DEFINE_MDNODE_GET_UNPACK(ARGS), Uniqued); \ |
| } \ |
| static CLASS *getIfExists(LLVMContext &Context, \ |
| DEFINE_MDNODE_GET_UNPACK(FORMAL)) { \ |
| return getImpl(Context, DEFINE_MDNODE_GET_UNPACK(ARGS), Uniqued, \ |
| /* ShouldCreate */ false); \ |
| } \ |
| DEFINE_MDNODE_GET_DISTINCT_TEMPORARY(CLASS, FORMAL, ARGS) |
| |
| namespace llvm { |
| |
| /// Holds a subclass of DINode. |
| /// |
| /// FIXME: This class doesn't currently make much sense. Previously it was a |
| /// union beteen MDString (for ODR-uniqued types) and things like DIType. To |
| /// support CodeView work, it wasn't deleted outright when MDString-based type |
| /// references were deleted; we'll soon need a similar concept for CodeView |
| /// DITypeIndex. |
| template <class T> class TypedDINodeRef { |
| const Metadata *MD = nullptr; |
| |
| public: |
| TypedDINodeRef() = default; |
| TypedDINodeRef(std::nullptr_t) {} |
| TypedDINodeRef(const T *MD) : MD(MD) {} |
| |
| explicit TypedDINodeRef(const Metadata *MD) : MD(MD) { |
| assert((!MD || isa<T>(MD)) && "Expected valid type ref"); |
| } |
| |
| template <class U> |
| TypedDINodeRef( |
| const TypedDINodeRef<U> &X, |
| typename std::enable_if<std::is_convertible<U *, T *>::value>::type * = |
| nullptr) |
| : MD(X) {} |
| |
| operator Metadata *() const { return const_cast<Metadata *>(MD); } |
| |
| T *resolve() const { return const_cast<T *>(cast_or_null<T>(MD)); } |
| |
| bool operator==(const TypedDINodeRef<T> &X) const { return MD == X.MD; } |
| bool operator!=(const TypedDINodeRef<T> &X) const { return MD != X.MD; } |
| }; |
| |
| using DINodeRef = TypedDINodeRef<DINode>; |
| using DIScopeRef = TypedDINodeRef<DIScope>; |
| using DITypeRef = TypedDINodeRef<DIType>; |
| |
| class DITypeRefArray { |
| const MDTuple *N = nullptr; |
| |
| public: |
| DITypeRefArray() = default; |
| DITypeRefArray(const MDTuple *N) : N(N) {} |
| |
| explicit operator bool() const { return get(); } |
| explicit operator MDTuple *() const { return get(); } |
| |
| MDTuple *get() const { return const_cast<MDTuple *>(N); } |
| MDTuple *operator->() const { return get(); } |
| MDTuple &operator*() const { return *get(); } |
| |
| // FIXME: Fix callers and remove condition on N. |
| unsigned size() const { return N ? N->getNumOperands() : 0u; } |
| DITypeRef operator[](unsigned I) const { return DITypeRef(N->getOperand(I)); } |
| |
| class iterator : std::iterator<std::input_iterator_tag, DITypeRef, |
| std::ptrdiff_t, void, DITypeRef> { |
| MDNode::op_iterator I = nullptr; |
| |
| public: |
| iterator() = default; |
| explicit iterator(MDNode::op_iterator I) : I(I) {} |
| |
| DITypeRef operator*() const { return DITypeRef(*I); } |
| |
| iterator &operator++() { |
| ++I; |
| return *this; |
| } |
| |
| iterator operator++(int) { |
| iterator Temp(*this); |
| ++I; |
| return Temp; |
| } |
| |
| bool operator==(const iterator &X) const { return I == X.I; } |
| bool operator!=(const iterator &X) const { return I != X.I; } |
| }; |
| |
| // FIXME: Fix callers and remove condition on N. |
| iterator begin() const { return N ? iterator(N->op_begin()) : iterator(); } |
| iterator end() const { return N ? iterator(N->op_end()) : iterator(); } |
| }; |
| |
| /// Tagged DWARF-like metadata node. |
| /// |
| /// A metadata node with a DWARF tag (i.e., a constant named \c DW_TAG_*, |
| /// defined in llvm/BinaryFormat/Dwarf.h). Called \a DINode because it's |
| /// potentially used for non-DWARF output. |
| class DINode : public MDNode { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| protected: |
| DINode(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, |
| ArrayRef<Metadata *> Ops1, ArrayRef<Metadata *> Ops2 = None) |
| : MDNode(C, ID, Storage, Ops1, Ops2) { |
| assert(Tag < 1u << 16); |
| SubclassData16 = Tag; |
| } |
| ~DINode() = default; |
| |
| template <class Ty> Ty *getOperandAs(unsigned I) const { |
| return cast_or_null<Ty>(getOperand(I)); |
| } |
| |
| StringRef getStringOperand(unsigned I) const { |
| if (auto *S = getOperandAs<MDString>(I)) |
| return S->getString(); |
| return StringRef(); |
| } |
| |
| static MDString *getCanonicalMDString(LLVMContext &Context, StringRef S) { |
| if (S.empty()) |
| return nullptr; |
| return MDString::get(Context, S); |
| } |
| |
| /// Allow subclasses to mutate the tag. |
| void setTag(unsigned Tag) { SubclassData16 = Tag; } |
| |
| public: |
| unsigned getTag() const { return SubclassData16; } |
| |
| /// Debug info flags. |
| /// |
| /// The three accessibility flags are mutually exclusive and rolled together |
| /// in the first two bits. |
| enum DIFlags : uint32_t { |
| #define HANDLE_DI_FLAG(ID, NAME) Flag##NAME = ID, |
| #define DI_FLAG_LARGEST_NEEDED |
| #include "llvm/IR/DebugInfoFlags.def" |
| FlagAccessibility = FlagPrivate | FlagProtected | FlagPublic, |
| FlagPtrToMemberRep = FlagSingleInheritance | FlagMultipleInheritance | |
| FlagVirtualInheritance, |
| LLVM_MARK_AS_BITMASK_ENUM(FlagLargest) |
| }; |
| |
| static DIFlags getFlag(StringRef Flag); |
| static StringRef getFlagString(DIFlags Flag); |
| |
| /// Split up a flags bitfield. |
| /// |
| /// Split \c Flags into \c SplitFlags, a vector of its components. Returns |
| /// any remaining (unrecognized) bits. |
| static DIFlags splitFlags(DIFlags Flags, |
| SmallVectorImpl<DIFlags> &SplitFlags); |
| |
| static bool classof(const Metadata *MD) { |
| switch (MD->getMetadataID()) { |
| default: |
| return false; |
| case GenericDINodeKind: |
| case DISubrangeKind: |
| case DIEnumeratorKind: |
| case DIBasicTypeKind: |
| case DIDerivedTypeKind: |
| case DICompositeTypeKind: |
| case DISubroutineTypeKind: |
| case DIFileKind: |
| case DICompileUnitKind: |
| case DISubprogramKind: |
| case DILexicalBlockKind: |
| case DILexicalBlockFileKind: |
| case DINamespaceKind: |
| case DITemplateTypeParameterKind: |
| case DITemplateValueParameterKind: |
| case DIGlobalVariableKind: |
| case DILocalVariableKind: |
| case DILabelKind: |
| case DIObjCPropertyKind: |
| case DIImportedEntityKind: |
| case DIModuleKind: |
| return true; |
| } |
| } |
| }; |
| |
| template <class T> struct simplify_type<const TypedDINodeRef<T>> { |
| using SimpleType = Metadata *; |
| |
| static SimpleType getSimplifiedValue(const TypedDINodeRef<T> &MD) { |
| return MD; |
| } |
| }; |
| |
| template <class T> |
| struct simplify_type<TypedDINodeRef<T>> |
| : simplify_type<const TypedDINodeRef<T>> {}; |
| |
| /// Generic tagged DWARF-like metadata node. |
| /// |
| /// An un-specialized DWARF-like metadata node. The first operand is a |
| /// (possibly empty) null-separated \a MDString header that contains arbitrary |
| /// fields. The remaining operands are \a dwarf_operands(), and are pointers |
| /// to other metadata. |
| class GenericDINode : public DINode { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| GenericDINode(LLVMContext &C, StorageType Storage, unsigned Hash, |
| unsigned Tag, ArrayRef<Metadata *> Ops1, |
| ArrayRef<Metadata *> Ops2) |
| : DINode(C, GenericDINodeKind, Storage, Tag, Ops1, Ops2) { |
| setHash(Hash); |
| } |
| ~GenericDINode() { dropAllReferences(); } |
| |
| void setHash(unsigned Hash) { SubclassData32 = Hash; } |
| void recalculateHash(); |
| |
| static GenericDINode *getImpl(LLVMContext &Context, unsigned Tag, |
| StringRef Header, ArrayRef<Metadata *> DwarfOps, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Tag, getCanonicalMDString(Context, Header), |
| DwarfOps, Storage, ShouldCreate); |
| } |
| |
| static GenericDINode *getImpl(LLVMContext &Context, unsigned Tag, |
| MDString *Header, ArrayRef<Metadata *> DwarfOps, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempGenericDINode cloneImpl() const { |
| return getTemporary( |
| getContext(), getTag(), getHeader(), |
| SmallVector<Metadata *, 4>(dwarf_op_begin(), dwarf_op_end())); |
| } |
| |
| public: |
| unsigned getHash() const { return SubclassData32; } |
| |
| DEFINE_MDNODE_GET(GenericDINode, (unsigned Tag, StringRef Header, |
| ArrayRef<Metadata *> DwarfOps), |
| (Tag, Header, DwarfOps)) |
| DEFINE_MDNODE_GET(GenericDINode, (unsigned Tag, MDString *Header, |
| ArrayRef<Metadata *> DwarfOps), |
| (Tag, Header, DwarfOps)) |
| |
| /// Return a (temporary) clone of this. |
| TempGenericDINode clone() const { return cloneImpl(); } |
| |
| unsigned getTag() const { return SubclassData16; } |
| StringRef getHeader() const { return getStringOperand(0); } |
| MDString *getRawHeader() const { return getOperandAs<MDString>(0); } |
| |
| op_iterator dwarf_op_begin() const { return op_begin() + 1; } |
| op_iterator dwarf_op_end() const { return op_end(); } |
| op_range dwarf_operands() const { |
| return op_range(dwarf_op_begin(), dwarf_op_end()); |
| } |
| |
| unsigned getNumDwarfOperands() const { return getNumOperands() - 1; } |
| const MDOperand &getDwarfOperand(unsigned I) const { |
| return getOperand(I + 1); |
| } |
| void replaceDwarfOperandWith(unsigned I, Metadata *New) { |
| replaceOperandWith(I + 1, New); |
| } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == GenericDINodeKind; |
| } |
| }; |
| |
| /// Array subrange. |
| /// |
| /// TODO: Merge into node for DW_TAG_array_type, which should have a custom |
| /// type. |
| class DISubrange : public DINode { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| int64_t LowerBound; |
| |
| DISubrange(LLVMContext &C, StorageType Storage, Metadata *Node, |
| int64_t LowerBound, ArrayRef<Metadata *> Ops) |
| : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops), |
| LowerBound(LowerBound) {} |
| |
| ~DISubrange() = default; |
| |
| static DISubrange *getImpl(LLVMContext &Context, int64_t Count, |
| int64_t LowerBound, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| static DISubrange *getImpl(LLVMContext &Context, Metadata *CountNode, |
| int64_t LowerBound, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDISubrange cloneImpl() const { |
| return getTemporary(getContext(), getRawCountNode(), getLowerBound()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DISubrange, (int64_t Count, int64_t LowerBound = 0), |
| (Count, LowerBound)) |
| |
| DEFINE_MDNODE_GET(DISubrange, (Metadata *CountNode, int64_t LowerBound = 0), |
| (CountNode, LowerBound)) |
| |
| TempDISubrange clone() const { return cloneImpl(); } |
| |
| int64_t getLowerBound() const { return LowerBound; } |
| |
| Metadata *getRawCountNode() const { |
| return getOperand(0).get(); |
| } |
| |
| typedef PointerUnion<ConstantInt*, DIVariable*> CountType; |
| |
| CountType getCount() const { |
| if (auto *MD = dyn_cast<ConstantAsMetadata>(getRawCountNode())) |
| return CountType(cast<ConstantInt>(MD->getValue())); |
| |
| if (auto *DV = dyn_cast<DIVariable>(getRawCountNode())) |
| return CountType(DV); |
| |
| return CountType(); |
| } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DISubrangeKind; |
| } |
| }; |
| |
| /// Enumeration value. |
| /// |
| /// TODO: Add a pointer to the context (DW_TAG_enumeration_type) once that no |
| /// longer creates a type cycle. |
| class DIEnumerator : public DINode { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| int64_t Value; |
| DIEnumerator(LLVMContext &C, StorageType Storage, int64_t Value, |
| bool IsUnsigned, ArrayRef<Metadata *> Ops) |
| : DINode(C, DIEnumeratorKind, Storage, dwarf::DW_TAG_enumerator, Ops), |
| Value(Value) { |
| SubclassData32 = IsUnsigned; |
| } |
| ~DIEnumerator() = default; |
| |
| static DIEnumerator *getImpl(LLVMContext &Context, int64_t Value, |
| bool IsUnsigned, StringRef Name, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Value, IsUnsigned, |
| getCanonicalMDString(Context, Name), Storage, ShouldCreate); |
| } |
| static DIEnumerator *getImpl(LLVMContext &Context, int64_t Value, |
| bool IsUnsigned, MDString *Name, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDIEnumerator cloneImpl() const { |
| return getTemporary(getContext(), getValue(), isUnsigned(), getName()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DIEnumerator, (int64_t Value, bool IsUnsigned, StringRef Name), |
| (Value, IsUnsigned, Name)) |
| DEFINE_MDNODE_GET(DIEnumerator, (int64_t Value, bool IsUnsigned, MDString *Name), |
| (Value, IsUnsigned, Name)) |
| |
| TempDIEnumerator clone() const { return cloneImpl(); } |
| |
| int64_t getValue() const { return Value; } |
| bool isUnsigned() const { return SubclassData32; } |
| StringRef getName() const { return getStringOperand(0); } |
| |
| MDString *getRawName() const { return getOperandAs<MDString>(0); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DIEnumeratorKind; |
| } |
| }; |
| |
| /// Base class for scope-like contexts. |
| /// |
| /// Base class for lexical scopes and types (which are also declaration |
| /// contexts). |
| /// |
| /// TODO: Separate the concepts of declaration contexts and lexical scopes. |
| class DIScope : public DINode { |
| protected: |
| DIScope(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, |
| ArrayRef<Metadata *> Ops) |
| : DINode(C, ID, Storage, Tag, Ops) {} |
| ~DIScope() = default; |
| |
| public: |
| DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); } |
| |
| inline StringRef getFilename() const; |
| inline StringRef getDirectory() const; |
| inline Optional<StringRef> getSource() const; |
| |
| StringRef getName() const; |
| DIScopeRef getScope() const; |
| |
| /// Return the raw underlying file. |
| /// |
| /// A \a DIFile is a \a DIScope, but it doesn't point at a separate file (it |
| /// \em is the file). If \c this is an \a DIFile, we need to return \c this. |
| /// Otherwise, return the first operand, which is where all other subclasses |
| /// store their file pointer. |
| Metadata *getRawFile() const { |
| return isa<DIFile>(this) ? const_cast<DIScope *>(this) |
| : static_cast<Metadata *>(getOperand(0)); |
| } |
| |
| static bool classof(const Metadata *MD) { |
| switch (MD->getMetadataID()) { |
| default: |
| return false; |
| case DIBasicTypeKind: |
| case DIDerivedTypeKind: |
| case DICompositeTypeKind: |
| case DISubroutineTypeKind: |
| case DIFileKind: |
| case DICompileUnitKind: |
| case DISubprogramKind: |
| case DILexicalBlockKind: |
| case DILexicalBlockFileKind: |
| case DINamespaceKind: |
| case DIModuleKind: |
| return true; |
| } |
| } |
| }; |
| |
| /// File. |
| /// |
| /// TODO: Merge with directory/file node (including users). |
| /// TODO: Canonicalize paths on creation. |
| class DIFile : public DIScope { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| public: |
| /// Which algorithm (e.g. MD5) a checksum was generated with. |
| /// |
| /// The encoding is explicit because it is used directly in Bitcode. The |
| /// value 0 is reserved to indicate the absence of a checksum in Bitcode. |
| enum ChecksumKind { |
| // The first variant was originally CSK_None, encoded as 0. The new |
| // internal representation removes the need for this by wrapping the |
| // ChecksumInfo in an Optional, but to preserve Bitcode compatibility the 0 |
| // encoding is reserved. |
| CSK_MD5 = 1, |
| CSK_SHA1 = 2, |
| CSK_Last = CSK_SHA1 // Should be last enumeration. |
| }; |
| |
| /// A single checksum, represented by a \a Kind and a \a Value (a string). |
| template <typename T> |
| struct ChecksumInfo { |
| /// The kind of checksum which \a Value encodes. |
| ChecksumKind Kind; |
| /// The string value of the checksum. |
| T Value; |
| |
| ChecksumInfo(ChecksumKind Kind, T Value) : Kind(Kind), Value(Value) { } |
| ~ChecksumInfo() = default; |
| bool operator==(const ChecksumInfo<T> &X) const { |
| return Kind == X.Kind && Value == X.Value; |
| } |
| bool operator!=(const ChecksumInfo<T> &X) const { return !(*this == X); } |
| StringRef getKindAsString() const { return getChecksumKindAsString(Kind); } |
| }; |
| |
| private: |
| Optional<ChecksumInfo<MDString *>> Checksum; |
| Optional<MDString *> Source; |
| |
| DIFile(LLVMContext &C, StorageType Storage, |
| Optional<ChecksumInfo<MDString *>> CS, Optional<MDString *> Src, |
| ArrayRef<Metadata *> Ops) |
| : DIScope(C, DIFileKind, Storage, dwarf::DW_TAG_file_type, Ops), |
| Checksum(CS), Source(Src) {} |
| ~DIFile() = default; |
| |
| static DIFile *getImpl(LLVMContext &Context, StringRef Filename, |
| StringRef Directory, |
| Optional<ChecksumInfo<StringRef>> CS, |
| Optional<StringRef> Source, |
| StorageType Storage, bool ShouldCreate = true) { |
| Optional<ChecksumInfo<MDString *>> MDChecksum; |
| if (CS) |
| MDChecksum.emplace(CS->Kind, getCanonicalMDString(Context, CS->Value)); |
| return getImpl(Context, getCanonicalMDString(Context, Filename), |
| getCanonicalMDString(Context, Directory), MDChecksum, |
| Source ? Optional<MDString *>(getCanonicalMDString(Context, *Source)) : None, |
| Storage, ShouldCreate); |
| } |
| static DIFile *getImpl(LLVMContext &Context, MDString *Filename, |
| MDString *Directory, |
| Optional<ChecksumInfo<MDString *>> CS, |
| Optional<MDString *> Source, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDIFile cloneImpl() const { |
| return getTemporary(getContext(), getFilename(), getDirectory(), |
| getChecksum(), getSource()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DIFile, (StringRef Filename, StringRef Directory, |
| Optional<ChecksumInfo<StringRef>> CS = None, |
| Optional<StringRef> Source = None), |
| (Filename, Directory, CS, Source)) |
| DEFINE_MDNODE_GET(DIFile, (MDString * Filename, MDString *Directory, |
| Optional<ChecksumInfo<MDString *>> CS = None, |
| Optional<MDString *> Source = None), |
| (Filename, Directory, CS, Source)) |
| |
| TempDIFile clone() const { return cloneImpl(); } |
| |
| StringRef getFilename() const { return getStringOperand(0); } |
| StringRef getDirectory() const { return getStringOperand(1); } |
| Optional<ChecksumInfo<StringRef>> getChecksum() const { |
| Optional<ChecksumInfo<StringRef>> StringRefChecksum; |
| if (Checksum) |
| StringRefChecksum.emplace(Checksum->Kind, Checksum->Value->getString()); |
| return StringRefChecksum; |
| } |
| Optional<StringRef> getSource() const { |
| return Source ? Optional<StringRef>((*Source)->getString()) : None; |
| } |
| |
| MDString *getRawFilename() const { return getOperandAs<MDString>(0); } |
| MDString *getRawDirectory() const { return getOperandAs<MDString>(1); } |
| Optional<ChecksumInfo<MDString *>> getRawChecksum() const { return Checksum; } |
| Optional<MDString *> getRawSource() const { return Source; } |
| |
| static StringRef getChecksumKindAsString(ChecksumKind CSKind); |
| static Optional<ChecksumKind> getChecksumKind(StringRef CSKindStr); |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DIFileKind; |
| } |
| }; |
| |
| StringRef DIScope::getFilename() const { |
| if (auto *F = getFile()) |
| return F->getFilename(); |
| return ""; |
| } |
| |
| StringRef DIScope::getDirectory() const { |
| if (auto *F = getFile()) |
| return F->getDirectory(); |
| return ""; |
| } |
| |
| Optional<StringRef> DIScope::getSource() const { |
| if (auto *F = getFile()) |
| return F->getSource(); |
| return None; |
| } |
| |
| /// Base class for types. |
| /// |
| /// TODO: Remove the hardcoded name and context, since many types don't use |
| /// them. |
| /// TODO: Split up flags. |
| class DIType : public DIScope { |
| unsigned Line; |
| DIFlags Flags; |
| uint64_t SizeInBits; |
| uint64_t OffsetInBits; |
| uint32_t AlignInBits; |
| |
| protected: |
| DIType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, |
| unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, DIFlags Flags, ArrayRef<Metadata *> Ops) |
| : DIScope(C, ID, Storage, Tag, Ops) { |
| init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags); |
| } |
| ~DIType() = default; |
| |
| void init(unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, DIFlags Flags) { |
| this->Line = Line; |
| this->Flags = Flags; |
| this->SizeInBits = SizeInBits; |
| this->AlignInBits = AlignInBits; |
| this->OffsetInBits = OffsetInBits; |
| } |
| |
| /// Change fields in place. |
| void mutate(unsigned Tag, unsigned Line, uint64_t SizeInBits, |
| uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags) { |
| assert(isDistinct() && "Only distinct nodes can mutate"); |
| setTag(Tag); |
| init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags); |
| } |
| |
| public: |
| TempDIType clone() const { |
| return TempDIType(cast<DIType>(MDNode::clone().release())); |
| } |
| |
| unsigned getLine() const { return Line; } |
| uint64_t getSizeInBits() const { return SizeInBits; } |
| uint32_t getAlignInBits() const { return AlignInBits; } |
| uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; } |
| uint64_t getOffsetInBits() const { return OffsetInBits; } |
| DIFlags getFlags() const { return Flags; } |
| |
| DIScopeRef getScope() const { return DIScopeRef(getRawScope()); } |
| StringRef getName() const { return getStringOperand(2); } |
| |
| |
| Metadata *getRawScope() const { return getOperand(1); } |
| MDString *getRawName() const { return getOperandAs<MDString>(2); } |
| |
| /// Returns a new temporary DIType with updated Flags |
| TempDIType cloneWithFlags(DIFlags NewFlags) const { |
| auto NewTy = clone(); |
| NewTy->Flags = NewFlags; |
| return NewTy; |
| } |
| |
| bool isPrivate() const { |
| return (getFlags() & FlagAccessibility) == FlagPrivate; |
| } |
| bool isProtected() const { |
| return (getFlags() & FlagAccessibility) == FlagProtected; |
| } |
| bool isPublic() const { |
| return (getFlags() & FlagAccessibility) == FlagPublic; |
| } |
| bool isForwardDecl() const { return getFlags() & FlagFwdDecl; } |
| bool isAppleBlockExtension() const { return getFlags() & FlagAppleBlock; } |
| bool isBlockByrefStruct() const { return getFlags() & FlagBlockByrefStruct; } |
| bool isVirtual() const { return getFlags() & FlagVirtual; } |
| bool isArtificial() const { return getFlags() & FlagArtificial; } |
| bool isObjectPointer() const { return getFlags() & FlagObjectPointer; } |
| bool isObjcClassComplete() const { |
| return getFlags() & FlagObjcClassComplete; |
| } |
| bool isVector() const { return getFlags() & FlagVector; } |
| bool isBitField() const { return getFlags() & FlagBitField; } |
| bool isStaticMember() const { return getFlags() & FlagStaticMember; } |
| bool isLValueReference() const { return getFlags() & FlagLValueReference; } |
| bool isRValueReference() const { return getFlags() & FlagRValueReference; } |
| bool isTypePassByValue() const { return getFlags() & FlagTypePassByValue; } |
| bool isTypePassByReference() const { |
| return getFlags() & FlagTypePassByReference; |
| } |
| bool isBigEndian() const { return getFlags() & FlagBigEndian; } |
| bool isLittleEndian() const { return getFlags() & FlagLittleEndian; } |
| |
| static bool classof(const Metadata *MD) { |
| switch (MD->getMetadataID()) { |
| default: |
| return false; |
| case DIBasicTypeKind: |
| case DIDerivedTypeKind: |
| case DICompositeTypeKind: |
| case DISubroutineTypeKind: |
| return true; |
| } |
| } |
| }; |
| |
| /// Basic type, like 'int' or 'float'. |
| /// |
| /// TODO: Split out DW_TAG_unspecified_type. |
| /// TODO: Drop unused accessors. |
| class DIBasicType : public DIType { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| unsigned Encoding; |
| |
| DIBasicType(LLVMContext &C, StorageType Storage, unsigned Tag, |
| uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, |
| DIFlags Flags, ArrayRef<Metadata *> Ops) |
| : DIType(C, DIBasicTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0, |
| Flags, Ops), |
| Encoding(Encoding) {} |
| ~DIBasicType() = default; |
| |
| static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, |
| StringRef Name, uint64_t SizeInBits, |
| uint32_t AlignInBits, unsigned Encoding, |
| DIFlags Flags, StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, Tag, getCanonicalMDString(Context, Name), |
| SizeInBits, AlignInBits, Encoding, Flags, Storage, |
| ShouldCreate); |
| } |
| static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, |
| MDString *Name, uint64_t SizeInBits, |
| uint32_t AlignInBits, unsigned Encoding, |
| DIFlags Flags, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDIBasicType cloneImpl() const { |
| return getTemporary(getContext(), getTag(), getName(), getSizeInBits(), |
| getAlignInBits(), getEncoding(), getFlags()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name), |
| (Tag, Name, 0, 0, 0, FlagZero)) |
| DEFINE_MDNODE_GET(DIBasicType, |
| (unsigned Tag, StringRef Name, uint64_t SizeInBits, |
| uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), |
| (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)) |
| DEFINE_MDNODE_GET(DIBasicType, |
| (unsigned Tag, MDString *Name, uint64_t SizeInBits, |
| uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), |
| (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)) |
| |
| TempDIBasicType clone() const { return cloneImpl(); } |
| |
| unsigned getEncoding() const { return Encoding; } |
| |
| enum class Signedness { Signed, Unsigned }; |
| |
| /// Return the signedness of this type, or None if this type is neither |
| /// signed nor unsigned. |
| Optional<Signedness> getSignedness() const; |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DIBasicTypeKind; |
| } |
| }; |
| |
| /// Derived types. |
| /// |
| /// This includes qualified types, pointers, references, friends, typedefs, and |
| /// class members. |
| /// |
| /// TODO: Split out members (inheritance, fields, methods, etc.). |
| class DIDerivedType : public DIType { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| /// The DWARF address space of the memory pointed to or referenced by a |
| /// pointer or reference type respectively. |
| Optional<unsigned> DWARFAddressSpace; |
| |
| DIDerivedType(LLVMContext &C, StorageType Storage, unsigned Tag, |
| unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, Optional<unsigned> DWARFAddressSpace, |
| DIFlags Flags, ArrayRef<Metadata *> Ops) |
| : DIType(C, DIDerivedTypeKind, Storage, Tag, Line, SizeInBits, |
| AlignInBits, OffsetInBits, Flags, Ops), |
| DWARFAddressSpace(DWARFAddressSpace) {} |
| ~DIDerivedType() = default; |
| |
| static DIDerivedType *getImpl(LLVMContext &Context, unsigned Tag, |
| StringRef Name, DIFile *File, unsigned Line, |
| DIScopeRef Scope, DITypeRef BaseType, |
| uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, |
| Optional<unsigned> DWARFAddressSpace, |
| DIFlags Flags, Metadata *ExtraData, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File, |
| Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, |
| DWARFAddressSpace, Flags, ExtraData, Storage, ShouldCreate); |
| } |
| static DIDerivedType *getImpl(LLVMContext &Context, unsigned Tag, |
| MDString *Name, Metadata *File, unsigned Line, |
| Metadata *Scope, Metadata *BaseType, |
| uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, |
| Optional<unsigned> DWARFAddressSpace, |
| DIFlags Flags, Metadata *ExtraData, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDIDerivedType cloneImpl() const { |
| return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), |
| getScope(), getBaseType(), getSizeInBits(), |
| getAlignInBits(), getOffsetInBits(), |
| getDWARFAddressSpace(), getFlags(), getExtraData()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DIDerivedType, |
| (unsigned Tag, MDString *Name, Metadata *File, |
| unsigned Line, Metadata *Scope, Metadata *BaseType, |
| uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, |
| Optional<unsigned> DWARFAddressSpace, DIFlags Flags, |
| Metadata *ExtraData = nullptr), |
| (Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
| AlignInBits, OffsetInBits, DWARFAddressSpace, Flags, |
| ExtraData)) |
| DEFINE_MDNODE_GET(DIDerivedType, |
| (unsigned Tag, StringRef Name, DIFile *File, unsigned Line, |
| DIScopeRef Scope, DITypeRef BaseType, uint64_t SizeInBits, |
| uint32_t AlignInBits, uint64_t OffsetInBits, |
| Optional<unsigned> DWARFAddressSpace, DIFlags Flags, |
| Metadata *ExtraData = nullptr), |
| (Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
| AlignInBits, OffsetInBits, DWARFAddressSpace, Flags, |
| ExtraData)) |
| |
| TempDIDerivedType clone() const { return cloneImpl(); } |
| |
| /// Get the base type this is derived from. |
| DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } |
| Metadata *getRawBaseType() const { return getOperand(3); } |
| |
| /// \returns The DWARF address space of the memory pointed to or referenced by |
| /// a pointer or reference type respectively. |
| Optional<unsigned> getDWARFAddressSpace() const { return DWARFAddressSpace; } |
| |
| /// Get extra data associated with this derived type. |
| /// |
| /// Class type for pointer-to-members, objective-c property node for ivars, |
| /// global constant wrapper for static members, or virtual base pointer offset |
| /// for inheritance. |
| /// |
| /// TODO: Separate out types that need this extra operand: pointer-to-member |
| /// types and member fields (static members and ivars). |
| Metadata *getExtraData() const { return getRawExtraData(); } |
| Metadata *getRawExtraData() const { return getOperand(4); } |
| |
| /// Get casted version of extra data. |
| /// @{ |
| DITypeRef getClassType() const { |
| assert(getTag() == dwarf::DW_TAG_ptr_to_member_type); |
| return DITypeRef(getExtraData()); |
| } |
| |
| DIObjCProperty *getObjCProperty() const { |
| return dyn_cast_or_null<DIObjCProperty>(getExtraData()); |
| } |
| |
| uint32_t getVBPtrOffset() const { |
| assert(getTag() == dwarf::DW_TAG_inheritance); |
| if (auto *CM = cast_or_null<ConstantAsMetadata>(getExtraData())) |
| if (auto *CI = dyn_cast_or_null<ConstantInt>(CM->getValue())) |
| return static_cast<uint32_t>(CI->getZExtValue()); |
| return 0; |
| } |
| |
| Constant *getStorageOffsetInBits() const { |
| assert(getTag() == dwarf::DW_TAG_member && isBitField()); |
| if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData())) |
| return C->getValue(); |
| return nullptr; |
| } |
| |
| Constant *getConstant() const { |
| assert(getTag() == dwarf::DW_TAG_member && isStaticMember()); |
| if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData())) |
| return C->getValue(); |
| return nullptr; |
| } |
| Constant *getDiscriminantValue() const { |
| assert(getTag() == dwarf::DW_TAG_member && !isStaticMember()); |
| if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData())) |
| return C->getValue(); |
| return nullptr; |
| } |
| /// @} |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DIDerivedTypeKind; |
| } |
| }; |
| |
| /// Composite types. |
| /// |
| /// TODO: Detach from DerivedTypeBase (split out MDEnumType?). |
| /// TODO: Create a custom, unrelated node for DW_TAG_array_type. |
| class DICompositeType : public DIType { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| unsigned RuntimeLang; |
| |
| DICompositeType(LLVMContext &C, StorageType Storage, unsigned Tag, |
| unsigned Line, unsigned RuntimeLang, uint64_t SizeInBits, |
| uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, |
| ArrayRef<Metadata *> Ops) |
| : DIType(C, DICompositeTypeKind, Storage, Tag, Line, SizeInBits, |
| AlignInBits, OffsetInBits, Flags, Ops), |
| RuntimeLang(RuntimeLang) {} |
| ~DICompositeType() = default; |
| |
| /// Change fields in place. |
| void mutate(unsigned Tag, unsigned Line, unsigned RuntimeLang, |
| uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, DIFlags Flags) { |
| assert(isDistinct() && "Only distinct nodes can mutate"); |
| assert(getRawIdentifier() && "Only ODR-uniqued nodes should mutate"); |
| this->RuntimeLang = RuntimeLang; |
| DIType::mutate(Tag, Line, SizeInBits, AlignInBits, OffsetInBits, Flags); |
| } |
| |
| static DICompositeType * |
| getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File, |
| unsigned Line, DIScopeRef Scope, DITypeRef BaseType, |
| uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, |
| DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang, |
| DITypeRef VTableHolder, DITemplateParameterArray TemplateParams, |
| StringRef Identifier, DIDerivedType *Discriminator, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl( |
| Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope, |
| BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements.get(), |
| RuntimeLang, VTableHolder, TemplateParams.get(), |
| getCanonicalMDString(Context, Identifier), Discriminator, Storage, ShouldCreate); |
| } |
| static DICompositeType * |
| getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, |
| unsigned Line, Metadata *Scope, Metadata *BaseType, |
| uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, |
| DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, |
| Metadata *VTableHolder, Metadata *TemplateParams, |
| MDString *Identifier, Metadata *Discriminator, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDICompositeType cloneImpl() const { |
| return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), |
| getScope(), getBaseType(), getSizeInBits(), |
| getAlignInBits(), getOffsetInBits(), getFlags(), |
| getElements(), getRuntimeLang(), getVTableHolder(), |
| getTemplateParams(), getIdentifier(), getDiscriminator()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DICompositeType, |
| (unsigned Tag, StringRef Name, DIFile *File, unsigned Line, |
| DIScopeRef Scope, DITypeRef BaseType, uint64_t SizeInBits, |
| uint32_t AlignInBits, uint64_t OffsetInBits, |
| DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang, |
| DITypeRef VTableHolder, |
| DITemplateParameterArray TemplateParams = nullptr, |
| StringRef Identifier = "", DIDerivedType *Discriminator = nullptr), |
| (Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
| AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, |
| VTableHolder, TemplateParams, Identifier, Discriminator)) |
| DEFINE_MDNODE_GET(DICompositeType, |
| (unsigned Tag, MDString *Name, Metadata *File, |
| unsigned Line, Metadata *Scope, Metadata *BaseType, |
| uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, |
| unsigned RuntimeLang, Metadata *VTableHolder, |
| Metadata *TemplateParams = nullptr, |
| MDString *Identifier = nullptr, |
| Metadata *Discriminator = nullptr), |
| (Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
| AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, |
| VTableHolder, TemplateParams, Identifier, Discriminator)) |
| |
| TempDICompositeType clone() const { return cloneImpl(); } |
| |
| /// Get a DICompositeType with the given ODR identifier. |
| /// |
| /// If \a LLVMContext::isODRUniquingDebugTypes(), gets the mapped |
| /// DICompositeType for the given ODR \c Identifier. If none exists, creates |
| /// a new node. |
| /// |
| /// Else, returns \c nullptr. |
| static DICompositeType * |
| getODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag, |
| MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, |
| Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, |
| unsigned RuntimeLang, Metadata *VTableHolder, |
| Metadata *TemplateParams, Metadata *Discriminator); |
| static DICompositeType *getODRTypeIfExists(LLVMContext &Context, |
| MDString &Identifier); |
| |
| /// Build a DICompositeType with the given ODR identifier. |
| /// |
| /// Looks up the mapped DICompositeType for the given ODR \c Identifier. If |
| /// it doesn't exist, creates a new one. If it does exist and \a |
| /// isForwardDecl(), and the new arguments would be a definition, mutates the |
| /// the type in place. In either case, returns the type. |
| /// |
| /// If not \a LLVMContext::isODRUniquingDebugTypes(), this function returns |
| /// nullptr. |
| static DICompositeType * |
| buildODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag, |
| MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, |
| Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, |
| uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, |
| unsigned RuntimeLang, Metadata *VTableHolder, |
| Metadata *TemplateParams, Metadata *Discriminator); |
| |
| DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } |
| DINodeArray getElements() const { |
| return cast_or_null<MDTuple>(getRawElements()); |
| } |
| DITypeRef getVTableHolder() const { return DITypeRef(getRawVTableHolder()); } |
| DITemplateParameterArray getTemplateParams() const { |
| return cast_or_null<MDTuple>(getRawTemplateParams()); |
| } |
| StringRef getIdentifier() const { return getStringOperand(7); } |
| unsigned getRuntimeLang() const { return RuntimeLang; } |
| |
| Metadata *getRawBaseType() const { return getOperand(3); } |
| Metadata *getRawElements() const { return getOperand(4); } |
| Metadata *getRawVTableHolder() const { return getOperand(5); } |
| Metadata *getRawTemplateParams() const { return getOperand(6); } |
| MDString *getRawIdentifier() const { return getOperandAs<MDString>(7); } |
| Metadata *getRawDiscriminator() const { return getOperand(8); } |
| DIDerivedType *getDiscriminator() const { return getOperandAs<DIDerivedType>(8); } |
| |
| /// Replace operands. |
| /// |
| /// If this \a isUniqued() and not \a isResolved(), on a uniquing collision |
| /// this will be RAUW'ed and deleted. Use a \a TrackingMDRef to keep track |
| /// of its movement if necessary. |
| /// @{ |
| void replaceElements(DINodeArray Elements) { |
| #ifndef NDEBUG |
| for (DINode *Op : getElements()) |
| assert(is_contained(Elements->operands(), Op) && |
| "Lost a member during member list replacement"); |
| #endif |
| replaceOperandWith(4, Elements.get()); |
| } |
| |
| void replaceVTableHolder(DITypeRef VTableHolder) { |
| replaceOperandWith(5, VTableHolder); |
| } |
| |
| void replaceTemplateParams(DITemplateParameterArray TemplateParams) { |
| replaceOperandWith(6, TemplateParams.get()); |
| } |
| /// @} |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DICompositeTypeKind; |
| } |
| }; |
| |
| /// Type array for a subprogram. |
| /// |
| /// TODO: Fold the array of types in directly as operands. |
| class DISubroutineType : public DIType { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| /// The calling convention used with DW_AT_calling_convention. Actually of |
| /// type dwarf::CallingConvention. |
| uint8_t CC; |
| |
| DISubroutineType(LLVMContext &C, StorageType Storage, DIFlags Flags, |
| uint8_t CC, ArrayRef<Metadata *> Ops) |
| : DIType(C, DISubroutineTypeKind, Storage, dwarf::DW_TAG_subroutine_type, |
| 0, 0, 0, 0, Flags, Ops), |
| CC(CC) {} |
| ~DISubroutineType() = default; |
| |
| static DISubroutineType *getImpl(LLVMContext &Context, DIFlags Flags, |
| uint8_t CC, DITypeRefArray TypeArray, |
| StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, Flags, CC, TypeArray.get(), Storage, ShouldCreate); |
| } |
| static DISubroutineType *getImpl(LLVMContext &Context, DIFlags Flags, |
| uint8_t CC, Metadata *TypeArray, |
| StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDISubroutineType cloneImpl() const { |
| return getTemporary(getContext(), getFlags(), getCC(), getTypeArray()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DISubroutineType, |
| (DIFlags Flags, uint8_t CC, DITypeRefArray TypeArray), |
| (Flags, CC, TypeArray)) |
| DEFINE_MDNODE_GET(DISubroutineType, |
| (DIFlags Flags, uint8_t CC, Metadata *TypeArray), |
| (Flags, CC, TypeArray)) |
| |
| TempDISubroutineType clone() const { return cloneImpl(); } |
| |
| uint8_t getCC() const { return CC; } |
| |
| DITypeRefArray getTypeArray() const { |
| return cast_or_null<MDTuple>(getRawTypeArray()); |
| } |
| |
| Metadata *getRawTypeArray() const { return getOperand(3); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DISubroutineTypeKind; |
| } |
| }; |
| |
| /// Compile unit. |
| class DICompileUnit : public DIScope { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| public: |
| enum DebugEmissionKind : unsigned { |
| NoDebug = 0, |
| FullDebug, |
| LineTablesOnly, |
| DebugDirectivesOnly, |
| LastEmissionKind = DebugDirectivesOnly |
| }; |
| |
| enum class DebugNameTableKind : unsigned { |
| Default = 0, |
| GNU = 1, |
| None = 2, |
| LastDebugNameTableKind = None |
| }; |
| |
| static Optional<DebugEmissionKind> getEmissionKind(StringRef Str); |
| static const char *emissionKindString(DebugEmissionKind EK); |
| static Optional<DebugNameTableKind> getNameTableKind(StringRef Str); |
| static const char *nameTableKindString(DebugNameTableKind PK); |
| |
| private: |
| unsigned SourceLanguage; |
| bool IsOptimized; |
| unsigned RuntimeVersion; |
| unsigned EmissionKind; |
| uint64_t DWOId; |
| bool SplitDebugInlining; |
| bool DebugInfoForProfiling; |
| unsigned NameTableKind; |
| bool RangesBaseAddress; |
| |
| DICompileUnit(LLVMContext &C, StorageType Storage, unsigned SourceLanguage, |
| bool IsOptimized, unsigned RuntimeVersion, |
| unsigned EmissionKind, uint64_t DWOId, bool SplitDebugInlining, |
| bool DebugInfoForProfiling, unsigned NameTableKind, |
| bool RangesBaseAddress, ArrayRef<Metadata *> Ops) |
| : DIScope(C, DICompileUnitKind, Storage, dwarf::DW_TAG_compile_unit, Ops), |
| SourceLanguage(SourceLanguage), IsOptimized(IsOptimized), |
| RuntimeVersion(RuntimeVersion), EmissionKind(EmissionKind), |
| DWOId(DWOId), SplitDebugInlining(SplitDebugInlining), |
| DebugInfoForProfiling(DebugInfoForProfiling), |
| NameTableKind(NameTableKind), RangesBaseAddress(RangesBaseAddress) { |
| assert(Storage != Uniqued); |
| } |
| ~DICompileUnit() = default; |
| |
| static DICompileUnit * |
| getImpl(LLVMContext &Context, unsigned SourceLanguage, DIFile *File, |
| StringRef Producer, bool IsOptimized, StringRef Flags, |
| unsigned RuntimeVersion, StringRef SplitDebugFilename, |
| unsigned EmissionKind, DICompositeTypeArray EnumTypes, |
| DIScopeArray RetainedTypes, |
| DIGlobalVariableExpressionArray GlobalVariables, |
| DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, |
| uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, |
| unsigned NameTableKind, bool RangesBaseAddress, StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, SourceLanguage, File, |
| getCanonicalMDString(Context, Producer), IsOptimized, |
| getCanonicalMDString(Context, Flags), RuntimeVersion, |
| getCanonicalMDString(Context, SplitDebugFilename), |
| EmissionKind, EnumTypes.get(), RetainedTypes.get(), |
| GlobalVariables.get(), ImportedEntities.get(), Macros.get(), |
| DWOId, SplitDebugInlining, DebugInfoForProfiling, |
| NameTableKind, RangesBaseAddress, Storage, ShouldCreate); |
| } |
| static DICompileUnit * |
| getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, |
| MDString *Producer, bool IsOptimized, MDString *Flags, |
| unsigned RuntimeVersion, MDString *SplitDebugFilename, |
| unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, |
| Metadata *GlobalVariables, Metadata *ImportedEntities, |
| Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, |
| bool DebugInfoForProfiling, unsigned NameTableKind, |
| bool RangesBaseAddress, StorageType Storage, bool ShouldCreate = true); |
| |
| TempDICompileUnit cloneImpl() const { |
| return getTemporary( |
| getContext(), getSourceLanguage(), getFile(), getProducer(), |
| isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(), |
| getEmissionKind(), getEnumTypes(), getRetainedTypes(), |
| getGlobalVariables(), getImportedEntities(), getMacros(), DWOId, |
| getSplitDebugInlining(), getDebugInfoForProfiling(), getNameTableKind(), |
| getRangesBaseAddress()); |
| } |
| |
| public: |
| static void get() = delete; |
| static void getIfExists() = delete; |
| |
| DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( |
| DICompileUnit, |
| (unsigned SourceLanguage, DIFile *File, StringRef Producer, |
| bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, |
| StringRef SplitDebugFilename, DebugEmissionKind EmissionKind, |
| DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes, |
| DIGlobalVariableExpressionArray GlobalVariables, |
| DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, |
| uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, |
| DebugNameTableKind NameTableKind, bool RangesBaseAddress), |
| (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, |
| SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, |
| GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, |
| DebugInfoForProfiling, (unsigned)NameTableKind, RangesBaseAddress)) |
| DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( |
| DICompileUnit, |
| (unsigned SourceLanguage, Metadata *File, MDString *Producer, |
| bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, |
| MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, |
| Metadata *RetainedTypes, Metadata *GlobalVariables, |
| Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, |
| bool SplitDebugInlining, bool DebugInfoForProfiling, |
| unsigned NameTableKind, bool RangesBaseAddress), |
| (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, |
| SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, |
| GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, |
| DebugInfoForProfiling, NameTableKind, RangesBaseAddress)) |
| |
| TempDICompileUnit clone() const { return cloneImpl(); } |
| |
| unsigned getSourceLanguage() const { return SourceLanguage; } |
| bool isOptimized() const { return IsOptimized; } |
| unsigned getRuntimeVersion() const { return RuntimeVersion; } |
| DebugEmissionKind getEmissionKind() const { |
| return (DebugEmissionKind)EmissionKind; |
| } |
| bool isDebugDirectivesOnly() const { |
| return EmissionKind == DebugDirectivesOnly; |
| } |
| bool getDebugInfoForProfiling() const { return DebugInfoForProfiling; } |
| DebugNameTableKind getNameTableKind() const { |
| return (DebugNameTableKind)NameTableKind; |
| } |
| bool getRangesBaseAddress() const { |
| return RangesBaseAddress; } |
| StringRef getProducer() const { |
| return getStringOperand(1); } |
| StringRef getFlags() const { |
| return getStringOperand(2); } |
| StringRef getSplitDebugFilename() const { |
| return getStringOperand(3); } |
| DICompositeTypeArray getEnumTypes() const { |
| return cast_or_null<MDTuple>(getRawEnumTypes()); |
| } |
| DIScopeArray getRetainedTypes() const { |
| return cast_or_null<MDTuple>(getRawRetainedTypes()); |
| } |
| DIGlobalVariableExpressionArray getGlobalVariables() const { |
| return cast_or_null<MDTuple>(getRawGlobalVariables()); |
| } |
| DIImportedEntityArray getImportedEntities() const { |
| return cast_or_null<MDTuple>(getRawImportedEntities()); |
| } |
| DIMacroNodeArray getMacros() const { |
| return cast_or_null<MDTuple>(getRawMacros()); |
| } |
| uint64_t getDWOId() const { return DWOId; } |
| void setDWOId(uint64_t DwoId) { DWOId = DwoId; } |
| bool getSplitDebugInlining() const { return SplitDebugInlining; } |
| void setSplitDebugInlining(bool SplitDebugInlining) { |
| this->SplitDebugInlining = SplitDebugInlining; |
| } |
| |
| MDString *getRawProducer() const { return getOperandAs<MDString>(1); } |
| MDString *getRawFlags() const { return getOperandAs<MDString>(2); } |
| MDString *getRawSplitDebugFilename() const { |
| return getOperandAs<MDString>(3); |
| } |
| Metadata *getRawEnumTypes() const { return getOperand(4); } |
| Metadata *getRawRetainedTypes() const { return getOperand(5); } |
| Metadata *getRawGlobalVariables() const { return getOperand(6); } |
| Metadata *getRawImportedEntities() const { return getOperand(7); } |
| Metadata *getRawMacros() const { return getOperand(8); } |
| |
| /// Replace arrays. |
| /// |
| /// If this \a isUniqued() and not \a isResolved(), it will be RAUW'ed and |
| /// deleted on a uniquing collision. In practice, uniquing collisions on \a |
| /// DICompileUnit should be fairly rare. |
| /// @{ |
| void replaceEnumTypes(DICompositeTypeArray N) { |
| replaceOperandWith(4, N.get()); |
| } |
| void replaceRetainedTypes(DITypeArray N) { |
| replaceOperandWith(5, N.get()); |
| } |
| void replaceGlobalVariables(DIGlobalVariableExpressionArray N) { |
| replaceOperandWith(6, N.get()); |
| } |
| void replaceImportedEntities(DIImportedEntityArray N) { |
| replaceOperandWith(7, N.get()); |
| } |
| void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(8, N.get()); } |
| /// @} |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DICompileUnitKind; |
| } |
| }; |
| |
| /// A scope for locals. |
| /// |
| /// A legal scope for lexical blocks, local variables, and debug info |
| /// locations. Subclasses are \a DISubprogram, \a DILexicalBlock, and \a |
| /// DILexicalBlockFile. |
| class DILocalScope : public DIScope { |
| protected: |
| DILocalScope(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, |
| ArrayRef<Metadata *> Ops) |
| : DIScope(C, ID, Storage, Tag, Ops) {} |
| ~DILocalScope() = default; |
| |
| public: |
| /// Get the subprogram for this scope. |
| /// |
| /// Return this if it's an \a DISubprogram; otherwise, look up the scope |
| /// chain. |
| DISubprogram *getSubprogram() const; |
| |
| /// Get the first non DILexicalBlockFile scope of this scope. |
| /// |
| /// Return this if it's not a \a DILexicalBlockFIle; otherwise, look up the |
| /// scope chain. |
| DILocalScope *getNonLexicalBlockFileScope() const; |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DISubprogramKind || |
| MD->getMetadataID() == DILexicalBlockKind || |
| MD->getMetadataID() == DILexicalBlockFileKind; |
| } |
| }; |
| |
| /// Debug location. |
| /// |
| /// A debug location in source code, used for debug info and otherwise. |
| class DILocation : public MDNode { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| DILocation(LLVMContext &C, StorageType Storage, unsigned Line, |
| unsigned Column, ArrayRef<Metadata *> MDs, bool ImplicitCode); |
| ~DILocation() { dropAllReferences(); } |
| |
| static DILocation *getImpl(LLVMContext &Context, unsigned Line, |
| unsigned Column, Metadata *Scope, |
| Metadata *InlinedAt, bool ImplicitCode, |
| StorageType Storage, bool ShouldCreate = true); |
| static DILocation *getImpl(LLVMContext &Context, unsigned Line, |
| unsigned Column, DILocalScope *Scope, |
| DILocation *InlinedAt, bool ImplicitCode, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Line, Column, static_cast<Metadata *>(Scope), |
| static_cast<Metadata *>(InlinedAt), ImplicitCode, Storage, |
| ShouldCreate); |
| } |
| |
| /// With a given unsigned int \p U, use up to 13 bits to represent it. |
| /// old_bit 1~5 --> new_bit 1~5 |
| /// old_bit 6~12 --> new_bit 7~13 |
| /// new_bit_6 is 0 if higher bits (7~13) are all 0 |
| static unsigned getPrefixEncodingFromUnsigned(unsigned U) { |
| U &= 0xfff; |
| return U > 0x1f ? (((U & 0xfe0) << 1) | (U & 0x1f) | 0x20) : U; |
| } |
| |
| /// Reverse transformation as getPrefixEncodingFromUnsigned. |
| static unsigned getUnsignedFromPrefixEncoding(unsigned U) { |
| if (U & 1) |
| return 0; |
| U >>= 1; |
| return (U & 0x20) ? (((U >> 1) & 0xfe0) | (U & 0x1f)) : (U & 0x1f); |
| } |
| |
| /// Returns the next component stored in discriminator. |
| static unsigned getNextComponentInDiscriminator(unsigned D) { |
| if ((D & 1) == 0) |
| return D >> ((D & 0x40) ? 14 : 7); |
| else |
| return D >> 1; |
| } |
| |
| TempDILocation cloneImpl() const { |
| // Get the raw scope/inlinedAt since it is possible to invoke this on |
| // a DILocation containing temporary metadata. |
| return getTemporary(getContext(), getLine(), getColumn(), getRawScope(), |
| getRawInlinedAt(), isImplicitCode()); |
| } |
| |
| static unsigned encodeComponent(unsigned C) { |
| return (C == 0) ? 1U : (getPrefixEncodingFromUnsigned(C) << 1); |
| } |
| |
| static unsigned encodingBits(unsigned C) { |
| return (C == 0) ? 1 : (C > 0x1f ? 14 : 7); |
| } |
| |
| public: |
| // Disallow replacing operands. |
| void replaceOperandWith(unsigned I, Metadata *New) = delete; |
| |
| DEFINE_MDNODE_GET(DILocation, |
| (unsigned Line, unsigned Column, Metadata *Scope, |
| Metadata *InlinedAt = nullptr, bool ImplicitCode = false), |
| (Line, Column, Scope, InlinedAt, ImplicitCode)) |
| DEFINE_MDNODE_GET(DILocation, |
| (unsigned Line, unsigned Column, DILocalScope *Scope, |
| DILocation *InlinedAt = nullptr, |
| bool ImplicitCode = false), |
| (Line, Column, Scope, InlinedAt, ImplicitCode)) |
| |
| /// Return a (temporary) clone of this. |
| TempDILocation clone() const { return cloneImpl(); } |
| |
| unsigned getLine() const { return SubclassData32; } |
| unsigned getColumn() const { return SubclassData16; } |
| DILocalScope *getScope() const { return cast<DILocalScope>(getRawScope()); } |
| |
| DILocation *getInlinedAt() const { |
| return cast_or_null<DILocation>(getRawInlinedAt()); |
| } |
| |
| /// Check if the location corresponds to an implicit code. |
| /// When the ImplicitCode flag is true, it means that the Instruction |
| /// with this DILocation has been added by the front-end but it hasn't been |
| /// written explicitly by the user (e.g. cleanup stuff in C++ put on a closing |
| /// bracket). It's useful for code coverage to not show a counter on "empty" |
| /// lines. |
| bool isImplicitCode() const { return ImplicitCode; } |
| void setImplicitCode(bool ImplicitCode) { this->ImplicitCode = ImplicitCode; } |
| |
| DIFile *getFile() const { return getScope()->getFile(); } |
| StringRef getFilename() const { return getScope()->getFilename(); } |
| StringRef getDirectory() const { return getScope()->getDirectory(); } |
| Optional<StringRef> getSource() const { return getScope()->getSource(); } |
| |
| /// Get the scope where this is inlined. |
| /// |
| /// Walk through \a getInlinedAt() and return \a getScope() from the deepest |
| /// location. |
| DILocalScope *getInlinedAtScope() const { |
| if (auto *IA = getInlinedAt()) |
| return IA->getInlinedAtScope(); |
| return getScope(); |
| } |
| |
| /// Get the DWARF discriminator. |
| /// |
| /// DWARF discriminators distinguish identical file locations between |
| /// instructions that are on different basic blocks. |
| /// |
| /// There are 3 components stored in discriminator, from lower bits: |
| /// |
| /// Base discriminator: assigned by AddDiscriminators pass to identify IRs |
| /// that are defined by the same source line, but |
| /// different basic blocks. |
| /// Duplication factor: assigned by optimizations that will scale down |
| /// the execution frequency of the original IR. |
| /// Copy Identifier: assigned by optimizations that clones the IR. |
| /// Each copy of the IR will be assigned an identifier. |
| /// |
| /// Encoding: |
| /// |
| /// The above 3 components are encoded into a 32bit unsigned integer in |
| /// order. If the lowest bit is 1, the current component is empty, and the |
| /// next component will start in the next bit. Otherwise, the current |
| /// component is non-empty, and its content starts in the next bit. The |
| /// value of each components is either 5 bit or 12 bit: if the 7th bit |
| /// is 0, the bit 2~6 (5 bits) are used to represent the component; if the |
| /// 7th bit is 1, the bit 2~6 (5 bits) and 8~14 (7 bits) are combined to |
| /// represent the component. Thus, the number of bits used for a component |
| /// is either 0 (if it and all the next components are empty); 1 - if it is |
| /// empty; 7 - if its value is up to and including 0x1f (lsb and msb are both |
| /// 0); or 14, if its value is up to and including 0x1ff. Note that the last |
| /// component is also capped at 0x1ff, even in the case when both first |
| /// components are 0, and we'd technically have 29 bits available. |
| /// |
| /// For precise control over the data being encoded in the discriminator, |
| /// use encodeDiscriminator/decodeDiscriminator. |
| |
| inline unsigned getDiscriminator() const; |
| |
| /// Returns a new DILocation with updated \p Discriminator. |
| inline const DILocation *cloneWithDiscriminator(unsigned Discriminator) const; |
| |
| /// Returns a new DILocation with updated base discriminator \p BD. Only the |
| /// base discriminator is set in the new DILocation, the other encoded values |
| /// are elided. |
| /// If the discriminator cannot be encoded, the function returns None. |
| inline Optional<const DILocation *> cloneWithBaseDiscriminator(unsigned BD) const; |
| |
| /// Returns the duplication factor stored in the discriminator, or 1 if no |
| /// duplication factor (or 0) is encoded. |
| inline unsigned getDuplicationFactor() const; |
| |
| /// Returns the copy identifier stored in the discriminator. |
| inline unsigned getCopyIdentifier() const; |
| |
| /// Returns the base discriminator stored in the discriminator. |
| inline unsigned getBaseDiscriminator() const; |
| |
| /// Returns a new DILocation with duplication factor \p DF * current |
| /// duplication factor encoded in the discriminator. The current duplication |
| /// factor is as defined by getDuplicationFactor(). |
| /// Returns None if encoding failed. |
| inline Optional<const DILocation *> cloneByMultiplyingDuplicationFactor(unsigned DF) const; |
| |
| /// When two instructions are combined into a single instruction we also |
| /// need to combine the original locations into a single location. |
| /// |
| /// When the locations are the same we can use either location. When they |
| /// differ, we need a third location which is distinct from either. If they |
| /// have the same file/line but have a different discriminator we could |
| /// create a location with a new discriminator. If they are from different |
| /// files/lines the location is ambiguous and can't be represented in a line |
| /// entry. In this case, if \p GenerateLocation is true, we will set the |
| /// merged debug location as line 0 of the nearest common scope where the two |
| /// locations are inlined from. |
| /// |
| /// \p GenerateLocation: Whether the merged location can be generated when |
| /// \p LocA and \p LocB differ. |
| static const DILocation *getMergedLocation(const DILocation *LocA, |
| const DILocation *LocB); |
| |
| /// Returns the base discriminator for a given encoded discriminator \p D. |
| static unsigned getBaseDiscriminatorFromDiscriminator(unsigned D) { |
| return getUnsignedFromPrefixEncoding(D); |
| } |
| |
| /// Raw encoding of the discriminator. APIs such as cloneWithDuplicationFactor |
| /// have certain special case behavior (e.g. treating empty duplication factor |
| /// as the value '1'). |
| /// This API, in conjunction with cloneWithDiscriminator, may be used to encode |
| /// the raw values provided. \p BD: base discriminator \p DF: duplication factor |
| /// \p CI: copy index |
| /// The return is None if the values cannot be encoded in 32 bits - for |
| /// example, values for BD or DF larger than 12 bits. Otherwise, the return |
| /// is the encoded value. |
| static Optional<unsigned> encodeDiscriminator(unsigned BD, unsigned DF, unsigned CI); |
| |
| /// Raw decoder for values in an encoded discriminator D. |
| static void decodeDiscriminator(unsigned D, unsigned &BD, unsigned &DF, |
| unsigned &CI); |
| |
| /// Returns the duplication factor for a given encoded discriminator \p D, or |
| /// 1 if no value or 0 is encoded. |
| static unsigned getDuplicationFactorFromDiscriminator(unsigned D) { |
| D = getNextComponentInDiscriminator(D); |
| unsigned Ret = getUnsignedFromPrefixEncoding(D); |
| if (Ret == 0) |
| return 1; |
| return Ret; |
| } |
| |
| /// Returns the copy identifier for a given encoded discriminator \p D. |
| static unsigned getCopyIdentifierFromDiscriminator(unsigned D) { |
| return getUnsignedFromPrefixEncoding(getNextComponentInDiscriminator( |
| getNextComponentInDiscriminator(D))); |
| } |
| |
| |
| Metadata *getRawScope() const { return getOperand(0); } |
| Metadata *getRawInlinedAt() const { |
| if (getNumOperands() == 2) |
| return getOperand(1); |
| return nullptr; |
| } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DILocationKind; |
| } |
| }; |
| |
| /// Subprogram description. |
| /// |
| /// TODO: Remove DisplayName. It's always equal to Name. |
| /// TODO: Split up flags. |
| class DISubprogram : public DILocalScope { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| unsigned Line; |
| unsigned ScopeLine; |
| unsigned VirtualIndex; |
| |
| /// In the MS ABI, the implicit 'this' parameter is adjusted in the prologue |
| /// of method overrides from secondary bases by this amount. It may be |
| /// negative. |
| int ThisAdjustment; |
| |
| public: |
| /// Debug info subprogram flags. |
| enum DISPFlags : uint32_t { |
| #define HANDLE_DISP_FLAG(ID, NAME) SPFlag##NAME = ID, |
| #define DISP_FLAG_LARGEST_NEEDED |
| #include "llvm/IR/DebugInfoFlags.def" |
| SPFlagNonvirtual = SPFlagZero, |
| SPFlagVirtuality = SPFlagVirtual | SPFlagPureVirtual, |
| LLVM_MARK_AS_BITMASK_ENUM(SPFlagLargest) |
| }; |
| |
| static DISPFlags getFlag(StringRef Flag); |
| static StringRef getFlagString(DISPFlags Flag); |
| |
| /// Split up a flags bitfield for easier printing. |
| /// |
| /// Split \c Flags into \c SplitFlags, a vector of its components. Returns |
| /// any remaining (unrecognized) bits. |
| static DISPFlags splitFlags(DISPFlags Flags, |
| SmallVectorImpl<DISPFlags> &SplitFlags); |
| |
| // Helper for converting old bitfields to new flags word. |
| static DISPFlags toSPFlags(bool IsLocalToUnit, bool IsDefinition, |
| bool IsOptimized, |
| unsigned Virtuality = SPFlagNonvirtual) { |
| // We're assuming virtuality is the low-order field. |
| static_assert( |
| int(SPFlagVirtual) == int(dwarf::DW_VIRTUALITY_virtual) && |
| int(SPFlagPureVirtual) == int(dwarf::DW_VIRTUALITY_pure_virtual), |
| "Virtuality constant mismatch"); |
| return static_cast<DISPFlags>( |
| (Virtuality & SPFlagVirtuality) | |
| (IsLocalToUnit ? SPFlagLocalToUnit : SPFlagZero) | |
| (IsDefinition ? SPFlagDefinition : SPFlagZero) | |
| (IsOptimized ? SPFlagOptimized : SPFlagZero)); |
| } |
| |
| private: |
| DIFlags Flags; |
| DISPFlags SPFlags; |
| |
| DISubprogram(LLVMContext &C, StorageType Storage, unsigned Line, |
| unsigned ScopeLine, unsigned VirtualIndex, int ThisAdjustment, |
| DIFlags Flags, DISPFlags SPFlags, ArrayRef<Metadata *> Ops) |
| : DILocalScope(C, DISubprogramKind, Storage, dwarf::DW_TAG_subprogram, |
| Ops), |
| Line(Line), ScopeLine(ScopeLine), VirtualIndex(VirtualIndex), |
| ThisAdjustment(ThisAdjustment), Flags(Flags), SPFlags(SPFlags) { |
| static_assert(dwarf::DW_VIRTUALITY_max < 4, "Virtuality out of range"); |
| } |
| ~DISubprogram() = default; |
| |
| static DISubprogram * |
| getImpl(LLVMContext &Context, DIScopeRef Scope, StringRef Name, |
| StringRef LinkageName, DIFile *File, unsigned Line, |
| DISubroutineType *Type, unsigned ScopeLine, DITypeRef ContainingType, |
| unsigned VirtualIndex, int ThisAdjustment, DIFlags Flags, |
| DISPFlags SPFlags, DICompileUnit *Unit, |
| DITemplateParameterArray TemplateParams, DISubprogram *Declaration, |
| DINodeArray RetainedNodes, DITypeArray ThrownTypes, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Scope, getCanonicalMDString(Context, Name), |
| getCanonicalMDString(Context, LinkageName), File, Line, Type, |
| ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, |
| Flags, SPFlags, Unit, TemplateParams.get(), Declaration, |
| RetainedNodes.get(), ThrownTypes.get(), Storage, |
| ShouldCreate); |
| } |
| static DISubprogram *getImpl(LLVMContext &Context, Metadata *Scope, |
| MDString *Name, MDString *LinkageName, |
| Metadata *File, unsigned Line, Metadata *Type, |
| unsigned ScopeLine, Metadata *ContainingType, |
| unsigned VirtualIndex, int ThisAdjustment, |
| DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, |
| Metadata *TemplateParams, Metadata *Declaration, |
| Metadata *RetainedNodes, Metadata *ThrownTypes, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDISubprogram cloneImpl() const { |
| return getTemporary(getContext(), getScope(), getName(), getLinkageName(), |
| getFile(), getLine(), getType(), getScopeLine(), |
| getContainingType(), getVirtualIndex(), |
| getThisAdjustment(), getFlags(), getSPFlags(), |
| getUnit(), getTemplateParams(), getDeclaration(), |
| getRetainedNodes(), getThrownTypes()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET( |
| DISubprogram, |
| (DIScopeRef Scope, StringRef Name, StringRef LinkageName, DIFile *File, |
| unsigned Line, DISubroutineType *Type, unsigned ScopeLine, |
| DITypeRef ContainingType, unsigned VirtualIndex, int ThisAdjustment, |
| DIFlags Flags, DISPFlags SPFlags, DICompileUnit *Unit, |
| DITemplateParameterArray TemplateParams = nullptr, |
| DISubprogram *Declaration = nullptr, DINodeArray RetainedNodes = nullptr, |
| DITypeArray ThrownTypes = nullptr), |
| (Scope, Name, LinkageName, File, Line, Type, ScopeLine, ContainingType, |
| VirtualIndex, ThisAdjustment, Flags, SPFlags, Unit, TemplateParams, |
| Declaration, RetainedNodes, ThrownTypes)) |
| |
| DEFINE_MDNODE_GET( |
| DISubprogram, |
| (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, |
| unsigned Line, Metadata *Type, unsigned ScopeLine, |
| Metadata *ContainingType, unsigned VirtualIndex, int ThisAdjustment, |
| DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, |
| Metadata *TemplateParams = nullptr, Metadata *Declaration = nullptr, |
| Metadata *RetainedNodes = nullptr, Metadata *ThrownTypes = nullptr), |
| (Scope, Name, LinkageName, File, Line, Type, ScopeLine, ContainingType, |
| VirtualIndex, ThisAdjustment, Flags, SPFlags, Unit, TemplateParams, |
| Declaration, RetainedNodes, ThrownTypes)) |
| |
| TempDISubprogram clone() const { return cloneImpl(); } |
| |
| /// Returns a new temporary DISubprogram with updated Flags |
| TempDISubprogram cloneWithFlags(DIFlags NewFlags) const { |
| auto NewSP = clone(); |
| NewSP->Flags = NewFlags; |
| return NewSP; |
| } |
| |
| public: |
| unsigned getLine() const { return Line; } |
| unsigned getVirtuality() const { return getSPFlags() & SPFlagVirtuality; } |
| unsigned getVirtualIndex() const { return VirtualIndex; } |
| int getThisAdjustment() const { return ThisAdjustment; } |
| unsigned getScopeLine() const { return ScopeLine; } |
| DIFlags getFlags() const { return Flags; } |
| DISPFlags getSPFlags() const { return SPFlags; } |
| bool isLocalToUnit() const { return getSPFlags() & SPFlagLocalToUnit; } |
| bool isDefinition() const { return getSPFlags() & SPFlagDefinition; } |
| bool isOptimized() const { return getSPFlags() & SPFlagOptimized; } |
| |
| bool isArtificial() const { return getFlags() & FlagArtificial; } |
| bool isPrivate() const { |
| return (getFlags() & FlagAccessibility) == FlagPrivate; |
| } |
| bool isProtected() const { |
| return (getFlags() & FlagAccessibility) == FlagProtected; |
| } |
| bool isPublic() const { |
| return (getFlags() & FlagAccessibility) == FlagPublic; |
| } |
| bool isExplicit() const { return getFlags() & FlagExplicit; } |
| bool isPrototyped() const { return getFlags() & FlagPrototyped; } |
| bool areAllCallsDescribed() const { |
| return getFlags() & FlagAllCallsDescribed; |
| } |
| bool isMainSubprogram() const { return getFlags() & FlagMainSubprogram; } |
| |
| /// Check if this is reference-qualified. |
| /// |
| /// Return true if this subprogram is a C++11 reference-qualified non-static |
| /// member function (void foo() &). |
| bool isLValueReference() const { return getFlags() & FlagLValueReference; } |
| |
| /// Check if this is rvalue-reference-qualified. |
| /// |
| /// Return true if this subprogram is a C++11 rvalue-reference-qualified |
| /// non-static member function (void foo() &&). |
| bool isRValueReference() const { return getFlags() & FlagRValueReference; } |
| |
| /// Check if this is marked as noreturn. |
| /// |
| /// Return true if this subprogram is C++11 noreturn or C11 _Noreturn |
| bool isNoReturn() const { return getFlags() & FlagNoReturn; } |
| |
| // Check if this routine is a compiler-generated thunk. |
| // |
| // Returns true if this subprogram is a thunk generated by the compiler. |
| bool isThunk() const { return getFlags() & FlagThunk; } |
| |
| DIScopeRef getScope() const { return DIScopeRef(getRawScope()); } |
| |
| StringRef getName() const { return getStringOperand(2); } |
| StringRef getLinkageName() const { return getStringOperand(3); } |
| |
| DISubroutineType *getType() const { |
| return cast_or_null<DISubroutineType>(getRawType()); |
| } |
| DITypeRef getContainingType() const { |
| return DITypeRef(getRawContainingType()); |
| } |
| |
| DICompileUnit *getUnit() const { |
| return cast_or_null<DICompileUnit>(getRawUnit()); |
| } |
| void replaceUnit(DICompileUnit *CU) { replaceOperandWith(5, CU); } |
| DITemplateParameterArray getTemplateParams() const { |
| return cast_or_null<MDTuple>(getRawTemplateParams()); |
| } |
| DISubprogram *getDeclaration() const { |
| return cast_or_null<DISubprogram>(getRawDeclaration()); |
| } |
| DINodeArray getRetainedNodes() const { |
| return cast_or_null<MDTuple>(getRawRetainedNodes()); |
| } |
| DITypeArray getThrownTypes() const { |
| return cast_or_null<MDTuple>(getRawThrownTypes()); |
| } |
| |
| Metadata *getRawScope() const { return getOperand(1); } |
| MDString *getRawName() const { return getOperandAs<MDString>(2); } |
| MDString *getRawLinkageName() const { return getOperandAs<MDString>(3); } |
| Metadata *getRawType() const { return getOperand(4); } |
| Metadata *getRawUnit() const { return getOperand(5); } |
| Metadata *getRawDeclaration() const { return getOperand(6); } |
| Metadata *getRawRetainedNodes() const { return getOperand(7); } |
| Metadata *getRawContainingType() const { |
| return getNumOperands() > 8 ? getOperandAs<Metadata>(8) : nullptr; |
| } |
| Metadata *getRawTemplateParams() const { |
| return getNumOperands() > 9 ? getOperandAs<Metadata>(9) : nullptr; |
| } |
| Metadata *getRawThrownTypes() const { |
| return getNumOperands() > 10 ? getOperandAs<Metadata>(10) : nullptr; |
| } |
| |
| /// Check if this subprogram describes the given function. |
| /// |
| /// FIXME: Should this be looking through bitcasts? |
| bool describes(const Function *F) const; |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DISubprogramKind; |
| } |
| }; |
| |
| class DILexicalBlockBase : public DILocalScope { |
| protected: |
| DILexicalBlockBase(LLVMContext &C, unsigned ID, StorageType Storage, |
| ArrayRef<Metadata *> Ops) |
| : DILocalScope(C, ID, Storage, dwarf::DW_TAG_lexical_block, Ops) {} |
| ~DILexicalBlockBase() = default; |
| |
| public: |
| DILocalScope *getScope() const { return cast<DILocalScope>(getRawScope()); } |
| |
| Metadata *getRawScope() const { return getOperand(1); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DILexicalBlockKind || |
| MD->getMetadataID() == DILexicalBlockFileKind; |
| } |
| }; |
| |
| class DILexicalBlock : public DILexicalBlockBase { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| unsigned Line; |
| uint16_t Column; |
| |
| DILexicalBlock(LLVMContext &C, StorageType Storage, unsigned Line, |
| unsigned Column, ArrayRef<Metadata *> Ops) |
| : DILexicalBlockBase(C, DILexicalBlockKind, Storage, Ops), Line(Line), |
| Column(Column) { |
| assert(Column < (1u << 16) && "Expected 16-bit column"); |
| } |
| ~DILexicalBlock() = default; |
| |
| static DILexicalBlock *getImpl(LLVMContext &Context, DILocalScope *Scope, |
| DIFile *File, unsigned Line, unsigned Column, |
| StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, static_cast<Metadata *>(Scope), |
| static_cast<Metadata *>(File), Line, Column, Storage, |
| ShouldCreate); |
| } |
| |
| static DILexicalBlock *getImpl(LLVMContext &Context, Metadata *Scope, |
| Metadata *File, unsigned Line, unsigned Column, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDILexicalBlock cloneImpl() const { |
| return getTemporary(getContext(), getScope(), getFile(), getLine(), |
| getColumn()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DILexicalBlock, (DILocalScope * Scope, DIFile *File, |
| unsigned Line, unsigned Column), |
| (Scope, File, Line, Column)) |
| DEFINE_MDNODE_GET(DILexicalBlock, (Metadata * Scope, Metadata *File, |
| unsigned Line, unsigned Column), |
| (Scope, File, Line, Column)) |
| |
| TempDILexicalBlock clone() const { return cloneImpl(); } |
| |
| unsigned getLine() const { return Line; } |
| unsigned getColumn() const { return Column; } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DILexicalBlockKind; |
| } |
| }; |
| |
| class DILexicalBlockFile : public DILexicalBlockBase { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| unsigned Discriminator; |
| |
| DILexicalBlockFile(LLVMContext &C, StorageType Storage, |
| unsigned Discriminator, ArrayRef<Metadata *> Ops) |
| : DILexicalBlockBase(C, DILexicalBlockFileKind, Storage, Ops), |
| Discriminator(Discriminator) {} |
| ~DILexicalBlockFile() = default; |
| |
| static DILexicalBlockFile *getImpl(LLVMContext &Context, DILocalScope *Scope, |
| DIFile *File, unsigned Discriminator, |
| StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, static_cast<Metadata *>(Scope), |
| static_cast<Metadata *>(File), Discriminator, Storage, |
| ShouldCreate); |
| } |
| |
| static DILexicalBlockFile *getImpl(LLVMContext &Context, Metadata *Scope, |
| Metadata *File, unsigned Discriminator, |
| StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDILexicalBlockFile cloneImpl() const { |
| return getTemporary(getContext(), getScope(), getFile(), |
| getDiscriminator()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DILexicalBlockFile, (DILocalScope * Scope, DIFile *File, |
| unsigned Discriminator), |
| (Scope, File, Discriminator)) |
| DEFINE_MDNODE_GET(DILexicalBlockFile, |
| (Metadata * Scope, Metadata *File, unsigned Discriminator), |
| (Scope, File, Discriminator)) |
| |
| TempDILexicalBlockFile clone() const { return cloneImpl(); } |
| |
| // TODO: Remove these once they're gone from DILexicalBlockBase. |
| unsigned getLine() const = delete; |
| unsigned getColumn() const = delete; |
| |
| unsigned getDiscriminator() const { return Discriminator; } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DILexicalBlockFileKind; |
| } |
| }; |
| |
| unsigned DILocation::getDiscriminator() const { |
| if (auto *F = dyn_cast<DILexicalBlockFile>(getScope())) |
| return F->getDiscriminator(); |
| return 0; |
| } |
| |
| const DILocation * |
| DILocation::cloneWithDiscriminator(unsigned Discriminator) const { |
| DIScope *Scope = getScope(); |
| // Skip all parent DILexicalBlockFile that already have a discriminator |
| // assigned. We do not want to have nested DILexicalBlockFiles that have |
| // mutliple discriminators because only the leaf DILexicalBlockFile's |
| // dominator will be used. |
| for (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope); |
| LBF && LBF->getDiscriminator() != 0; |
| LBF = dyn_cast<DILexicalBlockFile>(Scope)) |
| Scope = LBF->getScope(); |
| DILexicalBlockFile *NewScope = |
| DILexicalBlockFile::get(getContext(), Scope, getFile(), Discriminator); |
| return DILocation::get(getContext(), getLine(), getColumn(), NewScope, |
| getInlinedAt()); |
| } |
| |
| unsigned DILocation::getBaseDiscriminator() const { |
| return getBaseDiscriminatorFromDiscriminator(getDiscriminator()); |
| } |
| |
| unsigned DILocation::getDuplicationFactor() const { |
| return getDuplicationFactorFromDiscriminator(getDiscriminator()); |
| } |
| |
| unsigned DILocation::getCopyIdentifier() const { |
| return getCopyIdentifierFromDiscriminator(getDiscriminator()); |
| } |
| |
| Optional<const DILocation *> DILocation::cloneWithBaseDiscriminator(unsigned D) const { |
| unsigned BD, DF, CI; |
| decodeDiscriminator(getDiscriminator(), BD, DF, CI); |
| if (D == BD) |
| return this; |
| if (Optional<unsigned> Encoded = encodeDiscriminator(D, DF, CI)) |
| return cloneWithDiscriminator(*Encoded); |
| return None; |
| } |
| |
| Optional<const DILocation *> DILocation::cloneByMultiplyingDuplicationFactor(unsigned DF) const { |
| DF *= getDuplicationFactor(); |
| if (DF <= 1) |
| return this; |
| |
| unsigned BD = getBaseDiscriminator(); |
| unsigned CI = getCopyIdentifier(); |
| if (Optional<unsigned> D = encodeDiscriminator(BD, DF, CI)) |
| return cloneWithDiscriminator(*D); |
| return None; |
| } |
| |
| class DINamespace : public DIScope { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| unsigned ExportSymbols : 1; |
| |
| DINamespace(LLVMContext &Context, StorageType Storage, bool ExportSymbols, |
| ArrayRef<Metadata *> Ops) |
| : DIScope(Context, DINamespaceKind, Storage, dwarf::DW_TAG_namespace, |
| Ops), |
| ExportSymbols(ExportSymbols) {} |
| ~DINamespace() = default; |
| |
| static DINamespace *getImpl(LLVMContext &Context, DIScope *Scope, |
| StringRef Name, bool ExportSymbols, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Scope, getCanonicalMDString(Context, Name), |
| ExportSymbols, Storage, ShouldCreate); |
| } |
| static DINamespace *getImpl(LLVMContext &Context, Metadata *Scope, |
| MDString *Name, bool ExportSymbols, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDINamespace cloneImpl() const { |
| return getTemporary(getContext(), getScope(), getName(), |
| getExportSymbols()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DINamespace, |
| (DIScope *Scope, StringRef Name, bool ExportSymbols), |
| (Scope, Name, ExportSymbols)) |
| DEFINE_MDNODE_GET(DINamespace, |
| (Metadata *Scope, MDString *Name, bool ExportSymbols), |
| (Scope, Name, ExportSymbols)) |
| |
| TempDINamespace clone() const { return cloneImpl(); } |
| |
| bool getExportSymbols() const { return ExportSymbols; } |
| DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); } |
| StringRef getName() const { return getStringOperand(2); } |
| |
| Metadata *getRawScope() const { return getOperand(1); } |
| MDString *getRawName() const { return getOperandAs<MDString>(2); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DINamespaceKind; |
| } |
| }; |
| |
| /// A (clang) module that has been imported by the compile unit. |
| /// |
| class DIModule : public DIScope { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| DIModule(LLVMContext &Context, StorageType Storage, ArrayRef<Metadata *> Ops) |
| : DIScope(Context, DIModuleKind, Storage, dwarf::DW_TAG_module, Ops) {} |
| ~DIModule() = default; |
| |
| static DIModule *getImpl(LLVMContext &Context, DIScope *Scope, |
| StringRef Name, StringRef ConfigurationMacros, |
| StringRef IncludePath, StringRef ISysRoot, |
| StorageType Storage, bool ShouldCreate = true) { |
| return getImpl(Context, Scope, getCanonicalMDString(Context, Name), |
| getCanonicalMDString(Context, ConfigurationMacros), |
| getCanonicalMDString(Context, IncludePath), |
| getCanonicalMDString(Context, ISysRoot), |
| Storage, ShouldCreate); |
| } |
| static DIModule *getImpl(LLVMContext &Context, Metadata *Scope, |
| MDString *Name, MDString *ConfigurationMacros, |
| MDString *IncludePath, MDString *ISysRoot, |
| StorageType Storage, bool ShouldCreate = true); |
| |
| TempDIModule cloneImpl() const { |
| return getTemporary(getContext(), getScope(), getName(), |
| getConfigurationMacros(), getIncludePath(), |
| getISysRoot()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DIModule, (DIScope *Scope, StringRef Name, |
| StringRef ConfigurationMacros, StringRef IncludePath, |
| StringRef ISysRoot), |
| (Scope, Name, ConfigurationMacros, IncludePath, ISysRoot)) |
| DEFINE_MDNODE_GET(DIModule, |
| (Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, |
| MDString *IncludePath, MDString *ISysRoot), |
| (Scope, Name, ConfigurationMacros, IncludePath, ISysRoot)) |
| |
| TempDIModule clone() const { return cloneImpl(); } |
| |
| DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); } |
| StringRef getName() const { return getStringOperand(1); } |
| StringRef getConfigurationMacros() const { return getStringOperand(2); } |
| StringRef getIncludePath() const { return getStringOperand(3); } |
| StringRef getISysRoot() const { return getStringOperand(4); } |
| |
| Metadata *getRawScope() const { return getOperand(0); } |
| MDString *getRawName() const { return getOperandAs<MDString>(1); } |
| MDString *getRawConfigurationMacros() const { return getOperandAs<MDString>(2); } |
| MDString *getRawIncludePath() const { return getOperandAs<MDString>(3); } |
| MDString *getRawISysRoot() const { return getOperandAs<MDString>(4); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DIModuleKind; |
| } |
| }; |
| |
| /// Base class for template parameters. |
| class DITemplateParameter : public DINode { |
| protected: |
| DITemplateParameter(LLVMContext &Context, unsigned ID, StorageType Storage, |
| unsigned Tag, ArrayRef<Metadata *> Ops) |
| : DINode(Context, ID, Storage, Tag, Ops) {} |
| ~DITemplateParameter() = default; |
| |
| public: |
| StringRef getName() const { return getStringOperand(0); } |
| DITypeRef getType() const { return DITypeRef(getRawType()); } |
| |
| MDString *getRawName() const { return getOperandAs<MDString>(0); } |
| Metadata *getRawType() const { return getOperand(1); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DITemplateTypeParameterKind || |
| MD->getMetadataID() == DITemplateValueParameterKind; |
| } |
| }; |
| |
| class DITemplateTypeParameter : public DITemplateParameter { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| DITemplateTypeParameter(LLVMContext &Context, StorageType Storage, |
| ArrayRef<Metadata *> Ops) |
| : DITemplateParameter(Context, DITemplateTypeParameterKind, Storage, |
| dwarf::DW_TAG_template_type_parameter, Ops) {} |
| ~DITemplateTypeParameter() = default; |
| |
| static DITemplateTypeParameter *getImpl(LLVMContext &Context, StringRef Name, |
| DITypeRef Type, StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, getCanonicalMDString(Context, Name), Type, Storage, |
| ShouldCreate); |
| } |
| static DITemplateTypeParameter *getImpl(LLVMContext &Context, MDString *Name, |
| Metadata *Type, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDITemplateTypeParameter cloneImpl() const { |
| return getTemporary(getContext(), getName(), getType()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DITemplateTypeParameter, (StringRef Name, DITypeRef Type), |
| (Name, Type)) |
| DEFINE_MDNODE_GET(DITemplateTypeParameter, (MDString * Name, Metadata *Type), |
| (Name, Type)) |
| |
| TempDITemplateTypeParameter clone() const { return cloneImpl(); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DITemplateTypeParameterKind; |
| } |
| }; |
| |
| class DITemplateValueParameter : public DITemplateParameter { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| DITemplateValueParameter(LLVMContext &Context, StorageType Storage, |
| unsigned Tag, ArrayRef<Metadata *> Ops) |
| : DITemplateParameter(Context, DITemplateValueParameterKind, Storage, Tag, |
| Ops) {} |
| ~DITemplateValueParameter() = default; |
| |
| static DITemplateValueParameter *getImpl(LLVMContext &Context, unsigned Tag, |
| StringRef Name, DITypeRef Type, |
| Metadata *Value, StorageType Storage, |
| bool ShouldCreate = true) { |
| return getImpl(Context, Tag, getCanonicalMDString(Context, Name), Type, |
| Value, Storage, ShouldCreate); |
| } |
| static DITemplateValueParameter *getImpl(LLVMContext &Context, unsigned Tag, |
| MDString *Name, Metadata *Type, |
| Metadata *Value, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDITemplateValueParameter cloneImpl() const { |
| return getTemporary(getContext(), getTag(), getName(), getType(), |
| getValue()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DITemplateValueParameter, (unsigned Tag, StringRef Name, |
| DITypeRef Type, Metadata *Value), |
| (Tag, Name, Type, Value)) |
| DEFINE_MDNODE_GET(DITemplateValueParameter, (unsigned Tag, MDString *Name, |
| Metadata *Type, Metadata *Value), |
| (Tag, Name, Type, Value)) |
| |
| TempDITemplateValueParameter clone() const { return cloneImpl(); } |
| |
| Metadata *getValue() const { return getOperand(2); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DITemplateValueParameterKind; |
| } |
| }; |
| |
| /// Base class for variables. |
| class DIVariable : public DINode { |
| unsigned Line; |
| uint32_t AlignInBits; |
| |
| protected: |
| DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Line, |
| ArrayRef<Metadata *> Ops, uint32_t AlignInBits = 0) |
| : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line), |
| AlignInBits(AlignInBits) {} |
| ~DIVariable() = default; |
| |
| public: |
| unsigned getLine() const { return Line; } |
| DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); } |
| StringRef getName() const { return getStringOperand(1); } |
| DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); } |
| DITypeRef getType() const { return DITypeRef(getRawType()); } |
| uint32_t getAlignInBits() const { return AlignInBits; } |
| uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; } |
| /// Determines the size of the variable's type. |
| Optional<uint64_t> getSizeInBits() const; |
| |
| /// Return the signedness of this variable's type, or None if this type is |
| /// neither signed nor unsigned. |
| Optional<DIBasicType::Signedness> getSignedness() const { |
| if (auto *BT = dyn_cast<DIBasicType>(getType().resolve())) |
| return BT->getSignedness(); |
| return None; |
| } |
| |
| StringRef getFilename() const { |
| if (auto *F = getFile()) |
| return F->getFilename(); |
| return ""; |
| } |
| |
| StringRef getDirectory() const { |
| if (auto *F = getFile()) |
| return F->getDirectory(); |
| return ""; |
| } |
| |
| Optional<StringRef> getSource() const { |
| if (auto *F = getFile()) |
| return F->getSource(); |
| return None; |
| } |
| |
| Metadata *getRawScope() const { return getOperand(0); } |
| MDString *getRawName() const { return getOperandAs<MDString>(1); } |
| Metadata *getRawFile() const { return getOperand(2); } |
| Metadata *getRawType() const { return getOperand(3); } |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DILocalVariableKind || |
| MD->getMetadataID() == DIGlobalVariableKind; |
| } |
| }; |
| |
| /// DWARF expression. |
| /// |
| /// This is (almost) a DWARF expression that modifies the location of a |
| /// variable, or the location of a single piece of a variable, or (when using |
| /// DW_OP_stack_value) is the constant variable value. |
| /// |
| /// TODO: Co-allocate the expression elements. |
| /// TODO: Separate from MDNode, or otherwise drop Distinct and Temporary |
| /// storage types. |
| class DIExpression : public MDNode { |
| friend class LLVMContextImpl; |
| friend class MDNode; |
| |
| std::vector<uint64_t> Elements; |
| |
| DIExpression(LLVMContext &C, StorageType Storage, ArrayRef<uint64_t> Elements) |
| : MDNode(C, DIExpressionKind, Storage, None), |
| Elements(Elements.begin(), Elements.end()) {} |
| ~DIExpression() = default; |
| |
| static DIExpression *getImpl(LLVMContext &Context, |
| ArrayRef<uint64_t> Elements, StorageType Storage, |
| bool ShouldCreate = true); |
| |
| TempDIExpression cloneImpl() const { |
| return getTemporary(getContext(), getElements()); |
| } |
| |
| public: |
| DEFINE_MDNODE_GET(DIExpression, (ArrayRef<uint64_t> Elements), (Elements)) |
| |
| TempDIExpression clone() const { return cloneImpl(); } |
| |
| ArrayRef<uint64_t> getElements() const { return Elements; } |
| |
| unsigned getNumElements() const { return Elements.size(); } |
| |
| uint64_t getElement(unsigned I) const { |
| assert(I < Elements.size() && "Index out of range"); |
| return Elements[I]; |
| } |
| |
| /// Determine whether this represents a standalone constant value. |
| bool isConstant() const; |
| |
| using element_iterator = ArrayRef<uint64_t>::iterator; |
| |
| element_iterator elements_begin() const { return getElements().begin(); } |
| element_iterator elements_end() const { return getElements().end(); } |
| |
| /// A lightweight wrapper around an expression operand. |
| /// |
| /// TODO: Store arguments directly and change \a DIExpression to store a |
| /// range of these. |
| class ExprOperand { |
| const uint64_t *Op = nullptr; |
| |
| public: |
| ExprOperand() = default; |
| explicit ExprOperand(const uint64_t *Op) : Op(Op) {} |
| |
| const uint64_t *get() const { return Op; } |
| |
| /// Get the operand code. |
| uint64_t getOp() const { return *Op; } |
| |
| /// Get an argument to the operand. |
| /// |
| /// Never returns the operand itself. |
| uint64_t getArg(unsigned I) const { return Op[I + 1]; } |
| |
| unsigned getNumArgs() const { return getSize() - 1; } |
| |
| /// Return the size of the operand. |
| /// |
| /// Return the number of elements in the operand (1 + args). |
| unsigned getSize() const; |
| |
| /// Append the elements of this operand to \p V. |
| void appendToVector(SmallVectorImpl<uint64_t> &V) const { |
| V.append(get(), get() + getSize()); |
| } |
| }; |
| |
| /// An iterator for expression operands. |
| class expr_op_iterator |
| : public std::iterator<std::input_iterator_tag, ExprOperand> { |
| ExprOperand Op; |
| |
| public: |
| expr_op_iterator() = default; |
| explicit expr_op_iterator(element_iterator I) : Op(I) {} |
| |
| element_iterator getBase() const { return Op.get(); } |
| const ExprOperand &operator*() const { return Op; } |
| const ExprOperand *operator->() const { return &Op; } |
| |
| expr_op_iterator &operator++() { |
| increment(); |
| return *this; |
| } |
| expr_op_iterator operator++(int) { |
| expr_op_iterator T(*this); |
| increment(); |
| return T; |
| } |
| |
| /// Get the next iterator. |
| /// |
| /// \a std::next() doesn't work because this is technically an |
| /// input_iterator, but it's a perfectly valid operation. This is an |
| /// accessor to provide the same functionality. |
| expr_op_iterator getNext() const { return ++expr_op_iterator(*this); } |
| |
| bool operator==(const expr_op_iterator &X) const { |
| return getBase() == X.getBase(); |
| } |
| bool operator!=(const expr_op_iterator &X) const { |
| return getBase() != X.getBase(); |
| } |
| |
| private: |
| void increment() { Op = ExprOperand(getBase() + Op.getSize()); } |
| }; |
| |
| /// Visit the elements via ExprOperand wrappers. |
| /// |
| /// These range iterators visit elements through \a ExprOperand wrappers. |
| /// This is not guaranteed to be a valid range unless \a isValid() gives \c |
| /// true. |
| /// |
| /// \pre \a isValid() gives \c true. |
| /// @{ |
| expr_op_iterator expr_op_begin() const { |
| return expr_op_iterator(elements_begin()); |
| } |
| expr_op_iterator expr_op_end() const { |
| return expr_op_iterator(elements_end()); |
| } |
| iterator_range<expr_op_iterator> expr_ops() const { |
| return {expr_op_begin(), expr_op_end()}; |
| } |
| /// @} |
| |
| bool isValid() const; |
| |
| static bool classof(const Metadata *MD) { |
| return MD->getMetadataID() == DIExpressionKind; |
| } |
| |
| /// Return whether the first element a DW_OP_deref. |
| bool startsWithDeref() const { |
| return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref; |
| } |
| |
| /// Holds the characteristics of one fragment of a larger variable. |
| struct FragmentInfo { |
| uint64_t SizeInBits; |
| uint64_t OffsetInBits; |
| }; |
| |
| /// Retrieve the details of this fragment expression. |
| static Optional<FragmentInfo> getFragmentInfo(expr_op_iterator Start, |
| expr_op_iterator End); |
| |
| /// Retrieve the details of this fragment expression. |
| Optional<FragmentInfo> getFragmentInfo() const { |
| return getFragmentInfo(expr_op_begin(), expr_op_end()); |
| } |
| |
| /// Return whether this is a piece of an aggregate variable. |
| bool isFragment() const { return getFragmentInfo().hasValue(); } |
| |
| /// Append \p Ops with operations to apply the \p Offset. |
| static void appendOffset(SmallVectorImpl<uint64_t> &Ops, int64_t Offset); |
| |
| /// If this is a constant offset, extract it. If there is no expression, |
| /// return true with an offset of zero. |
| bool extractIfOffset(int64_t &Offset) const; |
| |
| /// Checks if the last 4 elements of the expression are DW_OP_constu <DWARF |
| /// Address Space> DW_OP_swap DW_OP_xderef and extracts the <DWARF Address |
| /// Space>. |
| static const DIExpression *extractAddressClass(const |