/// Climb up the parent chain to get the compile unit DIE to which this DIE
/// belongs.
-const DIE *DIE::getCompileUnit() const {
- const DIE *Cu = getCompileUnitOrNull();
+const DIE *DIE::getUnit() const {
+ const DIE *Cu = getUnitOrNull();
assert(Cu && "We should not have orphaned DIEs.");
return Cu;
}
/// Climb up the parent chain to get the compile unit DIE this DIE belongs
/// to. Return NULL if DIE is not added to an owner yet.
-const DIE *DIE::getCompileUnitOrNull() const {
+const DIE *DIE::getUnitOrNull() const {
const DIE *p = this;
while (p) {
- if (p->getTag() == dwarf::DW_TAG_compile_unit)
+ if (p->getTag() == dwarf::DW_TAG_compile_unit ||
+ p->getTag() == dwarf::DW_TAG_type_unit)
return p;
p = p->getParent();
}
case dwarf::DW_FORM_ref4: // Fall thru
case dwarf::DW_FORM_data4: Size = 4; break;
case dwarf::DW_FORM_ref8: // Fall thru
+ case dwarf::DW_FORM_ref_sig8: // Fall thru
case dwarf::DW_FORM_data8: Size = 8; break;
case dwarf::DW_FORM_GNU_str_index: Asm->EmitULEB128(Integer); return;
case dwarf::DW_FORM_GNU_addr_index: Asm->EmitULEB128(Integer); return;
case dwarf::DW_FORM_ref4: // Fall thru
case dwarf::DW_FORM_data4: return sizeof(int32_t);
case dwarf::DW_FORM_ref8: // Fall thru
+ case dwarf::DW_FORM_ref_sig8: // Fall thru
case dwarf::DW_FORM_data8: return sizeof(int64_t);
case dwarf::DW_FORM_GNU_str_index: return MCAsmInfo::getULEB128Size(Integer);
case dwarf::DW_FORM_GNU_addr_index: return MCAsmInfo::getULEB128Size(Integer);
const std::vector<DIE *> &getChildren() const { return Children; }
const SmallVectorImpl<DIEValue*> &getValues() const { return Values; }
DIE *getParent() const { return Parent; }
- /// Climb up the parent chain to get the compile unit DIE this DIE belongs
- /// to.
- const DIE *getCompileUnit() const;
- /// Similar to getCompileUnit, returns null when DIE is not added to an
+ /// Climb up the parent chain to get the compile or type unit DIE this DIE
+ /// belongs to.
+ const DIE *getUnit() const;
+ /// Similar to getUnit, returns null when DIE is not added to an
/// owner yet.
- const DIE *getCompileUnitOrNull() const;
+ const DIE *getUnitOrNull() const;
void setOffset(unsigned O) { Offset = O; }
void setSize(unsigned S) { Size = S; }
// outermost such construct...
SmallVector<const DIE *, 1> Parents;
const DIE *Cur = &Parent;
- while (Cur->getTag() != dwarf::DW_TAG_compile_unit) {
+ while (Cur->getParent()) {
Parents.push_back(Cur);
Cur = Cur->getParent();
}
+ assert(Cur->getTag() == dwarf::DW_TAG_compile_unit ||
+ Cur->getTag() == dwarf::DW_TAG_type_unit);
// Reverse iterate over our list to go from the outermost construct to the
// innermost.
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Support/CommandLine.h"
using namespace llvm;
+static cl::opt<bool> GenerateTypeUnits("generate-type-units", cl::Hidden,
+ cl::desc("Generate DWARF4 type units."),
+ cl::init(false));
+
/// CompileUnit - Compile unit constructor.
CompileUnit::CompileUnit(unsigned UID, DIE *D, DICompileUnit Node,
AsmPrinter *A, DwarfDebug *DW, DwarfUnits *DWU)
: UniqueID(UID), Node(Node), CUDie(D), Asm(A), DD(DW), DU(DWU),
- IndexTyDie(0), DebugInfoOffset(0) {
+ IndexTyDie(0), Language(Node.getLanguage()) {
DIEIntegerOne = new (DIEValueAllocator) DIEInteger(1);
insertDIE(Node, D);
}
+CompileUnit::CompileUnit(unsigned UID, DIE *D, uint16_t Language, AsmPrinter *A,
+ DwarfDebug *DD, DwarfUnits *DU)
+ : UniqueID(UID), Node(NULL), CUDie(D), Asm(A), DD(DD), DU(DU),
+ IndexTyDie(0), Language(Language) {
+ DIEIntegerOne = new (DIEValueAllocator) DIEInteger(1);
+}
+
/// ~CompileUnit - Destructor for compile unit.
CompileUnit::~CompileUnit() {
for (unsigned j = 0, M = DIEBlocks.size(); j < M; ++j)
static bool isShareableAcrossCUs(DIDescriptor D) {
// When the MDNode can be part of the type system, the DIE can be
// shared across CUs.
- return D.isType() || (D.isSubprogram() && !DISubprogram(D).isDefinition());
+ return (D.isType() ||
+ (D.isSubprogram() && !DISubprogram(D).isDefinition())) &&
+ !GenerateTypeUnits;
}
/// getDIE - Returns the debug information entry map slot for the
void CompileUnit::addDIEEntry(DIE *Die, dwarf::Attribute Attribute,
DIEEntry *Entry) {
- const DIE *DieCU = Die->getCompileUnitOrNull();
- const DIE *EntryCU = Entry->getEntry()->getCompileUnitOrNull();
+ const DIE *DieCU = Die->getUnitOrNull();
+ const DIE *EntryCU = Entry->getEntry()->getUnitOrNull();
if (!DieCU)
// We assume that Die belongs to this CU, if it is not linked to any CU yet.
DieCU = getCUDie();
return getDIE(Context);
}
+DIE *CompileUnit::createTypeDIE(DICompositeType Ty) {
+ DIE *ContextDIE = getOrCreateContextDIE(resolve(Ty.getContext()));
+
+ DIE *TyDIE = getDIE(Ty);
+ if (TyDIE)
+ return TyDIE;
+
+ // Create new type.
+ TyDIE = createAndAddDIE(Ty.getTag(), *ContextDIE, Ty);
+
+ constructTypeDIEImpl(*TyDIE, Ty);
+
+ updateAcceleratorTables(Ty, TyDIE);
+ return TyDIE;
+}
+
/// getOrCreateTypeDIE - Find existing DIE or create new DIE for the
/// given DIType.
DIE *CompileUnit::getOrCreateTypeDIE(const MDNode *TyNode) {
/// Return true if the type should be split out into a type unit.
static bool shouldCreateTypeUnit(DICompositeType CTy, const DwarfDebug *DD) {
+ if (!GenerateTypeUnits)
+ return false;
+
uint16_t Tag = CTy.getTag();
switch (Tag) {
/// constructTypeDIE - Construct type DIE from DICompositeType.
void CompileUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) {
- // Get core information.
+ // If this is a type applicable to a type unit it then add it to the
+ // list of types we'll compute a hash for later.
+ if (shouldCreateTypeUnit(CTy, DD))
+ DD->addTypeUnitType(&Buffer, CTy);
+ else
+ constructTypeDIEImpl(Buffer, CTy);
+}
+
+void CompileUnit::constructTypeDIEImpl(DIE &Buffer, DICompositeType CTy) {
+ // Add name if not anonymous or intermediate type.
StringRef Name = CTy.getName();
uint64_t Size = CTy.getSizeInBits() >> 3;
addUInt(&Buffer, dwarf::DW_AT_APPLE_runtime_class, dwarf::DW_FORM_data1,
RLang);
}
- // If this is a type applicable to a type unit it then add it to the
- // list of types we'll compute a hash for later.
- if (shouldCreateTypeUnit(CTy, DD))
- DD->addTypeUnitType(&Buffer);
}
/// constructTemplateTypeParameterDIE - Construct new DIE for the given
/// createGlobalVariableDIE - create global variable DIE.
void CompileUnit::createGlobalVariableDIE(DIGlobalVariable GV) {
-
// Check for pre-existence.
if (getDIE(GV))
return;
// DIEIntegerOne - A preallocated DIEValue because 1 is used frequently.
DIEInteger *DIEIntegerOne;
+ uint16_t Language;
+
public:
CompileUnit(unsigned UID, DIE *D, DICompileUnit CU, AsmPrinter *A,
DwarfDebug *DW, DwarfUnits *DWU);
+ CompileUnit(unsigned UID, DIE *D, uint16_t Language, AsmPrinter *A,
+ DwarfDebug *DW, DwarfUnits *DWU);
~CompileUnit();
// Accessors.
unsigned getUniqueID() const { return UniqueID; }
- uint16_t getLanguage() const { return Node.getLanguage(); }
+ uint16_t getLanguage() const { return Language; }
DICompileUnit getNode() const { return Node; }
DIE *getCUDie() const { return CUDie.get(); }
const StringMap<DIE *> &getGlobalNames() const { return GlobalNames; }
/// given DIType.
DIE *getOrCreateTypeDIE(const MDNode *N);
+ /// getOrCreateContextDIE - Get context owner's DIE.
+ DIE *createTypeDIE(DICompositeType Ty);
+
/// getOrCreateContextDIE - Get context owner's DIE.
DIE *getOrCreateContextDIE(DIScope Context);
DIE *createAndAddDIE(unsigned Tag, DIE &Parent,
DIDescriptor N = DIDescriptor());
+ /// constructTypeDIEImpl - Construct type DIE that is not a type unit
+ /// reference from a DICompositeType.
+ void constructTypeDIEImpl(DIE &Buffer, DICompositeType CTy);
+
/// Compute the size of a header for this unit, not including the initial
/// length field.
unsigned getHeaderSize() const {
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
computeInlinedDIEs();
- // Split out type units and conditionally add an ODR tag to the split
- // out type.
- // FIXME: Do type splitting.
- for (unsigned i = 0, e = TypeUnits.size(); i != e; ++i) {
- DIE *Die = TypeUnits[i];
- DIEHash Hash;
- // If we've requested ODR hashes and it's applicable for an ODR hash then
- // add the ODR signature now.
- // FIXME: This should be added onto the type unit, not the type, but this
- // works as an intermediate stage.
- if (GenerateODRHash && shouldAddODRHash(CUMap.begin()->second, Die))
- CUMap.begin()->second->addUInt(Die, dwarf::DW_AT_GNU_odr_signature,
- dwarf::DW_FORM_data8,
- Hash.computeDIEODRSignature(*Die));
- }
-
// Handle anything that needs to be done on a per-cu basis.
for (DenseMap<const MDNode *, CompileUnit *>::iterator CUI = CUMap.begin(),
CUE = CUMap.end();
// For DW_FORM_ref_addr, output the offset from beginning of debug info
// section. Origin->getOffset() returns the offset from start of the
// compile unit.
- CompileUnit *CU = CUDieMap.lookup(Origin->getCompileUnit());
+ CompileUnit *CU = CUDieMap.lookup(Origin->getUnit());
assert(CU && "CUDie should belong to a CU.");
Addr += CU->getDebugInfoOffset();
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
DIEEntry::getRefAddrSize(Asm));
} else {
// Make sure Origin belong to the same CU.
- assert(Die->getCompileUnit() == Origin->getCompileUnit() &&
+ assert(Die->getUnit() == Origin->getUnit() &&
"The referenced DIE should belong to the same CU in ref4");
Asm->EmitInt32(Addr);
}
InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(),
OffSec, StrSym);
}
+
+void DwarfDebug::addTypeUnitType(DIE *RefDie, DICompositeType CTy) {
+ DenseMap<const MDNode*, std::pair<uint64_t, SmallVectorImpl<DIE*>* > >::iterator I = TypeUnits.find(CTy);
+ SmallVector<DIE *, 8> References;
+ References.push_back(RefDie);
+ if (I != TypeUnits.end()) {
+ if (I->second.second) {
+ I->second.second->push_back(RefDie);
+ return;
+ }
+ } else {
+ DIE *UnitDie = new DIE(dwarf::DW_TAG_type_unit);
+ CompileUnit *NewCU =
+ new CompileUnit(GlobalCUIndexCount++, UnitDie,
+ dwarf::DW_LANG_C_plus_plus, Asm, this, &InfoHolder);
+ CUDieMap.insert(std::make_pair(UnitDie, NewCU));
+ NewCU->addUInt(UnitDie, dwarf::DW_AT_language, dwarf::DW_FORM_data2,
+ dwarf::DW_LANG_C_plus_plus);
+
+ // Register the type in the TypeUnits map with a vector of references to be
+ // populated whenever a reference is required.
+ I = TypeUnits.insert(std::make_pair(CTy, std::make_pair(0, &References)))
+ .first;
+
+ // Construct the type, this may, recursively, require more type units that
+ // may in turn require this type again - in which case they will add DIEs to
+ // the References vector.
+ DIE *Die = NewCU->createTypeDIE(CTy);
+
+ if (GenerateODRHash && shouldAddODRHash(NewCU, Die))
+ NewCU->addUInt(UnitDie, dwarf::DW_AT_GNU_odr_signature,
+ dwarf::DW_FORM_data8,
+ DIEHash().computeDIEODRSignature(*Die));
+ // FIXME: This won't handle circularly referential structures, as the DIE
+ // may have references to other DIEs still under construction and missing
+ // their signature. Hashing should walk through the signatures to their
+ // referenced type, or possibly walk the precomputed hashes of related types
+ // at the end.
+ uint64_t Signature = DIEHash().computeTypeSignature(*Die);
+
+ // Remove the References vector and add the type hash.
+ I->second.first = Signature;
+ I->second.second = NULL;
+
+
+ InfoHolder.addUnit(NewCU);
+ }
+
+ // Populate all the signatures.
+ for (unsigned i = 0, e = References.size(); i != e; ++i) {
+ CUMap.begin()->second->addUInt(References[i], dwarf::DW_AT_signature,
+ dwarf::DW_FORM_ref_sig8, I->second.first);
+ }
+}
class MachineModuleInfo;
class MachineOperand;
class MCAsmInfo;
+class MCObjectFileInfo;
class DIEAbbrev;
class DIE;
class DIEBlock;
ImportedEntityMap ScopesWithImportedEntities;
// Holder for types that are going to be extracted out into a type unit.
- std::vector<DIE *> TypeUnits;
+ DenseMap<const MDNode *, std::pair<uint64_t, SmallVectorImpl<DIE*>* > > TypeUnits;
// Whether to emit the pubnames/pubtypes sections.
bool HasDwarfPubSections;
/// \brief Add a DIE to the set of types that we're going to pull into
/// type units.
- void addTypeUnitType(DIE *Die) { TypeUnits.push_back(Die); }
+ void addTypeUnitType(DIE *Die, DICompositeType CTy);
/// \brief Add a label so that arange data can be generated for it.
void addArangeLabel(SymbolCU SCU) { ArangeLabels.push_back(SCU); }
; REQUIRES: object-emission
-; RUN: llc %s -o %t -filetype=obj -O0 -generate-odr-hash -mtriple=x86_64-unknown-linux-gnu
+; RUN: llc %s -o %t -filetype=obj -O0 -generate-type-units -generate-odr-hash -mtriple=x86_64-unknown-linux-gnu
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
;
; Generated from:
; wombat wom;
; Check that we generate a hash for bar and the value.
+; CHECK-LABEL: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x200520c0d5b90eff)
; CHECK: DW_TAG_structure_type
; CHECK-NEXT: debug_str{{.*}}"bar"
-; CHECK: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x200520c0d5b90eff)
+
+; Check that we generate a hash for fluffy and the value.
+; CHECK-LABEL: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x9a0124d5a0c21c52)
; CHECK: DW_TAG_namespace
; CHECK-NEXT: debug_str{{.*}}"echidna"
; CHECK: DW_TAG_namespace
; CHECK-NEXT: debug_str{{.*}}"mongoose"
; CHECK: DW_TAG_class_type
; CHECK-NEXT: debug_str{{.*}}"fluffy"
-; CHECK: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x9a0124d5a0c21c52)
; We emit no hash for walrus since the type is contained in an anonymous
; namespace and won't violate any ODR-ness.
+; CHECK: DW_TAG_type_unit
+; CHECK-NOT: NULL
+; CHECK-NOT: DW_AT_GNU_odr_signature
; CHECK: DW_TAG_structure_type
; CHECK-NEXT: debug_str{{.*}}"walrus"
; CHECK-NEXT: DW_AT_byte_size
; CHECK-NEXT: DW_AT_decl_file
; CHECK-NEXT: DW_AT_decl_line
-; CHECK-NOT: DW_AT_GNU_odr_signature
; CHECK: DW_TAG_subprogram
+
; Check that we generate a hash for wombat and the value, but not for the
; anonymous type contained within.
+; CHECK: DW_TAG_type_unit
; CHECK: DW_TAG_structure_type
-; CHECK-NEXT: debug_str{{.*}}wombat
-; CHECK: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x685bcc220141e9d7)
+; The signature for the outer 'wombat' type - this can be FileChecked once the
+; type units are moved to their own section with the full type unit header
+; including the signature
+; CHECK: DW_AT_signature [DW_FORM_ref_sig8] (0x73776f130648b986)
; CHECK: DW_TAG_structure_type
-; CHECK-NEXT: DW_AT_byte_size
-; CHECK-NEXT: DW_AT_decl_file
-; CHECK-NEXT: DW_AT_decl_line
+; CHECK-NOT: DW_AT_name
+; CHECK-NOT: DW_AT_GNU_odr_signature
; CHECK: DW_TAG_member
; CHECK-NEXT: debug_str{{.*}}"a"
-
-; Check that we don't generate a hash for baz.
+; CHECK-LABEL: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x685bcc220141e9d7)
; CHECK: DW_TAG_structure_type
-; CHECK-NEXT: debug_str{{.*}}"baz"
-; CHECK-NOT: DW_AT_GNU_odr_signature
+; CHECK-NEXT: debug_str{{.*}}"wombat"
%struct.bar = type { i8 }
%"class.echidna::capybara::mongoose::fluffy" = type { i32, i32 }