diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index 7fb3c90dcb6..7a14be65e2a 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -113,13 +113,21 @@ DIE::~DIE() { /// Climb up the parent chain to get the compile unit DIE to which this DIE /// belongs. DIE *DIE::getCompileUnit() { + DIE *Cu = checkCompileUnit(); + 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. +DIE *DIE::checkCompileUnit() { DIE *p = this; while (p) { if (p->getTag() == dwarf::DW_TAG_compile_unit) return p; p = p->getParent(); } - llvm_unreachable("We should not have orphaned DIEs."); + return NULL; } DIEValue *DIE::findAttribute(uint16_t Attribute) { diff --git a/lib/CodeGen/AsmPrinter/DIE.h b/lib/CodeGen/AsmPrinter/DIE.h index 6eaa6ee66ef..35b76b52c1f 100644 --- a/lib/CodeGen/AsmPrinter/DIE.h +++ b/lib/CodeGen/AsmPrinter/DIE.h @@ -152,6 +152,9 @@ namespace llvm { /// Climb up the parent chain to get the compile unit DIE this DIE belongs /// to. DIE *getCompileUnit(); + /// Similar to getCompileUnit, returns null when DIE is not added to an + /// owner yet. + DIE *checkCompileUnit(); void setTag(uint16_t Tag) { Abbrev.setTag(Tag); } void setOffset(unsigned O) { Offset = O; } void setSize(unsigned S) { Size = S; } diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index d3d8251bb2f..e5761ea475d 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -242,7 +242,7 @@ void CompileUnit::addDelta(DIE *Die, uint16_t Attribute, uint16_t Form, /// void CompileUnit::addDIEEntry(DIE *Die, uint16_t Attribute, uint16_t Form, DIE *Entry) { - Die->addValue(Attribute, Form, createDIEEntry(Entry)); + DD->addDIEEntry(Die, Attribute, Form, createDIEEntry(Entry)); } /// addBlock - Add block data. @@ -784,13 +784,13 @@ DIE *CompileUnit::getOrCreateTypeDIE(const MDNode *TyNode) { DIType Ty(TyNode); if (!Ty.isType()) return NULL; - DIE *TyDIE = getDIE(Ty); + DIE *TyDIE = DD->getTypeDIE(Ty); if (TyDIE) return TyDIE; // Create new type. TyDIE = new DIE(dwarf::DW_TAG_base_type); - insertDIE(Ty, TyDIE); + DD->insertTypeDIE(Ty, TyDIE); if (Ty.isBasicType()) constructTypeDIE(*TyDIE, DIBasicType(Ty)); else if (Ty.isCompositeType()) @@ -826,7 +826,7 @@ void CompileUnit::addType(DIE *Entity, DIType Ty, uint16_t Attribute) { DIEEntry *Entry = getDIEEntry(Ty); // If it exists then use the existing value. if (Entry) { - Entity->addValue(Attribute, dwarf::DW_FORM_ref4, Entry); + DD->addDIEEntry(Entity, Attribute, dwarf::DW_FORM_ref4, Entry); return; } @@ -836,7 +836,7 @@ void CompileUnit::addType(DIE *Entity, DIType Ty, uint16_t Attribute) { // Set up proxy. Entry = createDIEEntry(Buffer); insertDIEEntry(Ty, Entry); - Entity->addValue(Attribute, dwarf::DW_FORM_ref4, Entry); + DD->addDIEEntry(Entity, Attribute, dwarf::DW_FORM_ref4, Entry); // If this is a complete composite type then include it in the // list of global types. @@ -1268,14 +1268,14 @@ DIE *CompileUnit::getOrCreateNameSpace(DINameSpace NS) { /// getOrCreateSubprogramDIE - Create new DIE using SP. DIE *CompileUnit::getOrCreateSubprogramDIE(DISubprogram SP) { - DIE *SPDie = getDIE(SP); + DIE *SPDie = DD->getSPDIE(SP); if (SPDie) return SPDie; SPDie = new DIE(dwarf::DW_TAG_subprogram); // DW_TAG_inlined_subroutine may refer to this DIE. - insertDIE(SP, SPDie); + DD->insertSPDIE(SP, SPDie); DISubprogram SPDecl = SP.getFunctionDeclaration(); DIE *DeclDie = NULL; @@ -1422,7 +1422,7 @@ void CompileUnit::createGlobalVariableDIE(const MDNode *N) { // But that class might not exist in the DWARF yet. // Creating the class will create the static member decl DIE. getOrCreateContextDIE(DD->resolve(SDMDecl.getContext())); - VariableDIE = getDIE(SDMDecl); + VariableDIE = DD->getStaticMemberDIE(SDMDecl); assert(VariableDIE && "Static member decl has no context?"); IsStaticMember = true; } @@ -1616,7 +1616,7 @@ void CompileUnit::constructContainingTypeDIEs() { DIE *SPDie = CI->first; const MDNode *N = CI->second; if (!N) continue; - DIE *NDie = getDIE(N); + DIE *NDie = DD->getTypeDIE(N); if (!NDie) continue; addDIEEntry(SPDie, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, NDie); } @@ -1819,6 +1819,6 @@ DIE *CompileUnit::createStaticMemberDIE(const DIDerivedType DT) { if (const ConstantFP *CFP = dyn_cast_or_null(DT.getConstant())) addConstantFPValue(StaticMemberDIE, CFP); - insertDIE(DT, StaticMemberDIE); + DD->insertStaticMemberDIE(DT, StaticMemberDIE); return StaticMemberDIE; } diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 38262556979..3f2de40fa83 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -357,7 +357,7 @@ bool DwarfDebug::isSubprogramContext(const MDNode *Context) { // scope then create and insert DIEs for these variables. DIE *DwarfDebug::updateSubprogramScopeDIE(CompileUnit *SPCU, const MDNode *SPNode) { - DIE *SPDie = SPCU->getDIE(SPNode); + DIE *SPDie = getSPDIE(SPNode); assert(SPDie && "Unable to find subprogram DIE!"); DISubprogram SP(SPNode); @@ -511,7 +511,7 @@ DIE *DwarfDebug::constructInlinedScopeDIE(CompileUnit *TheCU, return NULL; DIScope DS(Scope->getScopeNode()); DISubprogram InlinedSP = getDISubprogram(DS); - DIE *OriginDIE = TheCU->getDIE(InlinedSP); + DIE *OriginDIE = getSPDIE(InlinedSP); if (!OriginDIE) { DEBUG(dbgs() << "Unable to find original DIE for an inlined subprogram."); return NULL; @@ -616,7 +616,7 @@ DIE *DwarfDebug::constructScopeDIE(CompileUnit *TheCU, LexicalScope *Scope) { else if (DS.isSubprogram()) { ProcessedSPNodes.insert(DS); if (Scope->isAbstractScope()) { - ScopeDIE = TheCU->getDIE(DS); + ScopeDIE = getSPDIE(DS); // Note down abstract DIE. if (ScopeDIE) AbstractSPDies.insert(std::make_pair(DS, ScopeDIE)); @@ -992,7 +992,7 @@ void DwarfDebug::collectDeadVariables() { CompileUnit *SPCU = CUMap.lookup(TheCU); assert(SPCU && "Unable to find Compile Unit!"); constructSubprogramDIE(SPCU, SP); - DIE *ScopeDIE = SPCU->getDIE(SP); + DIE *ScopeDIE = getSPDIE(SP); for (unsigned vi = 0, ve = Variables.getNumElements(); vi != ve; ++vi) { DIVariable DV(Variables.getElement(vi)); if (!DV.isVariable()) continue; @@ -1065,6 +1065,15 @@ void DwarfDebug::finalizeModuleInfo() { Hash.computeDIEODRSignature(Die)); } + // Process the worklist to add attributes with the correct form (ref_addr or + // ref4). + for (unsigned I = 0, E = DIEEntryWorklist.size(); I < E; I++) { + addDIEEntry(DIEEntryWorklist[I].Die, DIEEntryWorklist[I].Attribute, + dwarf::DW_FORM_ref4, DIEEntryWorklist[I].Entry); + assert(E == DIEEntryWorklist.size() && + "We should not add to the worklist during finalization."); + } + // Handle anything that needs to be done on a per-cu basis. for (DenseMap::iterator CUI = CUMap.begin(), CUE = CUMap.end(); @@ -2042,7 +2051,11 @@ void DwarfDebug::emitDIE(DIE *Die, std::vector *Abbrevs) { Asm->OutStreamer.AddComment(dwarf::AttributeString(Attr)); switch (Attr) { - case dwarf::DW_AT_abstract_origin: { + case dwarf::DW_AT_abstract_origin: + case dwarf::DW_AT_type: + case dwarf::DW_AT_friend: + case dwarf::DW_AT_specification: + case dwarf::DW_AT_containing_type: { DIEEntry *E = cast(Values[i]); DIE *Origin = E->getEntry(); unsigned Addr = Origin->getOffset(); @@ -3031,3 +3044,24 @@ void DwarfDebug::emitDebugStrDWO() { InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), OffSec, StrSym); } + +/// When we don't know whether the correct form is ref4 or ref_addr, we create +/// a worklist item and insert it to DIEEntryWorklist. +void DwarfDebug::addDIEEntry(DIE *Die, uint16_t Attribute, uint16_t Form, + DIEEntry *Entry) { + /// Early exit when we only have a single CU. + if (GlobalCUIndexCount == 1 || Form != dwarf::DW_FORM_ref4) { + Die->addValue(Attribute, Form, Entry); + return; + } + DIE *DieCU = Die->checkCompileUnit(); + DIE *EntryCU = Entry->getEntry()->checkCompileUnit(); + if (!DieCU || !EntryCU) { + // Die or Entry is not added to an owner yet. + insertDIEEntryWorklist(Die, Attribute, Entry); + return; + } + Die->addValue(Attribute, + EntryCU == DieCU ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr, + Entry); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 144635ef6a8..7e0ae22f519 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -326,6 +326,30 @@ class DwarfDebug { // Maps subprogram MDNode with its corresponding CompileUnit. DenseMap SPMap; + /// Maps type MDNode with its corresponding DIE. These DIEs can be + /// shared across CUs, that is why we keep the map here instead + /// of in CompileUnit. + DenseMap MDTypeNodeToDieMap; + /// Maps subprogram MDNode with its corresponding DIE. + DenseMap MDSPNodeToDieMap; + /// Maps static member MDNode with its corresponding DIE. + DenseMap MDStaticMemberNodeToDieMap; + + /// Specifies a worklist item. Sometimes, when we try to add an attribute to + /// a DIE, the DIE is not yet added to its owner yet, so we don't know whether + /// we should use ref_addr or ref4. We create a worklist that will be + /// processed during finalization to add attributes with the correct form + /// (ref_addr or ref4). + struct DIEEntryWorkItem { + DIE *Die; + uint16_t Attribute; + DIEEntry *Entry; + DIEEntryWorkItem(DIE *D, uint16_t A, DIEEntry *E) : + Die(D), Attribute(A), Entry(E) { + } + }; + SmallVector DIEEntryWorklist; + // Used to uniquely define abbreviations. FoldingSet AbbreviationsSet; @@ -660,6 +684,28 @@ public: DwarfDebug(AsmPrinter *A, Module *M); ~DwarfDebug(); + void insertTypeDIE(const MDNode *TypeMD, DIE *Die) { + MDTypeNodeToDieMap.insert(std::make_pair(TypeMD, Die)); + } + DIE *getTypeDIE(const MDNode *TypeMD) { + return MDTypeNodeToDieMap.lookup(TypeMD); + } + void insertSPDIE(const MDNode *SPMD, DIE *Die) { + MDSPNodeToDieMap.insert(std::make_pair(SPMD, Die)); + } + DIE *getSPDIE(const MDNode *SPMD) { + return MDSPNodeToDieMap.lookup(SPMD); + } + void insertStaticMemberDIE(const MDNode *StaticMD, DIE *Die) { + MDStaticMemberNodeToDieMap.insert(std::make_pair(StaticMD, Die)); + } + DIE *getStaticMemberDIE(const MDNode *StaticMD) { + return MDStaticMemberNodeToDieMap.lookup(StaticMD); + } + void insertDIEEntryWorklist(DIE *Die, uint16_t Attribute, DIEEntry *Entry) { + DIEEntryWorklist.push_back(DIEEntryWorkItem(Die, Attribute, Entry)); + } + /// \brief Emit all Dwarf sections that should come prior to the /// content. void beginModule(); @@ -722,6 +768,11 @@ public: return Ref.resolve(TypeIdentifierMap); } + /// When we don't know whether the correct form is ref4 or ref_addr, we create + /// a worklist item and insert it to DIEEntryWorklist. + void addDIEEntry(DIE *Die, uint16_t Attribute, uint16_t Form, + DIEEntry *Entry); + /// isSubprogramContext - Return true if Context is either a subprogram /// or another context nested inside a subprogram. bool isSubprogramContext(const MDNode *Context); diff --git a/test/Linker/type-unique-simple-a.ll b/test/Linker/type-unique-simple-a.ll index 7c2e7bfa908..251e5b34241 100644 --- a/test/Linker/type-unique-simple-a.ll +++ b/test/Linker/type-unique-simple-a.ll @@ -1,7 +1,22 @@ -; RUN: llvm-link %s %p/type-unique-simple-b.ll -S -o - | FileCheck %s +; REQUIRES: object-emission -; CHECK: DW_TAG_structure_type +; RUN: llvm-link %s %p/type-unique-simple-b.ll -S -o %t +; RUN: cat %t | FileCheck %s -check-prefix=LINK +; RUN: llc -filetype=obj -O0 < %t > %t2 +; RUN: llvm-dwarfdump -debug-dump=info %t2 | FileCheck %s +; CHECK: 0x[[INT:.*]]: DW_TAG_base_type +; CHECK-NEXT: DW_AT_name {{.*}} = "int" +; CHECK-NOT: DW_TAG_base_type +; CHECK: 0x[[BASE:.*]]: DW_TAG_structure_type +; CHECK-NEXT: DW_AT_name {{.*}} = "Base" ; CHECK-NOT: DW_TAG_structure_type +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[INT]]) +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[BASE]]) + +; LINK: DW_TAG_structure_type +; LINK-NOT: DW_TAG_structure_type ; Content of header files: ; struct Base { ; int a;