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
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 3826255..3f2de40 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -357,7 +357,7 @@
 // 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 @@
     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 @@
   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 @@
         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 @@
                                      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 @@
       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 @@
   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);
+}