Reapply "AsmPrinter: Change DIEValue to be stored by value"

This reverts commit r238350, effectively reapplying r238349 after fixing
(all?) the problems, all somehow related to how I was using
`AlignedArrayCharUnion<>` inside `DIEValue`:

  - MSVC can only handle `sizeof()` on types, not values.  Change the
    assert.
  - GCC doesn't know the `is_trivially_copyable` type trait.  Instead of
    asserting it, add destructors.
  - Call placement new even when constructing POD (i.e., the pointers).
  - Instead of copying the char buffer, copy the casted classes.

I've left in a couple of `static_assert`s that I think both MSVC and GCC
know how to handle.  If the bots disagree with me, I'll remove them.

  - Check that the constructed type is either standard layout or a
    pointer.  This protects against a programming error: we really want
    the "small" `DIEValue`s to be small and simple, so don't
    accidentally change them not to be.
  - Similarly, check that the size of the buffer is no bigger than a
    `uint64_t` or a pointer.  (I thought checking against
    `sizeof(uint64_t)` would be good enough, but Chandler suggested that
    pointers might sometimes be bigger than that in the context of
    sanitizers.)

I've also committed r238359 in the meantime, which introduces a
DIEValue.def to simplify dispatching between the various types (thanks
to a review comment by David Blaikie).  Without that, this commit would
be almost unintelligible.

Here's the original commit message:
--
Change `DIEValue` to be stored/passed/etc. by value, instead of
reference.  It's now a discriminated union, with a `Val` field storing
the actual type.  The classes that used to inherit from `DIEValue` no
longer do.  There are two categories of these:

  - Small values fit in a single pointer and are stored by value.
  - Large values require auxiliary storage, and are stored by reference.

The only non-mechanical change is to tools/dsymutil/DwarfLinker.cpp.  It
was relying on `DIEInteger`s being passed around by reference, so I
replaced that assumption with a `PatchLocation` type that stores a safe
reference to where the `DIEInteger` lives instead.

This commit causes a temporary regression in memory usage, since I've
left merging `DIEAbbrevData` into `DIEValue` for a follow-up commit.  I
measured an increase from 845 MB to 879 MB, around 3.9%.  The follow-up
drops it lower than the starting point, and I've only recently brought
the memory this low anyway, so I'm committing these changes separately
to keep them incremental.  (I also considered swapping the commits, but
the other one first would cause a lot more code churn.)

(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)
--

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238362 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith
2015-05-27 22:14:58 +00:00
parent 344593ce6c
commit 09fe4bf794
13 changed files with 577 additions and 547 deletions

View File

@@ -104,54 +104,14 @@ public:
#endif
};
//===--------------------------------------------------------------------===//
/// DIEValue - A debug information entry value. Some of these roughly correlate
/// to DWARF attribute classes.
///
class DIEValue {
public:
enum Type {
#define HANDLE_DIEVALUE(T) is##T,
#include "llvm/CodeGen/DIEValue.def"
};
private:
/// Ty - Type of data stored in the value.
///
Type Ty;
protected:
explicit DIEValue(Type T) : Ty(T) {}
~DIEValue() {}
public:
// Accessors
Type getType() const { return Ty; }
/// EmitValue - Emit value via the Dwarf writer.
///
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
/// SizeOf - Return the size of a value in bytes.
///
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void print(raw_ostream &O) const;
void dump() const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIEInteger - An integer value DIE.
///
class DIEInteger : public DIEValue {
friend DIEValue;
class DIEInteger {
uint64_t Integer;
public:
explicit DIEInteger(uint64_t I) : DIEValue(isInteger), Integer(I) {}
explicit DIEInteger(uint64_t I) : Integer(I) {}
/// BestForm - Choose the best form for integer.
///
@@ -178,120 +138,91 @@ public:
uint64_t getValue() const { return Integer; }
void setValue(uint64_t Val) { Integer = Val; }
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *I) { return I->getType() == isInteger; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIEExpr - An expression DIE.
//
class DIEExpr : public DIEValue {
friend class DIEValue;
class DIEExpr {
const MCExpr *Expr;
public:
explicit DIEExpr(const MCExpr *E) : DIEValue(isExpr), Expr(E) {}
explicit DIEExpr(const MCExpr *E) : Expr(E) {}
/// getValue - Get MCExpr.
///
const MCExpr *getValue() const { return Expr; }
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *E) { return E->getType() == isExpr; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIELabel - A label DIE.
//
class DIELabel : public DIEValue {
friend class DIEValue;
class DIELabel {
const MCSymbol *Label;
public:
explicit DIELabel(const MCSymbol *L) : DIEValue(isLabel), Label(L) {}
explicit DIELabel(const MCSymbol *L) : Label(L) {}
/// getValue - Get MCSymbol.
///
const MCSymbol *getValue() const { return Label; }
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *L) { return L->getType() == isLabel; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIEDelta - A simple label difference DIE.
///
class DIEDelta : public DIEValue {
friend class DIEValue;
class DIEDelta {
const MCSymbol *LabelHi;
const MCSymbol *LabelLo;
public:
DIEDelta(const MCSymbol *Hi, const MCSymbol *Lo)
: DIEValue(isDelta), LabelHi(Hi), LabelLo(Lo) {}
DIEDelta(const MCSymbol *Hi, const MCSymbol *Lo) : LabelHi(Hi), LabelLo(Lo) {}
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *D) { return D->getType() == isDelta; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIEString - A container for string values.
///
class DIEString : public DIEValue {
friend class DIEValue;
class DIEString {
DwarfStringPoolEntryRef S;
public:
DIEString(DwarfStringPoolEntryRef S) : DIEValue(isString), S(S) {}
DIEString(DwarfStringPoolEntryRef S) : S(S) {}
/// getString - Grab the string out of the object.
StringRef getString() const { return S.getString(); }
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *D) { return D->getType() == isString; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
@@ -300,60 +231,48 @@ private:
/// this class can also be used as a proxy for a debug information entry not
/// yet defined (ie. types.)
class DIE;
class DIEEntry : public DIEValue {
friend class DIEValue;
class DIEEntry {
DIE *Entry;
DIE &Entry;
DIEEntry() = delete;
public:
explicit DIEEntry(DIE &E) : DIEValue(isEntry), Entry(E) {
}
explicit DIEEntry(DIE &E) : Entry(&E) {}
DIE &getEntry() const { return Entry; }
DIE &getEntry() const { return *Entry; }
/// Returns size of a ref_addr entry.
static unsigned getRefAddrSize(const AsmPrinter *AP);
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *E) { return E->getType() == isEntry; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const {
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
return Form == dwarf::DW_FORM_ref_addr ? getRefAddrSize(AP)
: sizeof(int32_t);
}
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// \brief A signature reference to a type unit.
class DIETypeSignature : public DIEValue {
friend class DIEValue;
class DIETypeSignature {
const DwarfTypeUnit *Unit;
const DwarfTypeUnit &Unit;
DIETypeSignature() = delete;
public:
explicit DIETypeSignature(const DwarfTypeUnit &Unit)
: DIEValue(isTypeSignature), Unit(Unit) {}
explicit DIETypeSignature(const DwarfTypeUnit &Unit) : Unit(&Unit) {}
// \brief Implement isa/cast/dyncast.
static bool classof(const DIEValue *E) {
return E->getType() == isTypeSignature;
}
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const {
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
assert(Form == dwarf::DW_FORM_ref_sig8);
return 8;
}
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
@@ -361,27 +280,159 @@ private:
/// DIELocList - Represents a pointer to a location list in the debug_loc
/// section.
//
class DIELocList : public DIEValue {
friend class DIEValue;
class DIELocList {
// Index into the .debug_loc vector.
size_t Index;
public:
DIELocList(size_t I) : DIEValue(isLocList), Index(I) {}
DIELocList(size_t I) : Index(I) {}
/// getValue - Grab the current index out.
size_t getValue() const { return Index; }
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *E) { return E->getType() == isLocList; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIEValue - A debug information entry value. Some of these roughly correlate
/// to DWARF attribute classes.
///
class DIEBlock;
class DIELoc;
class DIEValue {
public:
enum Type {
isNone,
#define HANDLE_DIEVALUE(T) is##T,
#include "llvm/CodeGen/DIEValue.def"
};
private:
/// Ty - Type of data stored in the value.
///
Type Ty;
/// 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);
}
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(); }
/// 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() : Ty(isNone) {}
DIEValue(const DIEValue &X) : Ty(X.Ty) { copyVal(X); }
DIEValue &operator=(const DIEValue &X) {
destroyVal();
Ty = X.Ty;
copyVal(X);
return *this;
}
~DIEValue() { destroyVal(); }
#define HANDLE_DIEVALUE_SMALL(T) \
DIEValue(const DIE##T &V) : Ty(is##T) { construct<DIE##T>(V); }
#define HANDLE_DIEVALUE_LARGE(T) \
DIEValue(const DIE##T *V) : Ty(is##T) { \
assert(V && "Expected valid value"); \
construct<const DIE##T *>(V); \
}
#include "llvm/CodeGen/DIEValue.def"
// Accessors
Type getType() const { return Ty; }
explicit operator bool() const { return Ty; }
#define HANDLE_DIEVALUE_SMALL(T) \
const DIE##T &getDIE##T() const { \
assert(getType() == is##T && "Expected " #T); \
return get<DIE##T>(); \
}
#define HANDLE_DIEVALUE_LARGE(T) \
const DIE##T &getDIE##T() const { \
assert(getType() == is##T && "Expected " #T); \
return *get<const DIE##T *>(); \
}
#include "llvm/CodeGen/DIEValue.def"
/// EmitValue - Emit value via the Dwarf writer.
///
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
/// SizeOf - Return the size of a value in bytes.
///
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void print(raw_ostream &O) const;
void dump() const;
#endif
};
@@ -416,7 +467,7 @@ protected:
/// Attribute values.
///
SmallVector<DIEValue *, 12> Values;
SmallVector<DIEValue, 12> Values;
protected:
DIE()
@@ -438,7 +489,11 @@ public:
const std::vector<std::unique_ptr<DIE>> &getChildren() const {
return Children;
}
const SmallVectorImpl<DIEValue *> &getValues() const { return Values; }
const SmallVectorImpl<DIEValue> &getValues() const { return Values; }
void setValue(unsigned I, DIEValue New) {
assert(I < Values.size());
Values[I] = New;
}
DIE *getParent() const { return Parent; }
/// Climb up the parent chain to get the compile or type unit DIE this DIE
/// belongs to.
@@ -451,7 +506,7 @@ public:
/// addValue - Add a value and attributes to a DIE.
///
void addValue(dwarf::Attribute Attribute, dwarf::Form Form, DIEValue *Value) {
void addValue(dwarf::Attribute Attribute, dwarf::Form Form, DIEValue Value) {
Abbrev.AddAttribute(Attribute, Form);
Values.push_back(Value);
}
@@ -465,9 +520,11 @@ public:
Children.push_back(std::move(Child));
}
/// findAttribute - Find a value in the DIE with the attribute given,
/// returns NULL if no such attribute exists.
DIEValue *findAttribute(dwarf::Attribute Attribute) const;
/// Find a value in the DIE with the attribute given.
///
/// Returns a default-constructed DIEValue (where \a DIEValue::getType()
/// 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;
@@ -478,12 +535,11 @@ public:
//===--------------------------------------------------------------------===//
/// DIELoc - Represents an expression location.
//
class DIELoc : public DIEValue, public DIE {
friend class DIEValue;
class DIELoc : public DIE {
mutable unsigned Size; // Size in bytes excluding size header.
public:
DIELoc() : DIEValue(isLoc), Size(0) {}
DIELoc() : Size(0) {}
/// ComputeSize - Calculate the size of the location expression.
///
@@ -504,27 +560,22 @@ public:
return dwarf::DW_FORM_block;
}
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *E) { return E->getType() == isLoc; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};
//===--------------------------------------------------------------------===//
/// DIEBlock - Represents a block of values.
//
class DIEBlock : public DIEValue, public DIE {
friend class DIEValue;
class DIEBlock : public DIE {
mutable unsigned Size; // Size in bytes excluding size header.
public:
DIEBlock() : DIEValue(isBlock), Size(0) {}
DIEBlock() : Size(0) {}
/// ComputeSize - Calculate the size of the location expression.
///
@@ -542,15 +593,11 @@ public:
return dwarf::DW_FORM_block;
}
// Implement isa/cast/dyncast.
static bool classof(const DIEValue *E) { return E->getType() == isBlock; }
private:
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
#ifndef NDEBUG
void printImpl(raw_ostream &O) const;
void print(raw_ostream &O) const;
#endif
};