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.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 144635e..7e0ae22 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -326,6 +326,30 @@
   // 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 @@
   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 @@
     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);