blob: 8448b67bcb401738e00bb748b84ab03b78809ed5 [file] [log] [blame]
//===- 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; }
bool isPure() const { return getSPFlags() & SPFlagPure; }
bool isElemental() const { return getSPFlags() & SPFlagElemental; }
bool isRecursive() const { return getSPFlags() & SPFlagRecursive; }
/// 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 DIExpression *Expr,
unsigned &AddrClass);
/// Constants for DIExpression::prepend.
enum { NoDeref = false, WithDeref = true, WithStackValue = true };
/// Prepend \p DIExpr with a deref and offset operation and optionally turn it
/// into a stack value.
static DIExpression *prepend(const DIExpression *Expr, bool DerefBefore,
int64_t Offset = 0, bool DerefAfter = false,
bool StackValue = false);
/// Prepend \p DIExpr with the given opcodes and optionally turn it into a
/// stack value.
static DIExpression *prependOpcodes(const DIExpression *Expr,
SmallVectorImpl<uint64_t> &Ops,
bool StackValue = false);
/// Append the opcodes \p Ops to \p DIExpr. Unlike \ref appendToStack, the
/// returned expression is a stack value only if \p DIExpr is a stack value.
/// If \p DIExpr describes a fragment, the returned expression will describe
/// the same fragment.
static DIExpression *append(const DIExpression *Expr, ArrayRef<uint64_t> Ops);
/// Convert \p DIExpr into a stack value if it isn't one already by appending
/// DW_OP_deref if needed, and appending \p Ops to the resulting expression.
/// If \p DIExpr describes a fragment, the returned expression will describe
/// the same fragment.
static DIExpression *appendToStack(const DIExpression *Expr,
ArrayRef<uint64_t> Ops);
/// Create a DIExpression to describe one part of an aggregate variable that
/// is fragmented across multiple Values. The DW_OP_LLVM_fragment operation
/// will be appended to the elements of \c Expr. If \c Expr already contains
/// a \c DW_OP_LLVM_fragment \c OffsetInBits is interpreted as an offset
/// into the existing fragment.
///
/// \param OffsetInBits Offset of the piece in bits.
/// \param SizeInBits Size of the piece in bits.
/// \return Creating a fragment expression may fail if \c Expr
/// contains arithmetic operations that would be truncated.
static Optional<DIExpression *>
createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits,
unsigned SizeInBits);
/// Determine the relative position of the fragments described by this
/// DIExpression and \p Other.
/// Returns -1 if this is entirely before Other, 0 if this and Other overlap,
/// 1 if this is entirely after Other.
int fragmentCmp(const DIExpression *Other) const {
auto Fragment1 = *getFragmentInfo();
auto Fragment2 = *Other->getFragmentInfo();
unsigned l1 = Fragment1.OffsetInBits;
unsigned l2 = Fragment2.OffsetInBits;
unsigned r1 = l1 + Fragment1.SizeInBits;
unsigned r2 = l2 + Fragment2.SizeInBits;
if (r1 <= l2)
return -1;
else if (r2 <= l1)
return 1;
else
return 0;
}
/// Check if fragments overlap between this DIExpression and \p Other.
bool fragmentsOverlap(const DIExpression *Other) const {
if (!isFragment() || !Other->isFragment())
return true;
return fragmentCmp(Other) == 0;
}
};
/// Global variables.
///
/// TODO: Remove DisplayName. It's always equal to Name.
class DIGlobalVariable : public DIVariable {
friend class LLVMContextImpl;
friend class MDNode;
bool IsLocalToUnit;
bool IsDefinition;
DIGlobalVariable(LLVMContext &C, StorageType Storage, unsigned Line,
bool IsLocalToUnit, bool IsDefinition, uint32_t AlignInBits,
ArrayRef<Metadata *> Ops)
: DIVariable(C, DIGlobalVariableKind, Storage, Line, Ops, AlignInBits),
IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition) {}
~DIGlobalVariable() = default;
static DIGlobalVariable *
getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name,
StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type,
bool IsLocalToUnit, bool IsDefinition,
DIDerivedType *StaticDataMemberDeclaration, MDTuple *TemplateParams,
uint32_t AlignInBits, StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, LinkageName), File, Line, Type,
IsLocalToUnit, IsDefinition, StaticDataMemberDeclaration,
cast_or_null<Metadata>(TemplateParams), AlignInBits, Storage,
ShouldCreate);
}
static DIGlobalVariable *
getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name,
MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type,
bool IsLocalToUnit, bool IsDefinition,
Metadata *StaticDataMemberDeclaration, Metadata *TemplateParams,
uint32_t AlignInBits, StorageType Storage, bool ShouldCreate = true);
TempDIGlobalVariable cloneImpl() const {
return getTemporary(getContext(), getScope(), getName(), getLinkageName(),
getFile(), getLine(), getType(), isLocalToUnit(),
isDefinition(), getStaticDataMemberDeclaration(),
getTemplateParams(), getAlignInBits());
}
public:
DEFINE_MDNODE_GET(DIGlobalVariable,
(DIScope * Scope, StringRef Name, StringRef LinkageName,
DIFile *File, unsigned Line, DITypeRef Type,
bool IsLocalToUnit, bool IsDefinition,
DIDerivedType *StaticDataMemberDeclaration,
MDTuple *TemplateParams, uint32_t AlignInBits),
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit,
IsDefinition, StaticDataMemberDeclaration, TemplateParams,
AlignInBits))
DEFINE_MDNODE_GET(DIGlobalVariable,
(Metadata * Scope, MDString *Name, MDString *LinkageName,
Metadata *File, unsigned Line, Metadata *Type,
bool IsLocalToUnit, bool IsDefinition,
Metadata *StaticDataMemberDeclaration,
Metadata *TemplateParams, uint32_t AlignInBits),
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit,
IsDefinition, StaticDataMemberDeclaration, TemplateParams,
AlignInBits))
TempDIGlobalVariable clone() const { return cloneImpl(); }
bool isLocalToUnit() const { return IsLocalToUnit; }
bool isDefinition() const { return IsDefinition; }
StringRef getDisplayName() const { return getStringOperand(4); }
StringRef getLinkageName() const { return getStringOperand(5); }
DIDerivedType *getStaticDataMemberDeclaration() const {
return cast_or_null<DIDerivedType>(getRawStaticDataMemberDeclaration());
}
MDString *getRawLinkageName() const { return getOperandAs<MDString>(5); }
Metadata *getRawStaticDataMemberDeclaration() const { return getOperand(6); }
Metadata *getRawTemplateParams() const { return getOperand(7); }
MDTuple *getTemplateParams() const { return getOperandAs<MDTuple>(7); }
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIGlobalVariableKind;
}
};
/// Local variable.
///
/// TODO: Split up flags.
class DILocalVariable : public DIVariable {
friend class LLVMContextImpl;
friend class MDNode;
unsigned Arg : 16;
DIFlags Flags;
DILocalVariable(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Arg, DIFlags Flags, uint32_t AlignInBits,
ArrayRef<Metadata *> Ops)
: DIVariable(C, DILocalVariableKind, Storage, Line, Ops, AlignInBits),
Arg(Arg), Flags(Flags) {
assert(Arg < (1 << 16) && "DILocalVariable: Arg out of range");
}
~DILocalVariable() = default;
static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope,
StringRef Name, DIFile *File, unsigned Line,
DITypeRef Type, unsigned Arg, DIFlags Flags,
uint32_t AlignInBits, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File,
Line, Type, Arg, Flags, AlignInBits, Storage, ShouldCreate);
}
static DILocalVariable *getImpl(LLVMContext &Context, Metadata *Scope,
MDString *Name, Metadata *File, unsigned Line,
Metadata *Type, unsigned Arg, DIFlags Flags,
uint32_t AlignInBits, StorageType Storage,
bool ShouldCreate = true);
TempDILocalVariable cloneImpl() const {
return getTemporary(getContext(), getScope(), getName(), getFile(),
getLine(), getType(), getArg(), getFlags(),
getAlignInBits());
}
public:
DEFINE_MDNODE_GET(DILocalVariable,
(DILocalScope * Scope, StringRef Name, DIFile *File,
unsigned Line, DITypeRef Type, unsigned Arg,
DIFlags Flags, uint32_t AlignInBits),
(Scope, Name, File, Line, Type, Arg, Flags, AlignInBits))
DEFINE_MDNODE_GET(DILocalVariable,
(Metadata * Scope, MDString *Name, Metadata *File,
unsigned Line, Metadata *Type, unsigned Arg,
DIFlags Flags, uint32_t AlignInBits),
(Scope, Name, File, Line, Type, Arg, Flags, AlignInBits))
TempDILocalVariable clone() const { return cloneImpl(); }
/// Get the local scope for this variable.
///
/// Variables must be defined in a local scope.
DILocalScope *getScope() const {
return cast<DILocalScope>(DIVariable::getScope());
}
bool isParameter() const { return Arg; }
unsigned getArg() const { return Arg; }
DIFlags getFlags() const { return Flags; }
bool isArtificial() const { return getFlags() & FlagArtificial; }
bool isObjectPointer() const { return getFlags() & FlagObjectPointer; }
/// Check that a location is valid for this variable.
///
/// Check that \c DL exists, is in the same subprogram, and has the same
/// inlined-at location as \c this. (Otherwise, it's not a valid attachment
/// to a \a DbgInfoIntrinsic.)
bool isValidLocationForIntrinsic(const DILocation *DL) const {
return DL && getScope()->getSubprogram() == DL->getScope()->getSubprogram();
}
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DILocalVariableKind;
}
};
/// Label.
///
class DILabel : public DINode {
friend class LLVMContextImpl;
friend class MDNode;
unsigned Line;
DILabel(LLVMContext &C, StorageType Storage, unsigned Line,
ArrayRef<Metadata *> Ops)
: DINode(C, DILabelKind, Storage, dwarf::DW_TAG_label, Ops), Line(Line) {}
~DILabel() = default;
static DILabel *getImpl(LLVMContext &Context, DIScope *Scope,
StringRef Name, DIFile *File, unsigned Line,
StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File,
Line, Storage, ShouldCreate);
}
static DILabel *getImpl(LLVMContext &Context, Metadata *Scope,
MDString *Name, Metadata *File, unsigned Line,
StorageType Storage,
bool ShouldCreate = true);
TempDILabel cloneImpl() const {
return getTemporary(getContext(), getScope(), getName(), getFile(),
getLine());
}
public:
DEFINE_MDNODE_GET(DILabel,
(DILocalScope * Scope, StringRef Name, DIFile *File,
unsigned Line),
(Scope, Name, File, Line))
DEFINE_MDNODE_GET(DILabel,
(Metadata * Scope, MDString *Name, Metadata *File,
unsigned Line),
(Scope, Name, File, Line))
TempDILabel clone() const { return cloneImpl(); }
/// Get the local scope for this label.
///
/// Labels must be defined in a local scope.
DILocalScope *getScope() const {
return cast_or_null<DILocalScope>(getRawScope());
}
unsigned getLine() const { return Line; }
StringRef getName() const { return getStringOperand(1); }
DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); }
Metadata *getRawScope() const { return getOperand(0); }
MDString *getRawName() const { return getOperandAs<MDString>(1); }
Metadata *getRawFile() const { return getOperand(2); }
/// Check that a location is valid for this label.
///
/// Check that \c DL exists, is in the same subprogram, and has the same
/// inlined-at location as \c this. (Otherwise, it's not a valid attachment
/// to a \a DbgInfoIntrinsic.)
bool isValidLocationForIntrinsic(const DILocation *DL) const {
return DL && getScope()->getSubprogram() == DL->getScope()->getSubprogram();
}
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DILabelKind;
}
};
class DIObjCProperty : public DINode {
friend class LLVMContextImpl;
friend class MDNode;
unsigned Line;
unsigned Attributes;
DIObjCProperty(LLVMContext &C, StorageType Storage, unsigned Line,
unsigned Attributes, ArrayRef<Metadata *> Ops)
: DINode(C, DIObjCPropertyKind, Storage, dwarf::DW_TAG_APPLE_property,
Ops),
Line(Line), Attributes(Attributes) {}
~DIObjCProperty() = default;
static DIObjCProperty *
getImpl(LLVMContext &Context, StringRef Name, DIFile *File, unsigned Line,
StringRef GetterName, StringRef SetterName, unsigned Attributes,
DITypeRef Type, StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, getCanonicalMDString(Context, Name), File, Line,
getCanonicalMDString(Context, GetterName),
getCanonicalMDString(Context, SetterName), Attributes, Type,
Storage, ShouldCreate);
}
static DIObjCProperty *getImpl(LLVMContext &Context, MDString *Name,
Metadata *File, unsigned Line,
MDString *GetterName, MDString *SetterName,
unsigned Attributes, Metadata *Type,
StorageType Storage, bool ShouldCreate = true);
TempDIObjCProperty cloneImpl() const {
return getTemporary(getContext(), getName(), getFile(), getLine(),
getGetterName(), getSetterName(), getAttributes(),
getType());
}
public:
DEFINE_MDNODE_GET(DIObjCProperty,
(StringRef Name, DIFile *File, unsigned Line,
StringRef GetterName, StringRef SetterName,
unsigned Attributes, DITypeRef Type),
(Name, File, Line, GetterName, SetterName, Attributes,
Type))
DEFINE_MDNODE_GET(DIObjCProperty,
(MDString * Name, Metadata *File, unsigned Line,
MDString *GetterName, MDString *SetterName,
unsigned Attributes, Metadata *Type),
(Name, File, Line, GetterName, SetterName, Attributes,
Type))
TempDIObjCProperty clone() const { return cloneImpl(); }
unsigned getLine() const { return Line; }
unsigned getAttributes() const { return Attributes; }
StringRef getName() const { return getStringOperand(0); }
DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); }
StringRef getGetterName() const { return getStringOperand(2); }
StringRef getSetterName() const { return getStringOperand(3); }
DITypeRef getType() const { return DITypeRef(getRawType()); }
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;
}
MDString *getRawName() const { return getOperandAs<MDString>(0); }
Metadata *getRawFile() const { return getOperand(1); }
MDString *getRawGetterName() const { return getOperandAs<MDString>(2); }
MDString *getRawSetterName() const { return getOperandAs<MDString>(3); }
Metadata *getRawType() const { return getOperand(4); }
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIObjCPropertyKind;
}
};
/// An imported module (C++ using directive or similar).
class DIImportedEntity : public DINode {
friend class LLVMContextImpl;
friend class MDNode;
unsigned Line;
DIImportedEntity(LLVMContext &C, StorageType Storage, unsigned Tag,
unsigned Line, ArrayRef<Metadata *> Ops)
: DINode(C, DIImportedEntityKind, Storage, Tag, Ops), Line(Line) {}
~DIImportedEntity() = default;
static DIImportedEntity *getImpl(LLVMContext &Context, unsigned Tag,
DIScope *Scope, DINodeRef Entity,
DIFile *File, unsigned Line, StringRef Name,
StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, Tag, Scope, Entity, File, Line,
getCanonicalMDString(Context, Name), Storage, ShouldCreate);
}
static DIImportedEntity *getImpl(LLVMContext &Context, unsigned Tag,
Metadata *Scope, Metadata *Entity,
Metadata *File, unsigned Line,
MDString *Name, StorageType Storage,
bool ShouldCreate = true);
TempDIImportedEntity cloneImpl() const {
return getTemporary(getContext(), getTag(), getScope(), getEntity(),
getFile(), getLine(), getName());
}
public:
DEFINE_MDNODE_GET(DIImportedEntity,
(unsigned Tag, DIScope *Scope, DINodeRef Entity,
DIFile *File, unsigned Line, StringRef Name = ""),
(Tag, Scope, Entity, File, Line, Name))
DEFINE_MDNODE_GET(DIImportedEntity,
(unsigned Tag, Metadata *Scope, Metadata *Entity,
Metadata *File, unsigned Line, MDString *Name),
(Tag, Scope, Entity, File, Line, Name))
TempDIImportedEntity clone() const { return cloneImpl(); }
unsigned getLine() const { return Line; }
DIScope *getScope() const { return cast_or_null<DIScope>(getRawScope()); }
DINodeRef getEntity() const { return DINodeRef(getRawEntity()); }
StringRef getName() const { return getStringOperand(2); }
DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); }
Metadata *getRawScope() const { return getOperand(0); }
Metadata *getRawEntity() const { return getOperand(1); }
MDString *getRawName() const { return getOperandAs<MDString>(2); }
Metadata *getRawFile() const { return getOperand(3); }
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIImportedEntityKind;
}
};
/// A pair of DIGlobalVariable and DIExpression.
class DIGlobalVariableExpression : public MDNode {
friend class LLVMContextImpl;
friend class MDNode;
DIGlobalVariableExpression(LLVMContext &C, StorageType Storage,
ArrayRef<Metadata *> Ops)
: MDNode(C, DIGlobalVariableExpressionKind, Storage, Ops) {}
~DIGlobalVariableExpression() = default;
static DIGlobalVariableExpression *
getImpl(LLVMContext &Context, Metadata *Variable, Metadata *Expression,
StorageType Storage, bool ShouldCreate = true);
TempDIGlobalVariableExpression cloneImpl() const {
return getTemporary(getContext(), getVariable(), getExpression());
}
public:
DEFINE_MDNODE_GET(DIGlobalVariableExpression,
(Metadata * Variable, Metadata *Expression),
(Variable, Expression))
TempDIGlobalVariableExpression clone() const { return cloneImpl(); }
Metadata *getRawVariable() const { return getOperand(0); }
DIGlobalVariable *getVariable() const {
return cast_or_null<DIGlobalVariable>(getRawVariable());
}
Metadata *getRawExpression() const { return getOperand(1); }
DIExpression *getExpression() const {
return cast<DIExpression>(getRawExpression());
}
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIGlobalVariableExpressionKind;
}
};
/// Macro Info DWARF-like metadata node.
///
/// A metadata node with a DWARF macro info (i.e., a constant named
/// \c DW_MACINFO_*, defined in llvm/BinaryFormat/Dwarf.h). Called \a
/// DIMacroNode
/// because it's potentially used for non-DWARF output.
class DIMacroNode : public MDNode {
friend class LLVMContextImpl;
friend class MDNode;
protected:
DIMacroNode(LLVMContext &C, unsigned ID, StorageType Storage, unsigned MIType,
ArrayRef<Metadata *> Ops1, ArrayRef<Metadata *> Ops2 = None)
: MDNode(C, ID, Storage, Ops1, Ops2) {
assert(MIType < 1u << 16);
SubclassData16 = MIType;
}
~DIMacroNode() = 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);
}
public:
unsigned getMacinfoType() const { return SubclassData16; }
static bool classof(const Metadata *MD) {
switch (MD->getMetadataID()) {
default:
return false;
case DIMacroKind:
case DIMacroFileKind:
return true;
}
}
};
class DIMacro : public DIMacroNode {
friend class LLVMContextImpl;
friend class MDNode;
unsigned Line;
DIMacro(LLVMContext &C, StorageType Storage, unsigned MIType, unsigned Line,
ArrayRef<Metadata *> Ops)
: DIMacroNode(C, DIMacroKind, Storage, MIType, Ops), Line(Line) {}
~DIMacro() = default;
static DIMacro *getImpl(LLVMContext &Context, unsigned MIType, unsigned Line,
StringRef Name, StringRef Value, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, MIType, Line, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, Value), Storage, ShouldCreate);
}
static DIMacro *getImpl(LLVMContext &Context, unsigned MIType, unsigned Line,
MDString *Name, MDString *Value, StorageType Storage,
bool ShouldCreate = true);
TempDIMacro cloneImpl() const {
return getTemporary(getContext(), getMacinfoType(), getLine(), getName(),
getValue());
}
public:
DEFINE_MDNODE_GET(DIMacro, (unsigned MIType, unsigned Line, StringRef Name,
StringRef Value = ""),
(MIType, Line, Name, Value))
DEFINE_MDNODE_GET(DIMacro, (unsigned MIType, unsigned Line, MDString *Name,
MDString *Value),
(MIType, Line, Name, Value))
TempDIMacro clone() const { return cloneImpl(); }
unsigned getLine() const { return Line; }
StringRef getName() const { return getStringOperand(0); }
StringRef getValue() const { return getStringOperand(1); }
MDString *getRawName() const { return getOperandAs<MDString>(0); }
MDString *getRawValue() const { return getOperandAs<MDString>(1); }
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIMacroKind;
}
};
class DIMacroFile : public DIMacroNode {
friend class LLVMContextImpl;
friend class MDNode;
unsigned Line;
DIMacroFile(LLVMContext &C, StorageType Storage, unsigned MIType,
unsigned Line, ArrayRef<Metadata *> Ops)
: DIMacroNode(C, DIMacroFileKind, Storage, MIType, Ops), Line(Line) {}
~DIMacroFile() = default;
static DIMacroFile *getImpl(LLVMContext &Context, unsigned MIType,
unsigned Line, DIFile *File,
DIMacroNodeArray Elements, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, MIType, Line, static_cast<Metadata *>(File),
Elements.get(), Storage, ShouldCreate);
}
static DIMacroFile *getImpl(LLVMContext &Context, unsigned MIType,
unsigned Line, Metadata *File, Metadata *Elements,
StorageType Storage, bool ShouldCreate = true);
TempDIMacroFile cloneImpl() const {
return getTemporary(getContext(), getMacinfoType(), getLine(), getFile(),
getElements());
}
public:
DEFINE_MDNODE_GET(DIMacroFile, (unsigned MIType, unsigned Line, DIFile *File,
DIMacroNodeArray Elements),
(MIType, Line, File, Elements))
DEFINE_MDNODE_GET(DIMacroFile, (unsigned MIType, unsigned Line,
Metadata *File, Metadata *Elements),
(MIType, Line, File, Elements))
TempDIMacroFile clone() const { return cloneImpl(); }
void replaceElements(DIMacroNodeArray Elements) {
#ifndef NDEBUG
for (DIMacroNode *Op : getElements())
assert(is_contained(Elements->operands(), Op) &&
"Lost a macro node during macro node list replacement");
#endif
replaceOperandWith(1, Elements.get());
}
unsigned getLine() const { return Line; }
DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); }
DIMacroNodeArray getElements() const {
return cast_or_null<MDTuple>(getRawElements());
}
Metadata *getRawFile() const { return getOperand(0); }
Metadata *getRawElements() const { return getOperand(1); }
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIMacroFileKind;
}
};
} // end namespace llvm
#undef DEFINE_MDNODE_GET_UNPACK_IMPL
#undef DEFINE_MDNODE_GET_UNPACK
#undef DEFINE_MDNODE_GET
#endif // LLVM_IR_DEBUGINFOMETADATA_H