[llvm] r266786 - IR: Enable debug info type ODR uniquing for forward decls

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 19 11:00:19 PDT 2016


Author: dexonsmith
Date: Tue Apr 19 13:00:19 2016
New Revision: 266786

URL: http://llvm.org/viewvc/llvm-project?rev=266786&view=rev
Log:
IR: Enable debug info type ODR uniquing for forward decls

Add a new method, DICompositeType::buildODRType, that will create or
mutate the DICompositeType for a given ODR identifier, and use it in
LLParser and BitcodeReader instead of DICompositeType::getODRType.

The logic is as follows:

  - If there's no node, create one with the given arguments.
  - Else, if the current node is a forward declaration and the new
    arguments would create a definition, mutate the node to match the
    new arguments.
  - Else, return the old node.

This adds a missing feature supported by the current DITypeIdentifierMap
(which I'm slowly making redudant).  The only remaining difference is
that the DITypeIdentifierMap has a "the-last-one-wins" rule, whereas
DICompositeType::buildODRType has a "the-first-one-wins" rule.

For now I'm leaving behind DICompositeType::getODRType since it has
obvious, low-level semantics that are convenient for unit testing.

Modified:
    llvm/trunk/include/llvm/IR/DebugInfoMetadata.h
    llvm/trunk/lib/AsmParser/LLParser.cpp
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/trunk/lib/IR/DebugInfoMetadata.cpp
    llvm/trunk/test/Linker/Inputs/dicompositetype-unique.ll
    llvm/trunk/test/Linker/dicompositetype-unique.ll
    llvm/trunk/unittests/IR/DebugTypeODRUniquingTest.cpp

Modified: llvm/trunk/include/llvm/IR/DebugInfoMetadata.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/DebugInfoMetadata.h?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/DebugInfoMetadata.h (original)
+++ llvm/trunk/include/llvm/IR/DebugInfoMetadata.h Tue Apr 19 13:00:19 2016
@@ -175,6 +175,9 @@ protected:
     return MDString::get(Context, S);
   }
 
+  /// Allow subclasses to mutate the tag.
+  void setTag(unsigned Tag) { SubclassData16 = Tag; }
+
 public:
   unsigned getTag() const { return SubclassData16; }
 
@@ -530,11 +533,28 @@ protected:
   DIType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag,
          unsigned Line, uint64_t SizeInBits, uint64_t AlignInBits,
          uint64_t OffsetInBits, unsigned Flags, ArrayRef<Metadata *> Ops)
-      : DIScope(C, ID, Storage, Tag, Ops), Line(Line), Flags(Flags),
-        SizeInBits(SizeInBits), AlignInBits(AlignInBits),
-        OffsetInBits(OffsetInBits) {}
+      : DIScope(C, ID, Storage, Tag, Ops) {
+    init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags);
+  }
   ~DIType() = default;
 
+  void init(unsigned Line, uint64_t SizeInBits, uint64_t AlignInBits,
+            uint64_t OffsetInBits, unsigned Flags) {
+    this->Line = Line;
+    this->Flags = Flags;
+    this->SizeInBits = SizeInBits;
+    this->AlignInBits = AlignInBits;
+    this->OffsetInBits = OffsetInBits;
+  }
+
+  /// Change fields in place.
+  void mutate(unsigned Tag, unsigned Line, uint64_t SizeInBits,
+              uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags) {
+    assert(isDistinct() && "Only distinct nodes can mutate");
+    setTag(Tag);
+    init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags);
+  }
+
 public:
   TempDIType clone() const {
     return TempDIType(cast<DIType>(MDNode::clone().release()));
@@ -770,6 +790,16 @@ class DICompositeType : public DIType {
         RuntimeLang(RuntimeLang) {}
   ~DICompositeType() = default;
 
+  /// Change fields in place.
+  void mutate(unsigned Tag, unsigned Line, unsigned RuntimeLang,
+              uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits,
+              unsigned Flags) {
+    assert(isDistinct() && "Only distinct nodes can mutate");
+    assert(getRawIdentifier() && "Only ODR-uniqued nodes should mutate");
+    this->RuntimeLang = RuntimeLang;
+    DIType::mutate(Tag, Line, SizeInBits, AlignInBits, OffsetInBits, Flags);
+  }
+
   static DICompositeType *
   getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File,
           unsigned Line, DIScopeRef Scope, DITypeRef BaseType,
@@ -842,6 +872,23 @@ public:
   static DICompositeType *getODRTypeIfExists(LLVMContext &Context,
                                              MDString &Identifier);
 
+  /// Build a DICompositeType with the given ODR identifier.
+  ///
+  /// Looks up the mapped DICompositeType for the given ODR \c Identifier.  If
+  /// it doesn't exist, creates a new one.  If it does exist and \a
+  /// isForwardDecl(), and the new arguments would be a definition, mutates the
+  /// the type in place.  In either case, returns the type.
+  ///
+  /// If not \a LLVMContext::isODRUniquingDebugTypes(), this function returns
+  /// nullptr.
+  static DICompositeType *
+  buildODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag,
+               MDString *Name, Metadata *File, unsigned Line, Metadata *Scope,
+               Metadata *BaseType, uint64_t SizeInBits, uint64_t AlignInBits,
+               uint64_t OffsetInBits, unsigned Flags, Metadata *Elements,
+               unsigned RuntimeLang, Metadata *VTableHolder,
+               Metadata *TemplateParams);
+
   DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); }
   DINodeArray getElements() const {
     return cast_or_null<MDTuple>(getRawElements());

Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Tue Apr 19 13:00:19 2016
@@ -3839,10 +3839,9 @@ bool LLParser::ParseDICompositeType(MDNo
   PARSE_MD_FIELDS();
 #undef VISIT_MD_FIELDS
 
-  // If this isn't a forward declaration and it has a UUID, check for it in the
-  // type map in the context.
-  if (!(flags.Val & DINode::FlagFwdDecl) && identifier.Val)
-    if (auto *CT = DICompositeType::getODRType(
+  // If this has an identifier try to build an ODR type.
+  if (identifier.Val)
+    if (auto *CT = DICompositeType::buildODRType(
             Context, *identifier.Val, tag.Val, name.Val, file.Val, line.Val,
             scope.Val, baseType.Val, size.Val, align.Val, offset.Val, flags.Val,
             elements.Val, runtimeLang.Val, vtableHolder.Val,

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Tue Apr 19 13:00:19 2016
@@ -2207,8 +2207,8 @@ std::error_code BitcodeReader::parseMeta
       Metadata *TemplateParams = getMDOrNull(Record[14]);
       auto *Identifier = getMDString(Record[15]);
       DICompositeType *CT = nullptr;
-      if (!(Flags & DINode::FlagFwdDecl) && Identifier)
-        CT = DICompositeType::getODRType(
+      if (Identifier)
+        CT = DICompositeType::buildODRType(
             Context, *Identifier, Tag, Name, File, Line, Scope, BaseType,
             SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
             VTableHolder, TemplateParams);

Modified: llvm/trunk/lib/IR/DebugInfoMetadata.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/DebugInfoMetadata.cpp?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/lib/IR/DebugInfoMetadata.cpp (original)
+++ llvm/trunk/lib/IR/DebugInfoMetadata.cpp Tue Apr 19 13:00:19 2016
@@ -255,6 +255,7 @@ DICompositeType *DICompositeType::getImp
     bool ShouldCreate) {
   assert(isCanonical(Name) && "Expected canonical MDString");
 
+  // Keep this in sync with buildODRType.
   DEFINE_GETIMPL_LOOKUP(
       DICompositeType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits,
                         AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
@@ -266,6 +267,40 @@ DICompositeType *DICompositeType::getImp
                        Ops);
 }
 
+DICompositeType *DICompositeType::buildODRType(
+    LLVMContext &Context, MDString &Identifier, unsigned Tag, MDString *Name,
+    Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType,
+    uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits,
+    unsigned Flags, Metadata *Elements, unsigned RuntimeLang,
+    Metadata *VTableHolder, Metadata *TemplateParams) {
+  assert(!Identifier.getString().empty() && "Expected valid identifier");
+  if (!Context.isODRUniquingDebugTypes())
+    return nullptr;
+  auto *&CT = (*Context.pImpl->DITypeMap)[&Identifier];
+  if (!CT)
+    return CT = DICompositeType::getDistinct(
+               Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits,
+               AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
+               VTableHolder, TemplateParams, &Identifier);
+
+  // Only mutate CT if it's a forward declaration and the new operands aren't.
+  assert(CT->getRawIdentifier() == &Identifier && "Wrong ODR identifier?");
+  if (!CT->isForwardDecl() || (Flags & DINode::FlagFwdDecl))
+    return CT;
+
+  // Mutate CT in place.  Keep this in sync with getImpl.
+  CT->mutate(Tag, Line, RuntimeLang, SizeInBits, AlignInBits, OffsetInBits,
+             Flags);
+  Metadata *Ops[] = {File,     Scope,        Name,           BaseType,
+                     Elements, VTableHolder, TemplateParams, &Identifier};
+  assert(std::end(Ops) - std::begin(Ops) == CT->getNumOperands() &&
+         "Mismatched number of operands");
+  for (unsigned I = 0, E = CT->getNumOperands(); I != E; ++I)
+    if (Ops[I] != CT->getOperand(I))
+      CT->setOperand(I, Ops[I]);
+  return CT;
+}
+
 DICompositeType *DICompositeType::getODRType(
     LLVMContext &Context, MDString &Identifier, unsigned Tag, MDString *Name,
     Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType,

Modified: llvm/trunk/test/Linker/Inputs/dicompositetype-unique.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Linker/Inputs/dicompositetype-unique.ll?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/test/Linker/Inputs/dicompositetype-unique.ll (original)
+++ llvm/trunk/test/Linker/Inputs/dicompositetype-unique.ll Tue Apr 19 13:00:19 2016
@@ -1,4 +1,6 @@
-!named = !{!0, !1}
+!named = !{!0, !1, !2, !3}
 
 !0 = !DIFile(filename: "abc", directory: "/path/to")
 !1 = !DICompositeType(tag: DW_TAG_class_type, name: "T2", identifier: "T", file: !0)
+!2 = !DICompositeType(tag: DW_TAG_class_type, name: "FwdTDef", identifier: "FwdT", file: !0)
+!3 = !DICompositeType(tag: DW_TAG_class_type, flags: DIFlagFwdDecl, name: "BothFwdT2", identifier: "BothFwdT", file: !0)

Modified: llvm/trunk/test/Linker/dicompositetype-unique.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Linker/dicompositetype-unique.ll?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/test/Linker/dicompositetype-unique.ll (original)
+++ llvm/trunk/test/Linker/dicompositetype-unique.ll Tue Apr 19 13:00:19 2016
@@ -17,9 +17,9 @@
 
 ; Check that the type map will unique two DICompositeTypes.
 
-; CHECK:   !named = !{!0, !1, !0, !1}
-; NOMAP:   !named = !{!0, !1, !0, !2}
-!named = !{!0, !1}
+; CHECK:   !named = !{!0, !1, !2, !3, !0, !1, !2, !3}
+; NOMAP:   !named = !{!0, !1, !2, !3, !0, !4, !5, !6}
+!named = !{!0, !1, !2, !3}
 
 ; Check both directions.
 ; CHECK:        !1 = distinct !DICompositeType(
@@ -27,14 +27,39 @@
 ; REVERSE-SAME:                                name: "T2"
 ; CHECK-SAME:                                  identifier: "T"
 ; CHECK-NOT:       identifier: "T"
+; CHECK:        !2 = distinct !DICompositeType(
+; CHECK-SAME:                                  name: "FwdTDef"
+; CHECK-SAME:                                  identifier: "FwdT"
+; CHECK-NOT:       identifier: "FwdT"
+; CHECK:        !3 = distinct !DICompositeType(
+; FORWARD-SAME:                                name: "BothFwdT1"
+; REVERSE-SAME:                                name: "BothFwdT2"
+; CHECK-SAME:                                  identifier: "BothFwdT"
+; CHECK-NOT:       identifier: "BothFwdT"
 
 ; These types are different, so we should get both copies when there is no map.
 ; NOMAP:        !1 = !DICompositeType(
 ; NOMAP-SAME:                         name: "T1"
 ; NOMAP-SAME:                         identifier: "T"
 ; NOMAP:        !2 = !DICompositeType(
+; NOMAP-SAME:                         name: "FwdTFwd"
+; NOMAP-SAME:                         identifier: "FwdT"
+; NOMAP:        !3 = !DICompositeType(
+; NOMAP-SAME:                         name: "BothFwdT1"
+; NOMAP-SAME:                         identifier: "BothFwdT"
+; NOMAP:        !4 = !DICompositeType(
 ; NOMAP-SAME:                         name: "T2"
 ; NOMAP-SAME:                         identifier: "T"
 ; NOMAP-NOT:       identifier: "T"
+; NOMAP:        !5 = !DICompositeType(
+; NOMAP-SAME:                         name: "FwdTDef"
+; NOMAP-SAME:                         identifier: "FwdT"
+; NOMAP-NOT:       identifier: "FwdT"
+; NOMAP:        !6 = !DICompositeType(
+; NOMAP-SAME:                         name: "BothFwdT2"
+; NOMAP-SAME:                         identifier: "BothFwdT"
+; NOMAP-NOT:       identifier: "BothFwdT"
 !0 = !DIFile(filename: "abc", directory: "/path/to")
 !1 = !DICompositeType(tag: DW_TAG_class_type, name: "T1", identifier: "T", file: !0)
+!2 = !DICompositeType(tag: DW_TAG_class_type, flags: DIFlagFwdDecl, name: "FwdTFwd", identifier: "FwdT", file: !0)
+!3 = !DICompositeType(tag: DW_TAG_class_type, flags: DIFlagFwdDecl, name: "BothFwdT1", identifier: "BothFwdT", file: !0)

Modified: llvm/trunk/unittests/IR/DebugTypeODRUniquingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/DebugTypeODRUniquingTest.cpp?rev=266786&r1=266785&r2=266786&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/DebugTypeODRUniquingTest.cpp (original)
+++ llvm/trunk/unittests/IR/DebugTypeODRUniquingTest.cpp Tue Apr 19 13:00:19 2016
@@ -62,4 +62,95 @@ TEST(DebugTypeODRUniquingTest, getODRTyp
   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
 }
 
+TEST(DebugTypeODRUniquingTest, buildODRType) {
+  LLVMContext Context;
+  Context.enableDebugTypeODRUniquing();
+
+  // Build an ODR type that's a forward decl.
+  MDString &UUID = *MDString::get(Context, "Type");
+  auto &CT = *DICompositeType::buildODRType(
+      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
+      nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr);
+  EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
+  EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());
+
+  // Update with another forward decl.  This should be a no-op.
+  EXPECT_EQ(&CT, DICompositeType::buildODRType(
+      Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,
+      nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr));
+  EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());
+
+  // Update with a definition.  This time we should see a change.
+  EXPECT_EQ(&CT, DICompositeType::buildODRType(
+      Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,
+      nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr));
+  EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
+
+  // Further updates should be ignored.
+  EXPECT_EQ(&CT, DICompositeType::buildODRType(
+      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
+      nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr));
+  EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
+  EXPECT_EQ(&CT, DICompositeType::buildODRType(
+      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
+      nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr));
+  EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
+}
+
+TEST(DebugTypeODRUniquingTest, buildODRTypeFields) {
+  LLVMContext Context;
+  Context.enableDebugTypeODRUniquing();
+
+  // Build an ODR type that's a forward decl with no other fields set.
+  MDString &UUID = *MDString::get(Context, "UUID");
+  auto &CT = *DICompositeType::buildODRType(
+      Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0,
+      DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr);
+
+// Create macros for running through all the fields except Identifier and Flags.
+#define FOR_EACH_MDFIELD()                                                     \
+  DO_FOR_FIELD(Name)                                                           \
+  DO_FOR_FIELD(File)                                                           \
+  DO_FOR_FIELD(Scope)                                                          \
+  DO_FOR_FIELD(BaseType)                                                       \
+  DO_FOR_FIELD(Elements)                                                       \
+  DO_FOR_FIELD(VTableHolder)                                                   \
+  DO_FOR_FIELD(TemplateParams)
+#define FOR_EACH_INLINEFIELD()                                                 \
+  DO_FOR_FIELD(Tag)                                                            \
+  DO_FOR_FIELD(Line)                                                           \
+  DO_FOR_FIELD(SizeInBits)                                                     \
+  DO_FOR_FIELD(AlignInBits)                                                    \
+  DO_FOR_FIELD(OffsetInBits)                                                   \
+  DO_FOR_FIELD(RuntimeLang)
+
+// Create all the fields.
+#define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X);
+  FOR_EACH_MDFIELD();
+#undef DO_FOR_FIELD
+  unsigned NonZeroInit = 0;
+#define DO_FOR_FIELD(X) auto X = ++NonZeroInit;
+  FOR_EACH_INLINEFIELD();
+#undef DO_FOR_FIELD
+
+  // Replace all the fields with new values that are distinct from each other.
+  EXPECT_EQ(&CT,
+            DICompositeType::buildODRType(
+                Context, UUID, Tag, Name, File, Line, Scope, BaseType,
+                SizeInBits, AlignInBits, OffsetInBits, DINode::FlagArtificial,
+                Elements, RuntimeLang, VTableHolder, TemplateParams));
+
+  // Confirm that all the right fields got updated.
+#define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X());
+  FOR_EACH_MDFIELD();
+#undef DO_FOR_FIELD
+#undef FOR_EACH_MDFIELD
+#define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X());
+  FOR_EACH_INLINEFIELD();
+#undef DO_FOR_FIELD
+#undef FOR_EACH_INLINEFIELD
+  EXPECT_EQ(DINode::FlagArtificial, CT.getFlags());
+  EXPECT_EQ(&UUID, CT.getRawIdentifier());
+}
+
 } // end namespace




More information about the llvm-commits mailing list