Debug Info: Use identifier to reference DIType in base type field of
authorManman Ren <manman.ren@gmail.com>
Thu, 5 Sep 2013 18:48:31 +0000 (18:48 +0000)
committerManman Ren <manman.ren@gmail.com>
Thu, 5 Sep 2013 18:48:31 +0000 (18:48 +0000)
ptr_to_member.

We introduce a new class DITypeRef that represents a reference to a DIType.
It wraps around a Value*, which can be either an identifier in MDString
or an actual MDNode. The class has a helper function "resolve" that
finds the actual MDNode for a given DITypeRef.

We specialize getFieldAs to return a field that is a reference to a
DIType. To correctly access the base type field of ptr_to_member,
getClassType now calls getFieldAs<DITypeRef> to return a DITypeRef.

Also add a typedef for DITypeIdentifierMap and a helper
generateDITypeIdentifierMap in DebugInfo.h. In DwarfDebug.cpp, we keep
a DITypeIdentifierMap and call generateDITypeIdentifierMap to actually
populate the map.

Verifier is updated accordingly.

llvm-svn: 190081

llvm/include/llvm/DebugInfo.h
llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
llvm/lib/IR/DIBuilder.cpp
llvm/lib/IR/DebugInfo.cpp
llvm/test/DebugInfo/tu-member-pointer.ll [new file with mode: 0644]

index 87ccac1..997d01e 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef LLVM_DEBUGINFO_H
 #define LLVM_DEBUGINFO_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -45,12 +46,19 @@ namespace llvm {
   class DILexicalBlockFile;
   class DIVariable;
   class DIType;
+  class DITypeRef;
   class DIObjCProperty;
 
+  /// Maps from type identifier to the actual MDNode.
+  typedef DenseMap<const MDString *, MDNode*> DITypeIdentifierMap;
+
   /// DIDescriptor - A thin wraper around MDNode to access encoded debug info.
   /// This should not be stored in a container, because the underlying MDNode
   /// may change in certain situations.
   class DIDescriptor {
+    // Befriends DITypeRef so DITypeRef can befriend the protected member
+    // function: getFieldAs<DITypeRef>.
+    friend class DITypeRef;
   public:
     enum {
       FlagPrivate            = 1 << 0,
@@ -143,6 +151,23 @@ namespace llvm {
     void dump() const;
   };
 
+  /// Specialize getFieldAs to handle fields that are references to DITypes.
+  template <>
+  DITypeRef DIDescriptor::getFieldAs<DITypeRef>(unsigned Elt) const;
+
+  /// Represents reference to a DIType, abstracts over direct and
+  /// identifier-based metadata type references.
+  class DITypeRef {
+    friend DITypeRef DIDescriptor::getFieldAs<DITypeRef>(unsigned Elt) const;
+
+    /// TypeVal can be either a MDNode or a MDString, in the latter,
+    /// MDString specifies the type identifier.
+    const Value *TypeVal;
+    explicit DITypeRef(const Value *V);
+  public:
+    DIType resolve(const DITypeIdentifierMap &Map) const;
+  };
+
   /// DISubrange - This is used to represent ranges, for array bounds.
   class DISubrange : public DIDescriptor {
     friend class DIDescriptor;
@@ -296,9 +321,9 @@ namespace llvm {
     /// associated with one.
     MDNode *getObjCProperty() const;
 
-    DIType getClassType() const {
+    DITypeRef getClassType() const {
       assert(getTag() == dwarf::DW_TAG_ptr_to_member_type);
-      return getFieldAs<DIType>(10);
+      return getFieldAs<DITypeRef>(10);
     }
 
     Constant *getConstant() const {
@@ -720,6 +745,9 @@ namespace llvm {
   /// cleanseInlinedVariable - Remove inlined scope from the variable.
   DIVariable cleanseInlinedVariable(MDNode *DV, LLVMContext &VMContext);
 
+  /// Construct DITypeIdentifierMap by going through retained types of each CU.
+  DITypeIdentifierMap generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes);
+
   /// DebugInfoFinder tries to list all debug info MDNodes used in a module. To
   /// list debug info MDNodes used by an instruction, DebugInfoFinder uses
   /// processDeclare, processValue and processLocation to handle DbgDeclareInst,
index 4c95e14..6db54d2 100644 (file)
@@ -905,7 +905,7 @@ void CompileUnit::constructTypeDIE(DIE &Buffer, DIDerivedType DTy) {
 
   if (Tag == dwarf::DW_TAG_ptr_to_member_type)
       addDIEEntry(&Buffer, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4,
-                  getOrCreateTypeDIE(DTy.getClassType()));
+                  getOrCreateTypeDIE(DD->resolve(DTy.getClassType())));
   // Add source line info if available and TyDesc is not a forward declaration.
   if (!DTy.isForwardDecl())
     addSourceLine(&Buffer, DTy);
index f97ddcb..57ad489 100644 (file)
@@ -823,6 +823,7 @@ void DwarfDebug::beginModule() {
   NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu");
   if (!CU_Nodes)
     return;
+  TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes);
 
   // Emit initial sections so we can reference labels later.
   emitSectionLabels();
@@ -2631,3 +2632,8 @@ void DwarfDebug::emitDebugStrDWO() {
   InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(),
                          OffSec, StrSym);
 }
+
+/// Find the MDNode for the given type reference.
+MDNode *DwarfDebug::resolve(DITypeRef TRef) const {
+  return TRef.resolve(TypeIdentifierMap);
+}
index 97a454a..0258fdc 100644 (file)
@@ -450,6 +450,9 @@ class DwarfDebug {
   // Holder for the skeleton information.
   DwarfUnits SkeletonHolder;
 
+  // Maps from a type identifier to the actual MDNode.
+  DITypeIdentifierMap TypeIdentifierMap;
+
 private:
 
   void addScopeVariable(LexicalScope *LS, DbgVariable *Var);
@@ -679,6 +682,10 @@ public:
 
   /// Returns the Dwarf Version.
   unsigned getDwarfVersion() const { return DwarfVersion; }
+
+  /// Find the MDNode for the given type reference.
+  MDNode *resolve(DITypeRef TRef) const;
+
 };
 } // End of namespace llvm
 
index 51e2963..2ff10b5 100644 (file)
@@ -75,6 +75,18 @@ void DIBuilder::finalize() {
   DIType(TempImportedModules).replaceAllUsesWith(IMs);
 }
 
+/// Use the type identifier instead of the actual MDNode if possible,
+/// to help type uniquing. This function returns the identifier if it
+/// exists for the given type, otherwise returns the MDNode.
+static Value *getTypeIdentifier(DIType T) {
+  if (!T.isCompositeType())
+    return T;
+  DICompositeType DTy(T);
+  if (!DTy.getIdentifier())
+    return T;
+  return DTy.getIdentifier();
+}
+
 /// getNonCompileUnitScope - If N is compile unit return NULL otherwise return
 /// N.
 static MDNode *getNonCompileUnitScope(MDNode *N) {
@@ -322,7 +334,7 @@ DIDerivedType DIBuilder::createMemberPointerType(DIType PointeeTy,
     ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset
     ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags
     PointeeTy,
-    Base
+    getTypeIdentifier(Base)
   };
   return DIDerivedType(MDNode::get(VMContext, Elts));
 }
index 9684bd7..d3207ca 100644 (file)
@@ -425,6 +425,17 @@ static bool fieldIsMDString(const MDNode *DbgNode, unsigned Elt) {
   return !Fld || isa<MDString>(Fld);
 }
 
+/// Check if a value can be a TypeRef.
+static bool isTypeRef(const Value *Val) {
+  return !Val || isa<MDString>(Val) || isa<MDNode>(Val);
+}
+
+/// Check if a field at position Elt of a MDNode can be a TypeRef.
+static bool fieldIsTypeRef(const MDNode *DbgNode, unsigned Elt) {
+  Value *Fld = getField(DbgNode, Elt);
+  return isTypeRef(Fld);
+}
+
 /// Verify - Verify that a type descriptor is well formed.
 bool DIType::Verify() const {
   if (!isType())
@@ -470,8 +481,8 @@ bool DIDerivedType::Verify() const {
   if (!fieldIsMDNode(DbgNode, 9))
     return false;
   if (getTag() == dwarf::DW_TAG_ptr_to_member_type)
-    // Make sure ClassType @ field 10 is MDNode.
-    if (!fieldIsMDNode(DbgNode, 10))
+    // Make sure ClassType @ field 10 is a TypeRef.
+    if (!fieldIsTypeRef(DbgNode, 10))
       return false;
 
   return isDerivedType() && DbgNode->getNumOperands() >= 10 &&
@@ -923,6 +934,32 @@ bool llvm::isSubprogramContext(const MDNode *Context) {
   return false;
 }
 
+/// Update DITypeIdentifierMap by going through retained types of each CU.
+DITypeIdentifierMap llvm::generateDITypeIdentifierMap(
+                              const NamedMDNode *CU_Nodes) {
+  DITypeIdentifierMap Map;
+  for (unsigned CUi = 0, CUe = CU_Nodes->getNumOperands(); CUi != CUe; ++CUi) {
+    DICompileUnit CU(CU_Nodes->getOperand(CUi));
+    DIArray Retain = CU.getRetainedTypes();
+    for (unsigned Ti = 0, Te = Retain.getNumElements(); Ti != Te; ++Ti) {
+      if (!Retain.getElement(Ti).isCompositeType())
+        continue;
+      DICompositeType Ty(Retain.getElement(Ti));
+      if (MDString *TypeId = Ty.getIdentifier()) {
+        // Definition has priority over declaration.
+        // Try to insert (TypeId, Ty) to Map.
+        std::pair<DITypeIdentifierMap::iterator, bool> P =
+            Map.insert(std::make_pair(TypeId, Ty));
+        // If TypeId already exists in Map and this is a definition, replace
+        // whatever we had (declaration or definition) with the definition.
+        if (!P.second && !Ty.isForwardDecl())
+          P.first->second = Ty;
+      }
+    }
+  }
+  return Map;
+}
+
 //===----------------------------------------------------------------------===//
 // DebugInfoFinder implementations.
 //===----------------------------------------------------------------------===//
@@ -1378,3 +1415,34 @@ void DIVariable::printExtendedName(raw_ostream &OS) const {
     }
   }
 }
+
+DITypeRef::DITypeRef(const Value *V) : TypeVal(V) {
+  assert(isTypeRef(V) && "DITypeRef should be a MDString or MDNode");
+}
+
+/// Given a DITypeIdentifierMap, tries to find the corresponding
+/// DIType for a DITypeRef.
+DIType DITypeRef::resolve(const DITypeIdentifierMap &Map) const {
+  if (!TypeVal)
+    return NULL;
+
+  if (const MDNode *MD = dyn_cast<MDNode>(TypeVal)) {
+    assert(DIType(MD).isType() &&
+           "MDNode in DITypeRef should be a DIType.");
+    return MD;
+  }
+
+  const MDString *MS = cast<MDString>(TypeVal);
+  // Find the corresponding MDNode.
+  DITypeIdentifierMap::const_iterator Iter = Map.find(MS);
+  assert(Iter != Map.end() && "Identifier not in the type map?");
+  assert(DIType(Iter->second).isType() &&
+         "MDNode in DITypeIdentifierMap should be a DIType.");
+  return Iter->second;
+}
+
+/// Specialize getFieldAs to handle fields that are references to DITypes.
+template <>
+DITypeRef DIDescriptor::getFieldAs<DITypeRef>(unsigned Elt) const {
+  return DITypeRef(getField(DbgNode, Elt));
+}
diff --git a/llvm/test/DebugInfo/tu-member-pointer.ll b/llvm/test/DebugInfo/tu-member-pointer.ll
new file mode 100644 (file)
index 0000000..b8f6719
--- /dev/null
@@ -0,0 +1,29 @@
+; REQUIRES: object-emission
+
+; RUN: llc -filetype=obj -O0 < %s > %t
+; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
+; CHECK: [[TYPE:.*]]:   DW_TAG_base_type
+; CHECK: DW_TAG_ptr_to_member_type
+; CHECK-NEXT: DW_AT_type [DW_FORM_ref4]       (cu + {{.*}} => {[[TYPE]]})
+; IR generated from clang -g with the following source:
+; struct Foo {
+;   int e;
+; };
+; int Foo:*x = 0;
+
+@x = global i64 -1, align 8
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10}
+
+!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.4", i1 false, metadata !"", i32 0, metadata !2, metadata !3, metadata !2, metadata !5, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [foo.cpp] [DW_LANG_C_plus_plus]
+!1 = metadata !{metadata !"foo.cpp", metadata !"."}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786451, metadata !1, null, metadata !"Foo", i32 1, i64 0, i64 0, i32 0, i32 4, null, null, i32 0, null, null, metadata !"_ZTS3Foo"} ; [ DW_TAG_structure_type ] [Foo] [line 1, size 0, align 0, offset 0] [decl] [from ]
+!5 = metadata !{metadata !6}
+!6 = metadata !{i32 786484, i32 0, null, metadata !"x", metadata !"x", metadata !"", metadata !7, i32 4, metadata !8, i32 0, i32 1, i64* @x, null} ; [ DW_TAG_variable ] [x] [line 4] [def]
+!7 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [foo.cpp]
+!8 = metadata !{i32 786463, null, null, null, i32 0, i64 0, i64 0, i64 0, i32 0, metadata !9, metadata !"_ZTS3Foo"} ; [ DW_TAG_ptr_to_member_type ] [line 0, size 0, align 0, offset 0] [from int]
+!9 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!10 = metadata !{i32 2, metadata !"Dwarf Version", i32 2}