summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/LangRef.rst5
-rw-r--r--llvm/include/llvm/IR/LLVMContext.h19
-rw-r--r--llvm/lib/AsmParser/LLParser.cpp14
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp33
-rw-r--r--llvm/lib/IR/DebugInfoMetadata.cpp1
-rw-r--r--llvm/lib/IR/LLVMContext.cpp17
-rw-r--r--llvm/lib/IR/LLVMContextImpl.h3
-rw-r--r--llvm/lib/LTO/LTOCodeGenerator.cpp1
-rw-r--r--llvm/lib/Transforms/Utils/ValueMapper.cpp1
-rw-r--r--llvm/test/Linker/Inputs/dicompositetype-unique.ll4
-rw-r--r--llvm/test/Linker/dicompositetype-unique.ll42
-rw-r--r--llvm/tools/gold/gold-plugin.cpp2
-rw-r--r--llvm/tools/llvm-link/llvm-link.cpp7
-rw-r--r--llvm/unittests/IR/CMakeLists.txt1
-rw-r--r--llvm/unittests/IR/LLVMContextTest.cpp57
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
OpenPOWER on IntegriCloud