llvm.org GIT mirror llvm / 9bb5d5d
IR: Use an explicit map for debug info type uniquing Rather than relying on the structural equivalence of DICompositeType to merge type definitions, use an explicit map on the LLVMContext that LLParser and BitcodeReader consult when constructing new nodes. Each non-forward-declaration DICompositeType with a non-empty 'identifier:' field is stored/loaded from the type map, and the first definiton will "win". This map is opt-in: clients that expect ODR types from different modules to be merged must call LLVMContext::ensureDITypeMap. - Clients that just happen to load more than one Module in the same LLVMContext won't magically merge types. - Clients (like LTO) that want to continue to merge types based on ODR identifiers should opt-in immediately. I have updated LTOCodeGenerator.cpp, the two "linking" spots in gold-plugin.cpp, and llvm-link (unless -disable-debug-info-type-map) to set this. With this in place, it will be straightforward to remove the DITypeRef concept (i.e., referencing types by their 'identifier:' string rather than pointing at them directly). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@266549 91177308-0d34-0410-b5e6-96231b3b80d8 Duncan P. N. Exon Smith 3 years ago
15 changed file(s) with 197 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
40054005 can refer to composite types indirectly via a :ref:`metadata string
40064006 ` that matches their identifier.
40074007
4008 For a given ``identifier:``, there should only be a single composite type that
4009 does not have ``flags: DIFlagFwdDecl`` set. LLVM tools that link modules
4010 together will unique such definitions at parse time via the ``identifier:``
4011 field, even if the nodes are ``distinct``.
4012
40084013 .. code-block:: llvm
40094014
40104015 !0 = !DIEnumerator(name: "SixKind", value: 7)
2424 class Twine;
2525 class Instruction;
2626 class Module;
27 class MDString;
28 class DIType;
2729 class SMDiagnostic;
2830 class DiagnosticInfo;
2931 template class SmallVectorImpl;
112114 /// especially in release mode.
113115 void setDiscardValueNames(bool Discard);
114116
117 /// Whether there is a string map for uniquing debug info types with
118 /// identifiers across the context. Off by default.
119 bool hasDITypeMap() const;
120 void ensureDITypeMap();
121 void destroyDITypeMap();
122
123 /// Get or insert the DIType mapped to the given string.
124 ///
125 /// Returns the address of the current \a DIType pointer mapped to \c S,
126 /// inserting a mapping to \c nullptr if \c S was not previously mapped.
127 /// This method has no effect (and returns \c nullptr instead of a valid
128 /// address) if \a hasDITypeMap() is \c false.
129 ///
130 /// \post If \a hasDITypeMap(), \c S will have a (possibly null) mapping.
131 /// \note The returned address is only valid until the next call.
132 DIType **getOrInsertDITypeMapping(const MDString &S);
133
115134 typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context,
116135 unsigned LocCookie);
117136
38383838 PARSE_MD_FIELDS();
38393839 #undef VISIT_MD_FIELDS
38403840
3841 // If this isn't a forward declaration and it has a UUID, check for it in the
3842 // type map in the context.
3843 DIType **MappedT = nullptr;
3844 if (!(flags.Val & DINode::FlagFwdDecl) && identifier.Val &&
3845 (MappedT = Context.getOrInsertDITypeMapping(*identifier.Val)) &&
3846 *MappedT) {
3847 Result = *MappedT;
3848 return false;
3849 }
3850
3851 // Create a new node, and save it in the context if it belongs in the type
3852 // map.
38413853 Result = GET_OR_DISTINCT(
38423854 DICompositeType,
38433855 (Context, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val,
38443856 size.Val, align.Val, offset.Val, flags.Val, elements.Val,
38453857 runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val));
3858 if (MappedT)
3859 *MappedT = cast(Result);
38463860 return false;
38473861 }
38483862
21872187 if (Record.size() != 16)
21882188 return error("Invalid record");
21892189
2190 MetadataList.assignValue(
2191 GET_OR_DISTINCT(DICompositeType, Record[0],
2192 (Context, Record[1], getMDString(Record[2]),
2193 getMDOrNull(Record[3]), Record[4],
2194 getMDOrNull(Record[5]), getMDOrNull(Record[6]),
2195 Record[7], Record[8], Record[9], Record[10],
2196 getMDOrNull(Record[11]), Record[12],
2197 getMDOrNull(Record[13]), getMDOrNull(Record[14]),
2198 getMDString(Record[15]))),
2199 NextMetadataNo++);
2190 // If we have a UUID and this is not a forward declaration, lookup the
2191 // mapping.
2192 unsigned Flags = Record[10];
2193 auto *Identifier = getMDString(Record[15]);
2194 DIType **MappedT = nullptr;
2195 if (!(Flags & DINode::FlagFwdDecl) && Identifier)
2196 MappedT = Context.getOrInsertDITypeMapping(*Identifier);
2197
2198 // Use the mapped type node, or create a new one if necessary.
2199 DIType *CT = MappedT ? *MappedT : nullptr;
2200 if (!CT) {
2201 CT = GET_OR_DISTINCT(
2202 DICompositeType, Record[0],
2203 (Context, Record[1], getMDString(Record[2]), getMDOrNull(Record[3]),
2204 Record[4], getMDOrNull(Record[5]), getMDOrNull(Record[6]),
2205 Record[7], Record[8], Record[9], Flags, getMDOrNull(Record[11]),
2206 Record[12], getMDOrNull(Record[13]), getMDOrNull(Record[14]),
2207 Identifier));
2208 if (MappedT)
2209 *MappedT = CT;
2210 }
2211
2212 MetadataList.assignValue(CT, NextMetadataNo++);
22002213 break;
22012214 }
22022215 case bitc::METADATA_SUBROUTINE_TYPE: {
253253 Metadata *TemplateParams, MDString *Identifier, StorageType Storage,
254254 bool ShouldCreate) {
255255 assert(isCanonical(Name) && "Expected canonical MDString");
256
256257 DEFINE_GETIMPL_LOOKUP(
257258 DICompositeType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits,
258259 AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
310310 return pImpl->DiscardValueNames;
311311 }
312312
313 bool LLVMContext::hasDITypeMap() const { return !!pImpl->DITypeMap; }
314
315 void LLVMContext::ensureDITypeMap() {
316 if (pImpl->DITypeMap)
317 return;
318
319 pImpl->DITypeMap = llvm::make_unique>();
320 }
321
322 void LLVMContext::destroyDITypeMap() { pImpl->DITypeMap.reset(); }
323
324 DIType **LLVMContext::getOrInsertDITypeMapping(const MDString &S) {
325 if (!hasDITypeMap())
326 return nullptr;
327 return &(*pImpl->DITypeMap)[&S];
328 }
329
313330 void LLVMContext::setDiscardValueNames(bool Discard) {
314331 pImpl->DiscardValueNames = Discard;
315332 }
10211021 DenseSet CLASS##s;
10221022 #include "llvm/IR/Metadata.def"
10231023
1024 // Optional map for looking up composite types by identifier.
1025 std::unique_ptr> DITypeMap;
1026
10241027 // MDNodes may be uniqued or not uniqued. When they're not uniqued, they
10251028 // aren't in the MDNodeSet, but they're still shared between objects, so no
10261029 // one object can destroy them. This set allows us to at least destroy them
8383 : Context(Context), MergedModule(new Module("ld-temp.o", Context)),
8484 TheLinker(new Linker(*MergedModule)) {
8585 Context.setDiscardValueNames(LTODiscardValueNames);
86 Context.ensureDITypeMap();
8687 initializeLTOPasses();
8788 }
8889
1414 #include "llvm/Transforms/Utils/ValueMapper.h"
1515 #include "llvm/IR/CallSite.h"
1616 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/DebugInfoMetadata.h"
1718 #include "llvm/IR/Function.h"
1819 #include "llvm/IR/GlobalAlias.h"
1920 #include "llvm/IR/GlobalVariable.h"
0 !named = !{!0, !1}
1
2 !0 = !DIFile(filename: "abc", directory: "/path/to")
3 !1 = !DICompositeType(tag: DW_TAG_class_type, name: "T2", identifier: "T", file: !0)
0 ; RUN: llvm-link -S -o - %s %S/Inputs/dicompositetype-unique.ll \
1 ; RUN: | FileCheck %s
2 ; RUN: llvm-link -S -o - %S/Inputs/dicompositetype-unique.ll %s \
3 ; RUN: | FileCheck %s -check-prefix REVERSE
4 ; RUN: llvm-link -disable-debug-info-type-map -S -o - %s %S/Inputs/dicompositetype-unique.ll \
5 ; RUN: | FileCheck %s -check-prefix NOMAP
6
7 ; Check that the bitcode reader handles this too.
8 ; RUN: llvm-as -o %t1.bc <%s
9 ; RUN: llvm-as -o %t2.bc <%S/Inputs/dicompositetype-unique.ll
10 ; RUN: llvm-link -S -o - %t1.bc %t2.bc | FileCheck %s
11 ; RUN: llvm-link -S -o - %t2.bc %t1.bc | FileCheck %s -check-prefix REVERSE
12 ; RUN: llvm-link -disable-debug-info-type-map -S -o - %t1.bc %t2.bc \
13 ; RUN: | FileCheck %s -check-prefix NOMAP
14
15 ; Check that the type map will unique two DICompositeTypes.
16
17 ; CHECK: !named = !{!0, !1, !0, !1}
18 ; REVERSE: !named = !{!0, !1, !0, !1}
19 ; NOMAP: !named = !{!0, !1, !0, !2}
20 !named = !{!0, !1}
21
22 ; Check both directions.
23 ; CHECK: !1 = !DICompositeType(
24 ; CHECK-SAME: name: "T1"
25 ; CHECK-SAME: identifier: "T"
26 ; CHECK-NOT: identifier: "T"
27 ; REVERSE: !1 = !DICompositeType(
28 ; REVERSE-SAME: name: "T2"
29 ; REVERSE-SAME: identifier: "T"
30 ; REVERSE-NOT: identifier: "T"
31
32 ; These types are different, so we should get both copies when there is no map.
33 ; NOMAP: !1 = !DICompositeType(
34 ; NOMAP-SAME: name: "T1"
35 ; NOMAP-SAME: identifier: "T"
36 ; NOMAP: !2 = !DICompositeType(
37 ; NOMAP-SAME: name: "T2"
38 ; NOMAP-SAME: identifier: "T"
39 ; NOMAP-NOT: identifier: "T"
40 !0 = !DIFile(filename: "abc", directory: "/path/to")
41 !1 = !DICompositeType(tag: DW_TAG_class_type, name: "T1", identifier: "T", file: !0)
11091109 raw_fd_ostream *OS, unsigned TaskID) {
11101110 // Need to use a separate context for each task
11111111 LLVMContext Context;
1112 Context.ensureDITypeMap(); // Merge debug info types.
11121113 Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);
11131114
11141115 std::unique_ptr NewModule(new llvm::Module(File.name, Context));
12301231 }
12311232
12321233 LLVMContext Context;
1234 Context.ensureDITypeMap(); // Merge debug info types.
12331235 Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);
12341236
12351237 std::unique_ptr Combined(new Module("ld-temp.o", Context));
7070 Internalize("internalize", cl::desc("Internalize linked symbols"));
7171
7272 static cl::opt
73 DisableDITypeMap("disable-debug-info-type-map",
74 cl::desc("Don't use a uniquing type map for debug info"));
75
76 static cl::opt
7377 OnlyNeeded("only-needed", cl::desc("Link only needed symbols"));
7478
7579 static cl::opt
336340 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
337341 cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
338342
343 if (!DisableDITypeMap)
344 Context.ensureDITypeMap();
345
339346 auto Composite = make_unique("llvm-link", Context);
340347 Linker L(*Composite);
341348
1515 IRBuilderTest.cpp
1616 InstructionsTest.cpp
1717 IntrinsicsTest.cpp
18 LLVMContextTest.cpp
1819 LegacyPassManagerTest.cpp
1920 MDBuilderTest.cpp
2021 MetadataTest.cpp
0 //===- LLVMContextTest.cpp - LLVMContext unit tests -----------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/IR/LLVMContext.h"
10 #include "llvm/IR/DebugInfoMetadata.h"
11 #include "gtest/gtest.h"
12 using namespace llvm;
13
14 namespace {
15
16 TEST(LLVMContextTest, ensureDITypeMap) {
17 LLVMContext Context;
18 EXPECT_FALSE(Context.hasDITypeMap());
19 Context.ensureDITypeMap();
20 EXPECT_TRUE(Context.hasDITypeMap());
21 Context.destroyDITypeMap();
22 EXPECT_FALSE(Context.hasDITypeMap());
23 }
24
25 TEST(LLVMContextTest, getOrInsertDITypeMapping) {
26 LLVMContext Context;
27 const MDString &S = *MDString::get(Context, "string");
28
29 // Without a type map, this should return null.
30 EXPECT_FALSE(Context.getOrInsertDITypeMapping(S));
31
32 // Get the mapping.
33 Context.ensureDITypeMap();
34 DIType **Mapping = Context.getOrInsertDITypeMapping(S);
35 ASSERT_TRUE(Mapping);
36
37 // Create some type and add it to the mapping.
38 auto &BT =
39 *DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, S.getString());
40 *Mapping = &BT;
41
42 // Check that we get it back.
43 Mapping = Context.getOrInsertDITypeMapping(S);
44 ASSERT_TRUE(Mapping);
45 EXPECT_EQ(&BT, *Mapping);
46
47 // Check that it's discarded with the type map.
48 Context.destroyDITypeMap();
49 EXPECT_FALSE(Context.getOrInsertDITypeMapping(S));
50
51 // And it shouldn't magically reappear...
52 Context.ensureDITypeMap();
53 EXPECT_FALSE(*Context.getOrInsertDITypeMapping(S));
54 }
55
56 } // end namespace