IR / debug info: Add a DWOId field to DICompileUnit,
authorAdrian Prantl <aprantl@apple.com>
Thu, 21 May 2015 20:37:30 +0000 (20:37 +0000)
committerAdrian Prantl <aprantl@apple.com>
Thu, 21 May 2015 20:37:30 +0000 (20:37 +0000)
so DWARF skeleton CUs can be expression in IR. A skeleton CU is a
(typically empty) DW_TAG_compile_unit that has a DW_AT_(GNU)_dwo_name and
a DW_AT_(GNU)_dwo_id attribute. It is used to refer to external debug info.

This is a prerequisite for clang module debugging as discussed in
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-November/040076.html.
In order to refer to external types stored in split DWARF (dwo) objects,
such as clang modules, we need to emit skeleton CUs, which identify the
dwarf object (i.e., the clang module) by filename (the SplitDebugFilename)
and a hash value, the dwo_id.

This patch only contains the IR changes. The idea is that a CUs with a
non-zero dwo_id field will be emitted together with a DW_AT_GNU_dwo_name
and DW_AT_GNU_dwo_id attribute.

http://reviews.llvm.org/D9488
rdar://problem/20091852

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237949 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/llvm/IR/DIBuilder.h
include/llvm/IR/DebugInfoMetadata.h
lib/AsmParser/LLParser.cpp
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/IR/AsmWriter.cpp
lib/IR/DIBuilder.cpp
lib/IR/DebugInfoMetadata.cpp
lib/IR/LLVMContextImpl.h
test/Assembler/mdcompileunit.ll
test/Bitcode/DICompileUnit-no-DWOId.ll [new file with mode: 0644]
test/Bitcode/DICompileUnit-no-DWOId.ll.bc [new file with mode: 0644]
unittests/IR/MetadataTest.cpp

index 68fb59b20199cc1267a7cf70819496b50c15f9f3..997113191d196d8a6dc2876dbb00d3c9e8c24145 100644 (file)
@@ -95,6 +95,7 @@ namespace llvm {
     /// @param SplitName The name of the file that we'll split debug info out
     ///                  into.
     /// @param Kind     The kind of debug information to generate.
+    /// @param DWOId    The DWOId if this is a split skeleton compile unit.
     /// @param EmitDebugInfo   A boolean flag which indicates whether debug
     ///                        information should be written to the final
     ///                        output or not. When this is false, debug
@@ -104,12 +105,12 @@ namespace llvm {
     ///                        source location information in the back end
     ///                        without actually changing the output (e.g.,
     ///                        when using optimization remarks).
-    DICompileUnit *createCompileUnit(unsigned Lang, StringRef File,
-                                     StringRef Dir, StringRef Producer,
-                                     bool isOptimized, StringRef Flags,
-                                     unsigned RV, StringRef SplitName = "",
-                                     DebugEmissionKind Kind = FullDebug,
-                                     bool EmitDebugInfo = true);
+    DICompileUnit *
+    createCompileUnit(unsigned Lang, StringRef File, StringRef Dir,
+                      StringRef Producer, bool isOptimized, StringRef Flags,
+                      unsigned RV, StringRef SplitName = StringRef(),
+                      DebugEmissionKind Kind = FullDebug, uint64_t DWOId = 0,
+                      bool EmitDebugInfo = true);
 
     /// createFile - Create a file descriptor to hold debugging information
     /// for a file.
index 2be5e9349e167e203a61bfd3f09dc809d2f6649d..0125de5d40f5437adeb7c01db82f1d50bd6dc987 100644 (file)
@@ -971,13 +971,15 @@ class DICompileUnit : public DIScope {
   bool IsOptimized;
   unsigned RuntimeVersion;
   unsigned EmissionKind;
+  uint64_t DWOId;
 
   DICompileUnit(LLVMContext &C, StorageType Storage, unsigned SourceLanguage,
                 bool IsOptimized, unsigned RuntimeVersion,
-                unsigned EmissionKind, ArrayRef<Metadata *> Ops)
+                unsigned EmissionKind, uint64_t DWOId, ArrayRef<Metadata *> Ops)
       : DIScope(C, DICompileUnitKind, Storage, dwarf::DW_TAG_compile_unit, Ops),
         SourceLanguage(SourceLanguage), IsOptimized(IsOptimized),
-        RuntimeVersion(RuntimeVersion), EmissionKind(EmissionKind) {}
+        RuntimeVersion(RuntimeVersion), EmissionKind(EmissionKind),
+        DWOId(DWOId) {}
   ~DICompileUnit() = default;
 
   static DICompileUnit *
@@ -987,14 +989,15 @@ class DICompileUnit : public DIScope {
           unsigned EmissionKind, DICompositeTypeArray EnumTypes,
           DITypeArray RetainedTypes, DISubprogramArray Subprograms,
           DIGlobalVariableArray GlobalVariables,
-          DIImportedEntityArray ImportedEntities, StorageType Storage,
-          bool ShouldCreate = true) {
-    return getImpl(
-        Context, SourceLanguage, File, getCanonicalMDString(Context, Producer),
-        IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion,
-        getCanonicalMDString(Context, SplitDebugFilename), EmissionKind,
-        EnumTypes.get(), RetainedTypes.get(), Subprograms.get(),
-        GlobalVariables.get(), ImportedEntities.get(), Storage, ShouldCreate);
+          DIImportedEntityArray ImportedEntities, uint64_t DWOId,
+          StorageType Storage, bool ShouldCreate = true) {
+    return getImpl(Context, SourceLanguage, File,
+                   getCanonicalMDString(Context, Producer), IsOptimized,
+                   getCanonicalMDString(Context, Flags), RuntimeVersion,
+                   getCanonicalMDString(Context, SplitDebugFilename),
+                   EmissionKind, EnumTypes.get(), RetainedTypes.get(),
+                   Subprograms.get(), GlobalVariables.get(),
+                   ImportedEntities.get(), DWOId, Storage, ShouldCreate);
   }
   static DICompileUnit *
   getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File,
@@ -1002,7 +1005,7 @@ class DICompileUnit : public DIScope {
           unsigned RuntimeVersion, MDString *SplitDebugFilename,
           unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes,
           Metadata *Subprograms, Metadata *GlobalVariables,
-          Metadata *ImportedEntities, StorageType Storage,
+          Metadata *ImportedEntities, uint64_t DWOId, StorageType Storage,
           bool ShouldCreate = true);
 
   TempDICompileUnit cloneImpl() const {
@@ -1010,7 +1013,7 @@ class DICompileUnit : public DIScope {
         getContext(), getSourceLanguage(), getFile(), getProducer(),
         isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(),
         getEmissionKind(), getEnumTypes(), getRetainedTypes(), getSubprograms(),
-        getGlobalVariables(), getImportedEntities());
+        getGlobalVariables(), getImportedEntities(), DWOId);
   }
 
 public:
@@ -1021,22 +1024,21 @@ public:
                      DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes,
                      DISubprogramArray Subprograms,
                      DIGlobalVariableArray GlobalVariables,
-                     DIImportedEntityArray ImportedEntities),
-                    (SourceLanguage, File, Producer, IsOptimized, Flags,
-                     RuntimeVersion, SplitDebugFilename, EmissionKind,
-                     EnumTypes, RetainedTypes, Subprograms, GlobalVariables,
-                     ImportedEntities))
-  DEFINE_MDNODE_GET(DICompileUnit,
-                    (unsigned SourceLanguage, Metadata *File,
-                     MDString *Producer, bool IsOptimized, MDString *Flags,
-                     unsigned RuntimeVersion, MDString *SplitDebugFilename,
-                     unsigned EmissionKind, Metadata *EnumTypes,
-                     Metadata *RetainedTypes, Metadata *Subprograms,
-                     Metadata *GlobalVariables, Metadata *ImportedEntities),
+                     DIImportedEntityArray ImportedEntities, uint64_t DWOId),
                     (SourceLanguage, File, Producer, IsOptimized, Flags,
                      RuntimeVersion, SplitDebugFilename, EmissionKind,
                      EnumTypes, RetainedTypes, Subprograms, GlobalVariables,
-                     ImportedEntities))
+                     ImportedEntities, DWOId))
+  DEFINE_MDNODE_GET(
+      DICompileUnit,
+      (unsigned SourceLanguage, Metadata *File, MDString *Producer,
+       bool IsOptimized, MDString *Flags, unsigned RuntimeVersion,
+       MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes,
+       Metadata *RetainedTypes, Metadata *Subprograms,
+       Metadata *GlobalVariables, Metadata *ImportedEntities, uint64_t DWOId),
+      (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion,
+       SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms,
+       GlobalVariables, ImportedEntities, DWOId))
 
   TempDICompileUnit clone() const { return cloneImpl(); }
 
@@ -1062,6 +1064,7 @@ public:
   DIImportedEntityArray getImportedEntities() const {
     return cast_or_null<MDTuple>(getRawImportedEntities());
   }
+  unsigned getDWOId() const { return DWOId; }
 
   MDString *getRawProducer() const { return getOperandAs<MDString>(1); }
   MDString *getRawFlags() const { return getOperandAs<MDString>(2); }
index ef464c339f762635e46d6b63f01d7ec60d1bf524..d3c8ffd2fef94f797628a84e24d5b8cbf470e342 100644 (file)
@@ -3547,7 +3547,7 @@ bool LLParser::ParseDIFile(MDNode *&Result, bool IsDistinct) {
 ///                      isOptimized: true, flags: "-O2", runtimeVersion: 1,
 ///                      splitDebugFilename: "abc.debug", emissionKind: 1,
 ///                      enums: !1, retainedTypes: !2, subprograms: !3,
-///                      globals: !4, imports: !5)
+///                      globals: !4, imports: !5, dwoId: 0x0abcd)
 bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
 #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED)                                    \
   REQUIRED(language, DwarfLangField, );                                        \
@@ -3562,7 +3562,8 @@ bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
   OPTIONAL(retainedTypes, MDField, );                                          \
   OPTIONAL(subprograms, MDField, );                                            \
   OPTIONAL(globals, MDField, );                                                \
-  OPTIONAL(imports, MDField, );
+  OPTIONAL(imports, MDField, );                                                \
+  OPTIONAL(dwoId, MDUnsignedField, );
   PARSE_MD_FIELDS();
 #undef VISIT_MD_FIELDS
 
@@ -3571,7 +3572,7 @@ bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
                             isOptimized.Val, flags.Val, runtimeVersion.Val,
                             splitDebugFilename.Val, emissionKind.Val, enums.Val,
                             retainedTypes.Val, subprograms.Val, globals.Val,
-                            imports.Val));
+                            imports.Val, dwoId.Val));
   return false;
 }
 
index bba29172a28c6208dc3b3491ae672fa5ab9a5ec4..6eef594eaf1977e7d06f082505bd94b9f919b09e 100644 (file)
@@ -1844,7 +1844,7 @@ std::error_code BitcodeReader::ParseMetadata() {
       break;
     }
     case bitc::METADATA_COMPILE_UNIT: {
-      if (Record.size() != 14)
+      if (Record.size() < 14 || Record.size() > 15)
         return Error("Invalid record");
 
       MDValueList.AssignValue(
@@ -1855,7 +1855,8 @@ std::error_code BitcodeReader::ParseMetadata() {
                            getMDString(Record[7]), Record[8],
                            getMDOrNull(Record[9]), getMDOrNull(Record[10]),
                            getMDOrNull(Record[11]), getMDOrNull(Record[12]),
-                           getMDOrNull(Record[13]))),
+                           getMDOrNull(Record[13]),
+                           Record.size() == 14 ? 0 : Record[14])),
           NextMDValueNo++);
       break;
     }
index 199663d1bfd881843ce6a749c79cd848bcc88c04..3a539e12926d2b9bae1c3ba51bc73844b67d6f81 100644 (file)
@@ -949,6 +949,7 @@ static void WriteDICompileUnit(const DICompileUnit *N,
   Record.push_back(VE.getMetadataOrNullID(N->getSubprograms().get()));
   Record.push_back(VE.getMetadataOrNullID(N->getGlobalVariables().get()));
   Record.push_back(VE.getMetadataOrNullID(N->getImportedEntities().get()));
+  Record.push_back(N->getDWOId());
 
   Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev);
   Record.clear();
index 304221af400c6d054b6526b31ab192325495cec4..1089cb582180d383c0f7bbc56f0e28cda367e50c 100644 (file)
@@ -1624,6 +1624,7 @@ static void writeDICompileUnit(raw_ostream &Out, const DICompileUnit *N,
   Printer.printMetadata("subprograms", N->getRawSubprograms());
   Printer.printMetadata("globals", N->getRawGlobalVariables());
   Printer.printMetadata("imports", N->getRawImportedEntities());
+  Printer.printInt("dwoId", N->getDWOId());
   Out << ")";
 }
 
index 3baa468090554b60ee68ad3044872895c0bd3f4d..b1925ea5c48f66e43ebf5cc17e8312c25622e1fe 100644 (file)
@@ -125,7 +125,7 @@ static DIScope *getNonCompileUnitScope(DIScope *N) {
 DICompileUnit *DIBuilder::createCompileUnit(
     unsigned Lang, StringRef Filename, StringRef Directory, StringRef Producer,
     bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName,
-    DebugEmissionKind Kind, bool EmitDebugInfo) {
+    DebugEmissionKind Kind, uint64_t DWOId, bool EmitDebugInfo) {
 
   assert(((Lang <= dwarf::DW_LANG_Fortran08 && Lang >= dwarf::DW_LANG_C89) ||
           (Lang <= dwarf::DW_LANG_hi_user && Lang >= dwarf::DW_LANG_lo_user)) &&
@@ -147,7 +147,7 @@ DICompileUnit *DIBuilder::createCompileUnit(
       VMContext, Lang, DIFile::get(VMContext, Filename, Directory), Producer,
       isOptimized, Flags, RunTimeVer, SplitName, Kind, TempEnumTypes.get(),
       TempRetainTypes.get(), TempSubprograms.get(), TempGVs.get(),
-      TempImportedModules.get());
+      TempImportedModules.get(), DWOId);
 
   // Create a named metadata so that it is easier to find cu in a module.
   // Note that we only generate this when the caller wants to actually
index 85335d547b195459f2902f3fafcf30ee3cd9f44e..8b9857d373b92dacb8898cb5b5b0b59dac96b369 100644 (file)
@@ -311,7 +311,8 @@ DICompileUnit *DICompileUnit::getImpl(
     unsigned RuntimeVersion, MDString *SplitDebugFilename,
     unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes,
     Metadata *Subprograms, Metadata *GlobalVariables,
-    Metadata *ImportedEntities, StorageType Storage, bool ShouldCreate) {
+    Metadata *ImportedEntities, uint64_t DWOId,
+    StorageType Storage, bool ShouldCreate) {
   assert(isCanonical(Producer) && "Expected canonical MDString");
   assert(isCanonical(Flags) && "Expected canonical MDString");
   assert(isCanonical(SplitDebugFilename) && "Expected canonical MDString");
@@ -319,13 +320,13 @@ DICompileUnit *DICompileUnit::getImpl(
       DICompileUnit,
       (SourceLanguage, File, getString(Producer), IsOptimized, getString(Flags),
        RuntimeVersion, getString(SplitDebugFilename), EmissionKind, EnumTypes,
-       RetainedTypes, Subprograms, GlobalVariables, ImportedEntities));
+       RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, DWOId));
   Metadata *Ops[] = {File, Producer, Flags, SplitDebugFilename, EnumTypes,
                      RetainedTypes, Subprograms, GlobalVariables,
                      ImportedEntities};
   DEFINE_GETIMPL_STORE(
       DICompileUnit,
-      (SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind), Ops);
+      (SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind, DWOId), Ops);
 }
 
 DISubprogram *DILocalScope::getSubprogram() const {
index 95292509f505b3bb228d838d673b8b6065ce666f..f81db6077704dc4506535fbbb2d81b7177cd77a9 100644 (file)
@@ -472,19 +472,20 @@ template <> struct MDNodeKeyImpl<DICompileUnit> {
   Metadata *Subprograms;
   Metadata *GlobalVariables;
   Metadata *ImportedEntities;
+  uint64_t DWOId;
 
   MDNodeKeyImpl(unsigned SourceLanguage, Metadata *File, StringRef Producer,
                 bool IsOptimized, StringRef Flags, unsigned RuntimeVersion,
                 StringRef SplitDebugFilename, unsigned EmissionKind,
                 Metadata *EnumTypes, Metadata *RetainedTypes,
                 Metadata *Subprograms, Metadata *GlobalVariables,
-                Metadata *ImportedEntities)
+                Metadata *ImportedEntities, uint64_t DWOId)
       : SourceLanguage(SourceLanguage), File(File), Producer(Producer),
         IsOptimized(IsOptimized), Flags(Flags), RuntimeVersion(RuntimeVersion),
         SplitDebugFilename(SplitDebugFilename), EmissionKind(EmissionKind),
         EnumTypes(EnumTypes), RetainedTypes(RetainedTypes),
         Subprograms(Subprograms), GlobalVariables(GlobalVariables),
-        ImportedEntities(ImportedEntities) {}
+        ImportedEntities(ImportedEntities), DWOId(DWOId) {}
   MDNodeKeyImpl(const DICompileUnit *N)
       : SourceLanguage(N->getSourceLanguage()), File(N->getRawFile()),
         Producer(N->getProducer()), IsOptimized(N->isOptimized()),
@@ -494,7 +495,7 @@ template <> struct MDNodeKeyImpl<DICompileUnit> {
         RetainedTypes(N->getRawRetainedTypes()),
         Subprograms(N->getRawSubprograms()),
         GlobalVariables(N->getRawGlobalVariables()),
-        ImportedEntities(N->getRawImportedEntities()) {}
+        ImportedEntities(N->getRawImportedEntities()), DWOId(N->getDWOId()) {}
 
   bool isKeyOf(const DICompileUnit *RHS) const {
     return SourceLanguage == RHS->getSourceLanguage() &&
@@ -507,13 +508,14 @@ template <> struct MDNodeKeyImpl<DICompileUnit> {
            RetainedTypes == RHS->getRawRetainedTypes() &&
            Subprograms == RHS->getRawSubprograms() &&
            GlobalVariables == RHS->getRawGlobalVariables() &&
-           ImportedEntities == RHS->getRawImportedEntities();
+           ImportedEntities == RHS->getRawImportedEntities() &&
+           DWOId == RHS->getDWOId();
   }
   unsigned getHashValue() const {
     return hash_combine(SourceLanguage, File, Producer, IsOptimized, Flags,
                         RuntimeVersion, SplitDebugFilename, EmissionKind,
                         EnumTypes, RetainedTypes, Subprograms, GlobalVariables,
-                        ImportedEntities);
+                        ImportedEntities, DWOId);
   }
 };
 
index 9445c80e76ba7918f61ac2059e33c6c69279f749..dc136f0b83e9aa1f75c496f8dcbecb1d87204048 100644 (file)
 !5 = distinct !{}
 !6 = distinct !{}
 
-; CHECK: !7 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, flags: "-O2", runtimeVersion: 2, splitDebugFilename: "abc.debug", emissionKind: 3, enums: !2, retainedTypes: !3, subprograms: !4, globals: !5, imports: !6)
+; CHECK: !7 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, flags: "-O2", runtimeVersion: 2, splitDebugFilename: "abc.debug", emissionKind: 3, enums: !2, retainedTypes: !3, subprograms: !4, globals: !5, imports: !6, dwoId: 42)
 !7 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang",
                     isOptimized: true, flags: "-O2", runtimeVersion: 2,
                     splitDebugFilename: "abc.debug", emissionKind: 3,
                     enums: !2, retainedTypes: !3, subprograms: !4,
-                    globals: !5, imports: !6)
+                    globals: !5, imports: !6, dwoId: 42)
 !8 = !DICompileUnit(language: 12, file: !1, producer: "clang",
                     isOptimized: true, flags: "-O2", runtimeVersion: 2,
                     splitDebugFilename: "abc.debug", emissionKind: 3,
                     enums: !2, retainedTypes: !3, subprograms: !4,
-                    globals: !5, imports: !6)
+                    globals: !5, imports: !6, dwoId: 42)
 
 ; CHECK: !8 = !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: 0)
 !9 = !DICompileUnit(language: 12, file: !1, producer: "",
diff --git a/test/Bitcode/DICompileUnit-no-DWOId.ll b/test/Bitcode/DICompileUnit-no-DWOId.ll
new file mode 100644 (file)
index 0000000..4771c37
--- /dev/null
@@ -0,0 +1,9 @@
+; The input uses the older (r236428) form without a dwoId field.  This should
+; default to 0, which is not displayed at all in the textual representation.
+;
+; RUN: llvm-dis %s.bc -o - | FileCheck %s
+; CHECK: !DICompileUnit
+; CHECK-NOT: dwoId:
+!named = !{!0}
+!0 = !DICompileUnit(language: 12, file: !1)
+!1 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
diff --git a/test/Bitcode/DICompileUnit-no-DWOId.ll.bc b/test/Bitcode/DICompileUnit-no-DWOId.ll.bc
new file mode 100644 (file)
index 0000000..1a3c99b
Binary files /dev/null and b/test/Bitcode/DICompileUnit-no-DWOId.ll.bc differ
index baba3e5bc5253fff1fcce881df42364354f01e47..6994e2133f6f06228298042addbab004561c6369 100644 (file)
@@ -1294,10 +1294,11 @@ TEST_F(DICompileUnitTest, get) {
   MDTuple *Subprograms = getTuple();
   MDTuple *GlobalVariables = getTuple();
   MDTuple *ImportedEntities = getTuple();
+  uint64_t DWOId = 0xc0ffee;
   auto *N = DICompileUnit::get(
       Context, SourceLanguage, File, Producer, IsOptimized, Flags,
       RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
-      RetainedTypes, Subprograms, GlobalVariables, ImportedEntities);
+      RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, DWOId);
 
   EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag());
   EXPECT_EQ(SourceLanguage, N->getSourceLanguage());
@@ -1313,74 +1314,83 @@ TEST_F(DICompileUnitTest, get) {
   EXPECT_EQ(Subprograms, N->getSubprograms().get());
   EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get());
   EXPECT_EQ(ImportedEntities, N->getImportedEntities().get());
+  EXPECT_EQ(DWOId, N->getDWOId());
   EXPECT_EQ(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
+                                  ImportedEntities, DWOId));
 
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage + 1, File, Producer,
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, getFile(), Producer,
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, "other",
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   !IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   IsOptimized, "other", RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   IsOptimized, Flags, RuntimeVersion + 1,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
-  EXPECT_NE(N,
-            DICompileUnit::get(Context, SourceLanguage, File, Producer,
-                               IsOptimized, Flags, RuntimeVersion, "other",
-                               EmissionKind, EnumTypes, RetainedTypes,
-                               Subprograms, GlobalVariables, ImportedEntities));
+                                  ImportedEntities, DWOId));
+  EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
+                                  IsOptimized, Flags, RuntimeVersion, "other",
+                                  EmissionKind, EnumTypes, RetainedTypes,
+                                  Subprograms, GlobalVariables,
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind + 1,
                                   EnumTypes, RetainedTypes, Subprograms,
-                                  GlobalVariables, ImportedEntities));
+                                  GlobalVariables, ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, getTuple(),
                                   RetainedTypes, Subprograms, GlobalVariables,
-                                  ImportedEntities));
-  EXPECT_NE(N, DICompileUnit::get(
-                   Context, SourceLanguage, File, Producer, IsOptimized, Flags,
-                   RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
-                   getTuple(), Subprograms, GlobalVariables, ImportedEntities));
+                                  ImportedEntities, DWOId));
+  EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
+                                  IsOptimized, Flags, RuntimeVersion,
+                                  SplitDebugFilename, EmissionKind, EnumTypes,
+                                  getTuple(), Subprograms, GlobalVariables,
+                                  ImportedEntities, DWOId));
   EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
                                   IsOptimized, Flags, RuntimeVersion,
                                   SplitDebugFilename, EmissionKind, EnumTypes,
                                   RetainedTypes, getTuple(), GlobalVariables,
-                                  ImportedEntities));
-  EXPECT_NE(N, DICompileUnit::get(
-                   Context, SourceLanguage, File, Producer, IsOptimized, Flags,
-                   RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
-                   RetainedTypes, Subprograms, getTuple(), ImportedEntities));
-  EXPECT_NE(N, DICompileUnit::get(
-                   Context, SourceLanguage, File, Producer, IsOptimized, Flags,
-                   RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
-                   RetainedTypes, Subprograms, GlobalVariables, getTuple()));
+                                  ImportedEntities, DWOId));
+  EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
+                                  IsOptimized, Flags, RuntimeVersion,
+                                  SplitDebugFilename, EmissionKind, EnumTypes,
+                                  RetainedTypes, Subprograms, getTuple(),
+                                  ImportedEntities, DWOId));
+  EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
+                                  IsOptimized, Flags, RuntimeVersion,
+                                  SplitDebugFilename, EmissionKind, EnumTypes,
+                                  RetainedTypes, Subprograms, GlobalVariables,
+                                  getTuple(), DWOId));
+  EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer,
+                                  IsOptimized, Flags, RuntimeVersion,
+                                  SplitDebugFilename, EmissionKind, EnumTypes,
+                                  RetainedTypes, Subprograms, GlobalVariables,
+                                  ImportedEntities, DWOId + 1));
 
   TempDICompileUnit Temp = N->clone();
   EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
@@ -1398,10 +1408,11 @@ TEST_F(DICompileUnitTest, replaceArrays) {
   MDTuple *EnumTypes = MDTuple::getDistinct(Context, None);
   MDTuple *RetainedTypes = MDTuple::getDistinct(Context, None);
   MDTuple *ImportedEntities = MDTuple::getDistinct(Context, None);
+  uint64_t DWOId = 0xc0ffee;
   auto *N = DICompileUnit::get(
       Context, SourceLanguage, File, Producer, IsOptimized, Flags,
       RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
-      RetainedTypes, nullptr, nullptr, ImportedEntities);
+      RetainedTypes, nullptr, nullptr, ImportedEntities, DWOId);
 
   auto *Subprograms = MDTuple::getDistinct(Context, None);
   EXPECT_EQ(nullptr, N->getSubprograms().get());