forked from OSchip/llvm-project
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). llvm-svn: 266549
This commit is contained in:
parent
05ebfd0938
commit
5ab2be094e
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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));
|
||||
|
|
|
@ -70,6 +70,10 @@ OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
|
|||
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"));
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ set(IRSources
|
|||
IRBuilderTest.cpp
|
||||
InstructionsTest.cpp
|
||||
IntrinsicsTest.cpp
|
||||
LLVMContextTest.cpp
|
||||
LegacyPassManagerTest.cpp
|
||||
MDBuilderTest.cpp
|
||||
MetadataTest.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
|
Loading…
Reference in New Issue