#define LLVM_LIB_CODEGEN_ASMPRINTER_DIE_H
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
#include "llvm/Support/Dwarf.h"
///
void Emit(const AsmPrinter *AP) const;
-#ifndef NDEBUG
void print(raw_ostream &O);
void dump();
-#endif
};
//===--------------------------------------------------------------------===//
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
: sizeof(int32_t);
}
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
return 8;
}
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
public:
enum Type {
isNone,
- isInteger,
- isString,
- isExpr,
- isLabel,
- isDelta,
- isEntry,
- isTypeSignature,
- isBlock,
- isLoc,
- isLocList,
+#define HANDLE_DIEVALUE(T) is##T,
+#include "llvm/CodeGen/DIEValue.def"
};
private:
/// Ty - Type of data stored in the value.
///
- Type Ty;
+ Type Ty = isNone;
+ dwarf::Attribute Attribute = (dwarf::Attribute)0;
+ dwarf::Form Form = (dwarf::Form)0;
- AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel, DIEDelta *,
- DIEEntry, DIETypeSignature, DIEBlock *, DIELoc *,
- DIELocList> Val;
- static_assert(sizeof(Val) == sizeof(uint64_t),
- "Only small values should be allocated locally");
+ /// Storage for the value.
+ ///
+ /// All values that aren't standard layout (or are larger than 8 bytes)
+ /// should be stored by reference instead of by value.
+ typedef AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel,
+ DIEDelta *, DIEEntry, DIETypeSignature,
+ DIEBlock *, DIELoc *, DIELocList> ValTy;
+ static_assert(sizeof(ValTy) <= sizeof(uint64_t) ||
+ sizeof(ValTy) <= sizeof(void *),
+ "Expected all large types to be stored via pointer");
+
+ /// Underlying stored value.
+ ValTy Val;
+
+ template <class T> void construct(T V) {
+ static_assert(std::is_standard_layout<T>::value ||
+ std::is_pointer<T>::value,
+ "Expected standard layout or pointer");
+ new (reinterpret_cast<void *>(Val.buffer)) T(V);
+ }
-public:
- DIEValue() : Ty(isNone) {}
- DIEValue(const DIEValue &X) = default;
- DIEValue &operator=(const DIEValue &X) = default;
+ template <class T> T *get() { return reinterpret_cast<T *>(Val.buffer); }
+ template <class T> const T *get() const {
+ return reinterpret_cast<const T *>(Val.buffer);
+ }
+ template <class T> void destruct() { get<T>()->~T(); }
- explicit operator bool() const { return Ty; }
+ /// Destroy the underlying value.
+ ///
+ /// This should get optimized down to a no-op. We could skip it if we could
+ /// add a static assert on \a std::is_trivially_copyable(), but we currently
+ /// support versions of GCC that don't understand that.
+ void destroyVal() {
+ switch (Ty) {
+ case isNone:
+ return;
+#define HANDLE_DIEVALUE_SMALL(T) \
+ case is##T: \
+ destruct<DIE##T>();
+ return;
+#define HANDLE_DIEVALUE_LARGE(T) \
+ case is##T: \
+ destruct<const DIE##T *>();
+ return;
+#include "llvm/CodeGen/DIEValue.def"
+ }
+ }
+
+ /// Copy the underlying value.
+ ///
+ /// This should get optimized down to a simple copy. We need to actually
+ /// construct the value, rather than calling memcpy, to satisfy strict
+ /// aliasing rules.
+ void copyVal(const DIEValue &X) {
+ switch (Ty) {
+ case isNone:
+ return;
+#define HANDLE_DIEVALUE_SMALL(T) \
+ case is##T: \
+ construct<DIE##T>(*X.get<DIE##T>()); \
+ return;
+#define HANDLE_DIEVALUE_LARGE(T) \
+ case is##T: \
+ construct<const DIE##T *>(*X.get<const DIE##T *>()); \
+ return;
+#include "llvm/CodeGen/DIEValue.def"
+ }
+ }
+
+public:
+ DIEValue() = default;
+ DIEValue(const DIEValue &X) : Ty(X.Ty), Attribute(X.Attribute), Form(X.Form) {
+ copyVal(X);
+ }
+ DIEValue &operator=(const DIEValue &X) {
+ destroyVal();
+ Ty = X.Ty;
+ Attribute = X.Attribute;
+ Form = X.Form;
+ copyVal(X);
+ return *this;
+ }
+ ~DIEValue() { destroyVal(); }
-#define CONSTRUCT_FROM_SMALL(Kind) \
- DIEValue(const DIE##Kind &V) : Ty(is##Kind) { \
- static_assert(std::is_trivially_copyable<DIE##Kind>::value, \
- "Expected trivial type"); \
- new (reinterpret_cast<void *>(Val.buffer)) DIE##Kind(V); \
+#define HANDLE_DIEVALUE_SMALL(T) \
+ DIEValue(dwarf::Attribute Attribute, dwarf::Form Form, const DIE##T &V) \
+ : Ty(is##T), Attribute(Attribute), Form(Form) { \
+ construct<DIE##T>(V); \
}
-#define CONSTRUCT_FROM_LARGE(Kind) \
- DIEValue(const DIE##Kind *V) : Ty(is##Kind) { \
+#define HANDLE_DIEVALUE_LARGE(T) \
+ DIEValue(dwarf::Attribute Attribute, dwarf::Form Form, const DIE##T *V) \
+ : Ty(is##T), Attribute(Attribute), Form(Form) { \
assert(V && "Expected valid value"); \
- *reinterpret_cast<const DIE##Kind **>(Val.buffer) = V; \
+ construct<const DIE##T *>(V); \
}
- CONSTRUCT_FROM_SMALL(Integer)
- CONSTRUCT_FROM_SMALL(Expr)
- CONSTRUCT_FROM_SMALL(Label)
- CONSTRUCT_FROM_SMALL(Entry)
- CONSTRUCT_FROM_SMALL(TypeSignature)
- CONSTRUCT_FROM_SMALL(LocList)
- CONSTRUCT_FROM_SMALL(String)
- CONSTRUCT_FROM_LARGE(Delta)
- CONSTRUCT_FROM_LARGE(Block)
- CONSTRUCT_FROM_LARGE(Loc)
-#undef CONSTRUCT_FROM_SMALL
-#undef CONSTRUCT_FROM_LARGE
+#include "llvm/CodeGen/DIEValue.def"
// Accessors
Type getType() const { return Ty; }
+ dwarf::Attribute getAttribute() const { return Attribute; }
+ dwarf::Form getForm() const { return Form; }
+ explicit operator bool() const { return Ty; }
-#define GET_VALUE_REF_SMALL(Kind) \
- const DIE##Kind &getDIE##Kind() const { \
- assert(getType() == is##Kind && "Expected " #Kind); \
- return *reinterpret_cast<const DIE##Kind *>(Val.buffer); \
+#define HANDLE_DIEVALUE_SMALL(T) \
+ const DIE##T &getDIE##T() const { \
+ assert(getType() == is##T && "Expected " #T); \
+ return *get<DIE##T>(); \
}
-#define GET_VALUE_REF_LARGE(Kind) \
- const DIE##Kind &getDIE##Kind() const { \
- assert(getType() == is##Kind && "Expected " #Kind); \
- return **reinterpret_cast<const DIE##Kind *const *>(Val.buffer); \
+#define HANDLE_DIEVALUE_LARGE(T) \
+ const DIE##T &getDIE##T() const { \
+ assert(getType() == is##T && "Expected " #T); \
+ return **get<const DIE##T *>(); \
}
- GET_VALUE_REF_SMALL(Integer)
- GET_VALUE_REF_SMALL(Expr)
- GET_VALUE_REF_SMALL(Label)
- GET_VALUE_REF_SMALL(Entry)
- GET_VALUE_REF_SMALL(TypeSignature)
- GET_VALUE_REF_SMALL(LocList)
- GET_VALUE_REF_SMALL(String)
- GET_VALUE_REF_LARGE(Delta)
- GET_VALUE_REF_LARGE(Block)
- GET_VALUE_REF_LARGE(Loc)
-#undef GET_VALUE_REF_SMALL
-#undef GET_VALUE_REF_LARGE
+#include "llvm/CodeGen/DIEValue.def"
/// EmitValue - Emit value via the Dwarf writer.
///
- void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
+ void EmitValue(const AsmPrinter *AP) const;
/// SizeOf - Return the size of a value in bytes.
///
- unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
+ unsigned SizeOf(const AsmPrinter *AP) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
void dump() const;
-#endif
+};
+
+struct IntrusiveBackListNode {
+ PointerIntPair<IntrusiveBackListNode *, 1> Next;
+ IntrusiveBackListNode() : Next(this, true) {}
+
+ IntrusiveBackListNode *getNext() const {
+ return Next.getInt() ? nullptr : Next.getPointer();
+ }
+};
+
+struct IntrusiveBackListBase {
+ typedef IntrusiveBackListNode Node;
+ Node *Last = nullptr;
+
+ bool empty() const { return !Last; }
+ void push_back(Node &N) {
+ assert(N.Next.getPointer() == &N && "Expected unlinked node");
+ assert(N.Next.getInt() == true && "Expected unlinked node");
+
+ if (Last) {
+ N.Next = Last->Next;
+ Last->Next.setPointerAndInt(&N, false);
+ }
+ Last = &N;
+ }
+};
+
+template <class T> class IntrusiveBackList : IntrusiveBackListBase {
+public:
+ using IntrusiveBackListBase::empty;
+ void push_back(T &N) { IntrusiveBackListBase::push_back(N); }
+ T &back() { return *static_cast<T *>(Last); }
+ const T &back() const { return *static_cast<T *>(Last); }
+
+ class const_iterator;
+ class iterator
+ : public iterator_facade_base<iterator, std::forward_iterator_tag, T> {
+ friend class const_iterator;
+ Node *N = nullptr;
+
+ public:
+ iterator() = default;
+ explicit iterator(T *N) : N(N) {}
+
+ iterator &operator++() {
+ N = N->getNext();
+ return *this;
+ }
+
+ explicit operator bool() const { return N; }
+ T &operator*() const { return *static_cast<T *>(N); }
+
+ bool operator==(const iterator &X) const { return N == X.N; }
+ bool operator!=(const iterator &X) const { return N != X.N; }
+ };
+
+ class const_iterator
+ : public iterator_facade_base<const_iterator, std::forward_iterator_tag,
+ const T> {
+ const Node *N = nullptr;
+
+ public:
+ const_iterator() = default;
+ // Placate MSVC by explicitly scoping 'iterator'.
+ const_iterator(typename IntrusiveBackList<T>::iterator X) : N(X.N) {}
+ explicit const_iterator(const T *N) : N(N) {}
+
+ const_iterator &operator++() {
+ N = N->getNext();
+ return *this;
+ }
+
+ explicit operator bool() const { return N; }
+ const T &operator*() const { return *static_cast<const T *>(N); }
+
+ bool operator==(const const_iterator &X) const { return N == X.N; }
+ bool operator!=(const const_iterator &X) const { return N != X.N; }
+ };
+
+ iterator begin() {
+ return Last ? iterator(static_cast<T *>(Last->Next.getPointer())) : end();
+ }
+ const_iterator begin() const {
+ return const_cast<IntrusiveBackList *>(this)->begin();
+ }
+ iterator end() { return iterator(); }
+ const_iterator end() const { return const_iterator(); }
+
+ static iterator toIterator(T &N) { return iterator(&N); }
+ static const_iterator toIterator(const T &N) { return const_iterator(&N); }
+};
+
+/// A list of DIE values.
+///
+/// This is a singly-linked list, but instead of reversing the order of
+/// insertion, we keep a pointer to the back of the list so we can push in
+/// order.
+///
+/// There are two main reasons to choose a linked list over a customized
+/// vector-like data structure.
+///
+/// 1. For teardown efficiency, we want DIEs to be BumpPtrAllocated. Using a
+/// linked list here makes this way easier to accomplish.
+/// 2. Carrying an extra pointer per \a DIEValue isn't expensive. 45% of DIEs
+/// have 2 or fewer values, and 90% have 5 or fewer. A vector would be
+/// over-allocated by 50% on average anyway, the same cost as the
+/// linked-list node.
+class DIEValueList {
+ struct Node : IntrusiveBackListNode {
+ DIEValue V;
+ explicit Node(DIEValue V) : V(V) {}
+ };
+
+ typedef IntrusiveBackList<Node> ListTy;
+ ListTy List;
+
+public:
+ class const_value_iterator;
+ class value_iterator
+ : public iterator_adaptor_base<value_iterator, ListTy::iterator,
+ std::forward_iterator_tag, DIEValue> {
+ friend class const_value_iterator;
+ typedef iterator_adaptor_base<value_iterator, ListTy::iterator,
+ std::forward_iterator_tag,
+ DIEValue> iterator_adaptor;
+
+ public:
+ value_iterator() = default;
+ explicit value_iterator(ListTy::iterator X) : iterator_adaptor(X) {}
+
+ explicit operator bool() const { return bool(wrapped()); }
+ DIEValue &operator*() const { return wrapped()->V; }
+ };
+
+ class const_value_iterator : public iterator_adaptor_base<
+ const_value_iterator, ListTy::const_iterator,
+ std::forward_iterator_tag, const DIEValue> {
+ typedef iterator_adaptor_base<const_value_iterator, ListTy::const_iterator,
+ std::forward_iterator_tag,
+ const DIEValue> iterator_adaptor;
+
+ public:
+ const_value_iterator() = default;
+ const_value_iterator(DIEValueList::value_iterator X)
+ : iterator_adaptor(X.wrapped()) {}
+ explicit const_value_iterator(ListTy::const_iterator X)
+ : iterator_adaptor(X) {}
+
+ explicit operator bool() const { return bool(wrapped()); }
+ const DIEValue &operator*() const { return wrapped()->V; }
+ };
+
+ typedef iterator_range<value_iterator> value_range;
+ typedef iterator_range<const_value_iterator> const_value_range;
+
+ value_iterator addValue(BumpPtrAllocator &Alloc, DIEValue V) {
+ List.push_back(*new (Alloc) Node(V));
+ return value_iterator(ListTy::toIterator(List.back()));
+ }
+ template <class T>
+ value_iterator addValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute,
+ dwarf::Form Form, T &&Value) {
+ return addValue(Alloc, DIEValue(Attribute, Form, std::forward<T>(Value)));
+ }
+
+ value_range values() {
+ return llvm::make_range(value_iterator(List.begin()),
+ value_iterator(List.end()));
+ }
+ const_value_range values() const {
+ return llvm::make_range(const_value_iterator(List.begin()),
+ const_value_iterator(List.end()));
+ }
};
//===--------------------------------------------------------------------===//
/// DIE - A structured debug information entry. Has an abbreviation which
/// describes its organization.
-class DIE {
-protected:
+class DIE : IntrusiveBackListNode, public DIEValueList {
+ friend class IntrusiveBackList<DIE>;
+
/// Offset - Offset in debug info section.
///
unsigned Offset;
///
unsigned Size;
- /// Abbrev - Buffer for constructing abbreviation.
- ///
- DIEAbbrev Abbrev;
+ unsigned AbbrevNumber = ~0u;
- /// Children DIEs.
+ /// Tag - Dwarf tag code.
///
- // This can't be a vector<DIE> because pointer validity is requirent for the
- // Parent pointer and DIEEntry.
- // It can't be a list<DIE> because some clients need pointer validity before
- // the object has been added to any child list
- // (eg: DwarfUnit::constructVariableDIE). These aren't insurmountable, but may
- // be more convoluted than beneficial.
- std::vector<std::unique_ptr<DIE>> Children;
+ dwarf::Tag Tag = (dwarf::Tag)0;
- DIE *Parent;
+ /// Children DIEs.
+ IntrusiveBackList<DIE> Children;
- /// Attribute values.
- ///
- SmallVector<DIEValue, 12> Values;
+ DIE *Parent = nullptr;
-protected:
- DIE()
- : Offset(0), Size(0), Abbrev((dwarf::Tag)0, dwarf::DW_CHILDREN_no),
- Parent(nullptr) {}
+ DIE() = delete;
+ explicit DIE(dwarf::Tag Tag) : Offset(0), Size(0), Tag(Tag) {}
public:
- explicit DIE(dwarf::Tag Tag)
- : Offset(0), Size(0), Abbrev((dwarf::Tag)Tag, dwarf::DW_CHILDREN_no),
- Parent(nullptr) {}
+ static DIE *get(BumpPtrAllocator &Alloc, dwarf::Tag Tag) {
+ return new (Alloc) DIE(Tag);
+ }
// Accessors.
- DIEAbbrev &getAbbrev() { return Abbrev; }
- const DIEAbbrev &getAbbrev() const { return Abbrev; }
- unsigned getAbbrevNumber() const { return Abbrev.getNumber(); }
- dwarf::Tag getTag() const { return Abbrev.getTag(); }
+ unsigned getAbbrevNumber() const { return AbbrevNumber; }
+ dwarf::Tag getTag() const { return Tag; }
unsigned getOffset() const { return Offset; }
unsigned getSize() const { return Size; }
- const std::vector<std::unique_ptr<DIE>> &getChildren() const {
- return Children;
+ bool hasChildren() const { return !Children.empty(); }
+
+ typedef IntrusiveBackList<DIE>::iterator child_iterator;
+ typedef IntrusiveBackList<DIE>::const_iterator const_child_iterator;
+ typedef iterator_range<child_iterator> child_range;
+ typedef iterator_range<const_child_iterator> const_child_range;
+
+ child_range children() {
+ return llvm::make_range(Children.begin(), Children.end());
}
- const SmallVectorImpl<DIEValue> &getValues() const { return Values; }
- void setValue(unsigned I, DIEValue New) {
- assert(I < Values.size());
- Values[I] = New;
+ const_child_range children() const {
+ return llvm::make_range(Children.begin(), Children.end());
}
+
DIE *getParent() const { return Parent; }
+
+ /// Generate the abbreviation for this DIE.
+ ///
+ /// Calculate the abbreviation for this, which should be uniqued and
+ /// eventually used to call \a setAbbrevNumber().
+ DIEAbbrev generateAbbrev() const;
+
+ /// Set the abbreviation number for this DIE.
+ void setAbbrevNumber(unsigned I) { AbbrevNumber = I; }
+
/// Climb up the parent chain to get the compile or type unit DIE this DIE
/// belongs to.
const DIE *getUnit() const;
void setOffset(unsigned O) { Offset = O; }
void setSize(unsigned S) { Size = S; }
- /// addValue - Add a value and attributes to a DIE.
- ///
- void addValue(dwarf::Attribute Attribute, dwarf::Form Form, DIEValue Value) {
- Abbrev.AddAttribute(Attribute, Form);
- Values.push_back(Value);
- }
-
- /// addChild - Add a child to the DIE.
- ///
- void addChild(std::unique_ptr<DIE> Child) {
- assert(!Child->getParent());
- Abbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
+ /// Add a child to the DIE.
+ DIE &addChild(DIE *Child) {
+ assert(!Child->getParent() && "Child should be orphaned");
Child->Parent = this;
- Children.push_back(std::move(Child));
+ Children.push_back(*Child);
+ return Children.back();
}
/// Find a value in the DIE with the attribute given.
/// gives \a DIEValue::isNone) if no such attribute exists.
DIEValue findAttribute(dwarf::Attribute Attribute) const;
-#ifndef NDEBUG
void print(raw_ostream &O, unsigned IndentCount = 0) const;
void dump();
-#endif
};
//===--------------------------------------------------------------------===//
/// DIELoc - Represents an expression location.
//
-class DIELoc : public DIE {
+class DIELoc : public DIEValueList {
mutable unsigned Size; // Size in bytes excluding size header.
public:
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
//===--------------------------------------------------------------------===//
/// DIEBlock - Represents a block of values.
//
-class DIEBlock : public DIE {
+class DIEBlock : public DIEValueList {
mutable unsigned Size; // Size in bytes excluding size header.
public:
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
-#ifndef NDEBUG
void print(raw_ostream &O) const;
-#endif
};
} // end llvm namespace