diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index 69444285f4e..c6b765a5f0a 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -114,18 +114,19 @@ DIE::~DIE() { /// 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(); } @@ -227,6 +228,7 @@ void DIEInteger::EmitValue(AsmPrinter *Asm, dwarf::Form Form) const { 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; @@ -253,6 +255,7 @@ unsigned DIEInteger::SizeOf(AsmPrinter *AP, dwarf::Form Form) const { 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); diff --git a/lib/CodeGen/AsmPrinter/DIE.h b/lib/CodeGen/AsmPrinter/DIE.h index 28a2e8e38a0..0574a98536b 100644 --- a/lib/CodeGen/AsmPrinter/DIE.h +++ b/lib/CodeGen/AsmPrinter/DIE.h @@ -146,12 +146,12 @@ namespace llvm { const std::vector &getChildren() const { return Children; } const SmallVectorImpl &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; } diff --git a/lib/CodeGen/AsmPrinter/DIEHash.cpp b/lib/CodeGen/AsmPrinter/DIEHash.cpp index 95eca90ef04..d76af538041 100644 --- a/lib/CodeGen/AsmPrinter/DIEHash.cpp +++ b/lib/CodeGen/AsmPrinter/DIEHash.cpp @@ -92,10 +92,12 @@ void DIEHash::addParentContext(const DIE &Parent) { // outermost such construct... SmallVector 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. diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index fbd7ce82283..2489002f7fd 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -29,18 +29,30 @@ #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 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) @@ -102,7 +114,9 @@ int64_t CompileUnit::getDefaultLowerBound() const { 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 @@ -281,8 +295,8 @@ void CompileUnit::addDIEEntry(DIE *Die, dwarf::Attribute Attribute, 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(); @@ -871,6 +885,22 @@ DIE *CompileUnit::getOrCreateContextDIE(DIScope Context) { 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) { @@ -1112,6 +1142,9 @@ static bool isTypeUnitScoped(DIType Ty, const DwarfDebug *DD) { /// 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) { @@ -1130,7 +1163,16 @@ static bool shouldCreateTypeUnit(DICompositeType CTy, const DwarfDebug *DD) { /// 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; @@ -1296,10 +1338,6 @@ void CompileUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { 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 @@ -1510,7 +1548,6 @@ static const ConstantExpr *getMergedGlobalExpr(const Value *V) { /// createGlobalVariableDIE - create global variable DIE. void CompileUnit::createGlobalVariableDIE(DIGlobalVariable GV) { - // Check for pre-existence. if (getDIE(GV)) return; diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 02f4206e949..3a0c6be0acf 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -93,14 +93,18 @@ class CompileUnit { // 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 &getGlobalNames() const { return GlobalNames; } @@ -310,6 +314,9 @@ public: /// 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); @@ -328,6 +335,10 @@ public: 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 { diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 35f76047dba..dca2196214f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1051,22 +1051,6 @@ void DwarfDebug::finalizeModuleInfo() { // 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::iterator CUI = CUMap.begin(), CUE = CUMap.end(); @@ -2071,7 +2055,7 @@ void DwarfDebug::emitDIE(DIE *Die, ArrayRef Abbrevs) { // 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()) @@ -2083,7 +2067,7 @@ void DwarfDebug::emitDIE(DIE *Die, ArrayRef Abbrevs) { 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); } @@ -3063,3 +3047,57 @@ void DwarfDebug::emitDebugStrDWO() { InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), OffSec, StrSym); } + +void DwarfDebug::addTypeUnitType(DIE *RefDie, DICompositeType CTy) { + DenseMap* > >::iterator I = TypeUnits.find(CTy); + SmallVector 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); + } +} diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index cebac39a19b..c3b12997317 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -37,6 +37,7 @@ class MachineFrameInfo; class MachineModuleInfo; class MachineOperand; class MCAsmInfo; +class MCObjectFileInfo; class DIEAbbrev; class DIE; class DIEBlock; @@ -443,7 +444,7 @@ class DwarfDebug { ImportedEntityMap ScopesWithImportedEntities; // Holder for types that are going to be extracted out into a type unit. - std::vector TypeUnits; + DenseMap* > > TypeUnits; // Whether to emit the pubnames/pubtypes sections. bool HasDwarfPubSections; @@ -695,7 +696,7 @@ public: /// \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); } diff --git a/test/DebugInfo/X86/generate-odr-hash.ll b/test/DebugInfo/X86/generate-odr-hash.ll index c3075f2f0d8..853d4a2047e 100644 --- a/test/DebugInfo/X86/generate-odr-hash.ll +++ b/test/DebugInfo/X86/generate-odr-hash.ll @@ -1,6 +1,6 @@ ; 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: @@ -44,9 +44,12 @@ ; 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 @@ -55,34 +58,36 @@ ; 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 }