Debug Info: remove duplication of DIEs when a DIE is part of the type system

and it is shared across CUs.

We add a few maps in DwarfDebug to map MDNodes for the type system to the
corresponding DIEs: MDTypeNodeToDieMap, MDSPNodeToDieMap, and
MDStaticMemberNodeToDieMap. These DIEs can be shared across CUs, that is why we
keep the maps in DwarfDebug instead of CompileUnit.

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).

We add addDIEEntry to DwarfDebug to be a wrapper around DIE->addValue. It checks
whether we know the correct form, if not, we update the worklist
(DIEEntryWorklist).

A testing case is added to show that we only create a single DIE for a type
MDNode and we use ref_addr to refer to the type DIE.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191792 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Manman Ren 2013-10-01 19:52:23 +00:00
parent dfef7cbfc6
commit 620f436b20
6 changed files with 129 additions and 18 deletions

View File

@ -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) {

View File

@ -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; }

View File

@ -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<ConstantFP>(DT.getConstant()))
addConstantFPValue(StaticMemberDIE, CFP);
insertDIE(DT, StaticMemberDIE);
DD->insertStaticMemberDIE(DT, StaticMemberDIE);
return StaticMemberDIE;
}

View File

@ -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<const MDNode *, CompileUnit *>::iterator CUI = CUMap.begin(),
CUE = CUMap.end();
@ -2042,7 +2051,11 @@ void DwarfDebug::emitDIE(DIE *Die, std::vector<DIEAbbrev *> *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<DIEEntry>(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);
}

View File

@ -326,6 +326,30 @@ class DwarfDebug {
// Maps subprogram MDNode with its corresponding CompileUnit.
DenseMap <const MDNode *, CompileUnit *> 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<const MDNode *, DIE *> MDTypeNodeToDieMap;
/// Maps subprogram MDNode with its corresponding DIE.
DenseMap<const MDNode *, DIE *> MDSPNodeToDieMap;
/// Maps static member MDNode with its corresponding DIE.
DenseMap<const MDNode *, DIE *> 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<DIEEntryWorkItem, 64> DIEEntryWorklist;
// Used to uniquely define abbreviations.
FoldingSet<DIEAbbrev> 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);

View File

@ -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;