diff options
-rw-r--r-- | llvm/docs/LangRef.rst | 5 | ||||
-rw-r--r-- | llvm/include/llvm/IR/LLVMContext.h | 19 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 33 | ||||
-rw-r--r-- | llvm/lib/IR/DebugInfoMetadata.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/IR/LLVMContext.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/IR/LLVMContextImpl.h | 3 | ||||
-rw-r--r-- | llvm/lib/LTO/LTOCodeGenerator.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/ValueMapper.cpp | 1 | ||||
-rw-r--r-- | llvm/test/Linker/Inputs/dicompositetype-unique.ll | 4 | ||||
-rw-r--r-- | llvm/test/Linker/dicompositetype-unique.ll | 42 | ||||
-rw-r--r-- | llvm/tools/gold/gold-plugin.cpp | 2 | ||||
-rw-r--r-- | llvm/tools/llvm-link/llvm-link.cpp | 7 | ||||
-rw-r--r-- | llvm/unittests/IR/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/IR/LLVMContextTest.cpp | 57 |
15 files changed, 197 insertions, 10 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index d3ad74ffd58..57ed68e4a81 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -4006,6 +4006,11 @@ identifier used for type merging between modules. When specified, other types can refer to composite types indirectly via a :ref:`metadata string <metadata-string>` that matches their identifier. +For a given ``identifier:``, there should only be a single composite type that +does not have ``flags: DIFlagFwdDecl`` set. LLVM tools that link modules +together will unique such definitions at parse time via the ``identifier:`` +field, even if the nodes are ``distinct``. + .. code-block:: llvm !0 = !DIEnumerator(name: "SixKind", value: 7) diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h index 2a381b1724b..34541995c4c 100644 --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -25,6 +25,8 @@ class StringRef; class Twine; class Instruction; class Module; +class MDString; +class DIType; class SMDiagnostic; class DiagnosticInfo; template <typename T> class SmallVectorImpl; @@ -113,6 +115,23 @@ public: /// especially in release mode. void setDiscardValueNames(bool Discard); + /// Whether there is a string map for uniquing debug info types with + /// identifiers across the context. Off by default. + bool hasDITypeMap() const; + void ensureDITypeMap(); + void destroyDITypeMap(); + + /// Get or insert the DIType mapped to the given string. + /// + /// Returns the address of the current \a DIType pointer mapped to \c S, + /// inserting a mapping to \c nullptr if \c S was not previously mapped. + /// This method has no effect (and returns \c nullptr instead of a valid + /// address) if \a hasDITypeMap() is \c false. + /// + /// \post If \a hasDITypeMap(), \c S will have a (possibly null) mapping. + /// \note The returned address is only valid until the next call. + DIType **getOrInsertDITypeMapping(const MDString &S); + typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context, unsigned LocCookie); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index c72b7196195..34f7ec4469b 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3839,11 +3839,25 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) { 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. + DIType **MappedT = nullptr; + if (!(flags.Val & DINode::FlagFwdDecl) && identifier.Val && + (MappedT = Context.getOrInsertDITypeMapping(*identifier.Val)) && + *MappedT) { + Result = *MappedT; + return false; + } + + // Create a new node, and save it in the context if it belongs in the type + // map. Result = GET_OR_DISTINCT( DICompositeType, (Context, 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, templateParams.Val, identifier.Val)); + if (MappedT) + *MappedT = cast<DIType>(Result); return false; } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index ad14cbc998d..18386ed0727 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2188,16 +2188,29 @@ std::error_code BitcodeReader::parseMetadata(bool ModuleLevel) { if (Record.size() != 16) return error("Invalid record"); - MetadataList.assignValue( - GET_OR_DISTINCT(DICompositeType, Record[0], - (Context, Record[1], getMDString(Record[2]), - getMDOrNull(Record[3]), Record[4], - getMDOrNull(Record[5]), getMDOrNull(Record[6]), - Record[7], Record[8], Record[9], Record[10], - getMDOrNull(Record[11]), Record[12], - getMDOrNull(Record[13]), getMDOrNull(Record[14]), - getMDString(Record[15]))), - NextMetadataNo++); + // If we have a UUID and this is not a forward declaration, lookup the + // mapping. + unsigned Flags = Record[10]; + auto *Identifier = getMDString(Record[15]); + DIType **MappedT = nullptr; + if (!(Flags & DINode::FlagFwdDecl) && Identifier) + MappedT = Context.getOrInsertDITypeMapping(*Identifier); + + // Use the mapped type node, or create a new one if necessary. + DIType *CT = MappedT ? *MappedT : nullptr; + if (!CT) { + CT = GET_OR_DISTINCT( + DICompositeType, Record[0], + (Context, Record[1], getMDString(Record[2]), getMDOrNull(Record[3]), + Record[4], getMDOrNull(Record[5]), getMDOrNull(Record[6]), + Record[7], Record[8], Record[9], Flags, getMDOrNull(Record[11]), + Record[12], getMDOrNull(Record[13]), getMDOrNull(Record[14]), + Identifier)); + if (MappedT) + *MappedT = CT; + } + + MetadataList.assignValue(CT, NextMetadataNo++); break; } case bitc::METADATA_SUBROUTINE_TYPE: { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 80c83140ee3..3e6400785fd 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -254,6 +254,7 @@ DICompositeType *DICompositeType::getImpl( Metadata *TemplateParams, MDString *Identifier, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP( DICompositeType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 0e8d3e826aa..3fc79ed03c3 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -311,6 +311,23 @@ bool LLVMContext::shouldDiscardValueNames() const { return pImpl->DiscardValueNames; } +bool LLVMContext::hasDITypeMap() const { return !!pImpl->DITypeMap; } + +void LLVMContext::ensureDITypeMap() { + if (pImpl->DITypeMap) + return; + + pImpl->DITypeMap = llvm::make_unique<DenseMap<const MDString *, DIType *>>(); +} + +void LLVMContext::destroyDITypeMap() { pImpl->DITypeMap.reset(); } + +DIType **LLVMContext::getOrInsertDITypeMapping(const MDString &S) { + if (!hasDITypeMap()) + return nullptr; + return &(*pImpl->DITypeMap)[&S]; +} + void LLVMContext::setDiscardValueNames(bool Discard) { pImpl->DiscardValueNames = Discard; } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 8a2c43909b4..a535a19d653 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1022,6 +1022,9 @@ public: DenseSet<CLASS *, CLASS##Info> CLASS##s; #include "llvm/IR/Metadata.def" + // Optional map for looking up composite types by identifier. + std::unique_ptr<DenseMap<const MDString *, DIType *>> DITypeMap; + // MDNodes may be uniqued or not uniqued. When they're not uniqued, they // aren't in the MDNodeSet, but they're still shared between objects, so no // one object can destroy them. This set allows us to at least destroy them diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index bc500085a72..4f779d4390b 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -84,6 +84,7 @@ LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) : Context(Context), MergedModule(new Module("ld-temp.o", Context)), TheLinker(new Linker(*MergedModule)) { Context.setDiscardValueNames(LTODiscardValueNames); + Context.ensureDITypeMap(); initializeLTOPasses(); } diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp index a58b98bb9fb..f8fa61329e2 100644 --- a/llvm/lib/Transforms/Utils/ValueMapper.cpp +++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp @@ -15,6 +15,7 @@ #include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" diff --git a/llvm/test/Linker/Inputs/dicompositetype-unique.ll b/llvm/test/Linker/Inputs/dicompositetype-unique.ll new file mode 100644 index 00000000000..c2389e9a63c --- /dev/null +++ b/llvm/test/Linker/Inputs/dicompositetype-unique.ll @@ -0,0 +1,4 @@ +!named = !{!0, !1} + +!0 = !DIFile(filename: "abc", directory: "/path/to") +!1 = !DICompositeType(tag: DW_TAG_class_type, name: "T2", identifier: "T", file: !0) diff --git a/llvm/test/Linker/dicompositetype-unique.ll b/llvm/test/Linker/dicompositetype-unique.ll new file mode 100644 index 00000000000..9c8b351ec64 --- /dev/null +++ b/llvm/test/Linker/dicompositetype-unique.ll @@ -0,0 +1,42 @@ +; RUN: llvm-link -S -o - %s %S/Inputs/dicompositetype-unique.ll \ +; RUN: | FileCheck %s +; RUN: llvm-link -S -o - %S/Inputs/dicompositetype-unique.ll %s \ +; RUN: | FileCheck %s -check-prefix REVERSE +; RUN: llvm-link -disable-debug-info-type-map -S -o - %s %S/Inputs/dicompositetype-unique.ll \ +; RUN: | FileCheck %s -check-prefix NOMAP + +; Check that the bitcode reader handles this too. +; RUN: llvm-as -o %t1.bc <%s +; RUN: llvm-as -o %t2.bc <%S/Inputs/dicompositetype-unique.ll +; RUN: llvm-link -S -o - %t1.bc %t2.bc | FileCheck %s +; RUN: llvm-link -S -o - %t2.bc %t1.bc | FileCheck %s -check-prefix REVERSE +; RUN: llvm-link -disable-debug-info-type-map -S -o - %t1.bc %t2.bc \ +; RUN: | FileCheck %s -check-prefix NOMAP + +; Check that the type map will unique two DICompositeTypes. + +; CHECK: !named = !{!0, !1, !0, !1} +; REVERSE: !named = !{!0, !1, !0, !1} +; NOMAP: !named = !{!0, !1, !0, !2} +!named = !{!0, !1} + +; Check both directions. +; CHECK: !1 = !DICompositeType( +; CHECK-SAME: name: "T1" +; CHECK-SAME: identifier: "T" +; CHECK-NOT: identifier: "T" +; REVERSE: !1 = !DICompositeType( +; REVERSE-SAME: name: "T2" +; REVERSE-SAME: identifier: "T" +; REVERSE-NOT: identifier: "T" + +; 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: "T2" +; NOMAP-SAME: identifier: "T" +; NOMAP-NOT: identifier: "T" +!0 = !DIFile(filename: "abc", directory: "/path/to") +!1 = !DICompositeType(tag: DW_TAG_class_type, name: "T1", identifier: "T", file: !0) diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp index affd826e5a7..15a70a22dc6 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -1110,6 +1110,7 @@ static void thinLTOBackendTask(claimed_file &F, const void *View, raw_fd_ostream *OS, unsigned TaskID) { // Need to use a separate context for each task LLVMContext Context; + Context.ensureDITypeMap(); // Merge debug info types. Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true); std::unique_ptr<llvm::Module> NewModule(new llvm::Module(File.name, Context)); @@ -1231,6 +1232,7 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { } LLVMContext Context; + Context.ensureDITypeMap(); // Merge debug info types. Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true); std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context)); diff --git a/llvm/tools/llvm-link/llvm-link.cpp b/llvm/tools/llvm-link/llvm-link.cpp index 7d02425adb8..2dac8eabaee 100644 --- a/llvm/tools/llvm-link/llvm-link.cpp +++ b/llvm/tools/llvm-link/llvm-link.cpp @@ -71,6 +71,10 @@ static cl::opt<bool> Internalize("internalize", cl::desc("Internalize linked symbols")); static cl::opt<bool> + DisableDITypeMap("disable-debug-info-type-map", + cl::desc("Don't use a uniquing type map for debug info")); + +static cl::opt<bool> OnlyNeeded("only-needed", cl::desc("Link only needed symbols")); static cl::opt<bool> @@ -337,6 +341,9 @@ int main(int argc, char **argv) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); + if (!DisableDITypeMap) + Context.ensureDITypeMap(); + auto Composite = make_unique<Module>("llvm-link", Context); Linker L(*Composite); diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt index c14fd2ff0e7..8e63af05e0b 100644 --- a/llvm/unittests/IR/CMakeLists.txt +++ b/llvm/unittests/IR/CMakeLists.txt @@ -16,6 +16,7 @@ set(IRSources IRBuilderTest.cpp InstructionsTest.cpp IntrinsicsTest.cpp + LLVMContextTest.cpp LegacyPassManagerTest.cpp MDBuilderTest.cpp MetadataTest.cpp diff --git a/llvm/unittests/IR/LLVMContextTest.cpp b/llvm/unittests/IR/LLVMContextTest.cpp new file mode 100644 index 00000000000..16cf0745e09 --- /dev/null +++ b/llvm/unittests/IR/LLVMContextTest.cpp @@ -0,0 +1,57 @@ +//===- LLVMContextTest.cpp - LLVMContext unit tests -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(LLVMContextTest, ensureDITypeMap) { + LLVMContext Context; + EXPECT_FALSE(Context.hasDITypeMap()); + Context.ensureDITypeMap(); + EXPECT_TRUE(Context.hasDITypeMap()); + Context.destroyDITypeMap(); + EXPECT_FALSE(Context.hasDITypeMap()); +} + +TEST(LLVMContextTest, getOrInsertDITypeMapping) { + LLVMContext Context; + const MDString &S = *MDString::get(Context, "string"); + + // Without a type map, this should return null. + EXPECT_FALSE(Context.getOrInsertDITypeMapping(S)); + + // Get the mapping. + Context.ensureDITypeMap(); + DIType **Mapping = Context.getOrInsertDITypeMapping(S); + ASSERT_TRUE(Mapping); + + // Create some type and add it to the mapping. + auto &BT = + *DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, S.getString()); + *Mapping = &BT; + + // Check that we get it back. + Mapping = Context.getOrInsertDITypeMapping(S); + ASSERT_TRUE(Mapping); + EXPECT_EQ(&BT, *Mapping); + + // Check that it's discarded with the type map. + Context.destroyDITypeMap(); + EXPECT_FALSE(Context.getOrInsertDITypeMapping(S)); + + // And it shouldn't magically reappear... + Context.ensureDITypeMap(); + EXPECT_FALSE(*Context.getOrInsertDITypeMapping(S)); +} + +} // end namespace |