[ThinLTO] Import composite types as declarations

Summary:
When reading the metadata bitcode, create a type declaration when
possible for composite types when we are importing. Doing this in
the bitcode reader saves memory. Also it works naturally in the case
when the type ODR map contains a definition for the same composite type
because it was used in the importing module (buildODRType will
automatically use the existing definition and not create a type
declaration).

For Chromium built with -g2, this reduces the aggregate size of the
generated native object files by 66% (from 31G to 10G). It reduced
the time through the ThinLTO link and backend phases by about 20% on
my machine.

Reviewers: mehdi_amini, dblaikie, aprantl

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D27775

llvm-svn: 289993
This commit is contained in:
Teresa Johnson 2016-12-16 21:25:01 +00:00
parent 3ca147ea3d
commit a61f5e3796
10 changed files with 173 additions and 51 deletions

View File

@ -61,9 +61,10 @@ namespace llvm {
friend Expected<std::vector<BitcodeModule>> friend Expected<std::vector<BitcodeModule>>
getBitcodeModuleList(MemoryBufferRef Buffer); getBitcodeModuleList(MemoryBufferRef Buffer);
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>> getModuleImpl(LLVMContext &Context,
getModuleImpl(LLVMContext &Context, bool MaterializeAll, bool MaterializeAll,
bool ShouldLazyLoadMetadata); bool ShouldLazyLoadMetadata,
bool IsImporting);
public: public:
StringRef getBuffer() const { StringRef getBuffer() const {
@ -74,8 +75,11 @@ namespace llvm {
/// Read the bitcode module and prepare for lazy deserialization of function /// Read the bitcode module and prepare for lazy deserialization of function
/// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well.
Expected<std::unique_ptr<Module>> /// If IsImporting is true, this module is being parsed for ThinLTO
getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata); /// importing into another module.
Expected<std::unique_ptr<Module>> getLazyModule(LLVMContext &Context,
bool ShouldLazyLoadMetadata,
bool IsImporting);
/// Read the entire bitcode module and return it. /// Read the entire bitcode module and return it.
Expected<std::unique_ptr<Module>> parseModule(LLVMContext &Context); Expected<std::unique_ptr<Module>> parseModule(LLVMContext &Context);
@ -93,18 +97,20 @@ namespace llvm {
/// Read the header of the specified bitcode buffer and prepare for lazy /// Read the header of the specified bitcode buffer and prepare for lazy
/// deserialization of function bodies. If ShouldLazyLoadMetadata is true, /// deserialization of function bodies. If ShouldLazyLoadMetadata is true,
/// lazily load metadata as well. /// lazily load metadata as well. If IsImporting is true, this module is
/// being parsed for ThinLTO importing into another module.
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>>
getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context, getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context,
bool ShouldLazyLoadMetadata = false); bool ShouldLazyLoadMetadata = false,
bool IsImporting = false);
/// Like getLazyBitcodeModule, except that the module takes ownership of /// Like getLazyBitcodeModule, except that the module takes ownership of
/// the memory buffer if successful. If successful, this moves Buffer. On /// the memory buffer if successful. If successful, this moves Buffer. On
/// error, this *does not* move Buffer. /// error, this *does not* move Buffer. If IsImporting is true, this module is
Expected<std::unique_ptr<Module>> /// being parsed for ThinLTO importing into another module.
getOwningLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer, Expected<std::unique_ptr<Module>> getOwningLazyBitcodeModule(
LLVMContext &Context, std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
bool ShouldLazyLoadMetadata = false); bool ShouldLazyLoadMetadata = false, bool IsImporting = false);
/// Read the header of the specified bitcode buffer and extract just the /// Read the header of the specified bitcode buffer and extract just the
/// triple information. If successful, this returns a string. On error, this /// triple information. If successful, this returns a string. On error, this

View File

@ -488,7 +488,8 @@ public:
/// \brief Main interface to parsing a bitcode buffer. /// \brief Main interface to parsing a bitcode buffer.
/// \returns true if an error occurred. /// \returns true if an error occurred.
Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false); Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false,
bool IsImporting = false);
static uint64_t decodeSignRotatedValue(uint64_t V); static uint64_t decodeSignRotatedValue(uint64_t V);
@ -3084,9 +3085,10 @@ Error BitcodeReader::parseModule(uint64_t ResumeBit,
} }
} }
Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata) { Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata,
bool IsImporting) {
TheModule = M; TheModule = M;
MDLoader = MetadataLoader(Stream, *M, ValueList, MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting,
[&](unsigned ID) { return getTypeByID(ID); }); [&](unsigned ID) { return getTypeByID(ID); });
return parseModule(0, ShouldLazyLoadMetadata); return parseModule(0, ShouldLazyLoadMetadata);
} }
@ -5220,7 +5222,7 @@ llvm::getBitcodeModuleList(MemoryBufferRef Buffer) {
/// everything. /// everything.
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>>
BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll, BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
bool ShouldLazyLoadMetadata) { bool ShouldLazyLoadMetadata, bool IsImporting) {
BitstreamCursor Stream(Buffer); BitstreamCursor Stream(Buffer);
std::string ProducerIdentification; std::string ProducerIdentification;
@ -5243,7 +5245,8 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
M->setMaterializer(R); M->setMaterializer(R);
// Delay parsing Metadata if ShouldLazyLoadMetadata is true. // Delay parsing Metadata if ShouldLazyLoadMetadata is true.
if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata)) if (Error Err =
R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting))
return std::move(Err); return std::move(Err);
if (MaterializeAll) { if (MaterializeAll) {
@ -5259,9 +5262,9 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
} }
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>>
BitcodeModule::getLazyModule(LLVMContext &Context, BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata,
bool ShouldLazyLoadMetadata) { bool IsImporting) {
return getModuleImpl(Context, false, ShouldLazyLoadMetadata); return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting);
} }
// Parse the specified bitcode buffer, returning the function info index. // Parse the specified bitcode buffer, returning the function info index.
@ -5323,20 +5326,20 @@ static Expected<BitcodeModule> getSingleModule(MemoryBufferRef Buffer) {
} }
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>>
llvm::getLazyBitcodeModule(MemoryBufferRef Buffer, llvm::getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context,
LLVMContext &Context, bool ShouldLazyLoadMetadata) { bool ShouldLazyLoadMetadata, bool IsImporting) {
Expected<BitcodeModule> BM = getSingleModule(Buffer); Expected<BitcodeModule> BM = getSingleModule(Buffer);
if (!BM) if (!BM)
return BM.takeError(); return BM.takeError();
return BM->getLazyModule(Context, ShouldLazyLoadMetadata); return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting);
} }
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>> llvm::getOwningLazyBitcodeModule(
llvm::getOwningLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer, std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
LLVMContext &Context, bool ShouldLazyLoadMetadata, bool IsImporting) {
bool ShouldLazyLoadMetadata) { auto MOrErr = getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata,
auto MOrErr = getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata); IsImporting);
if (MOrErr) if (MOrErr)
(*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer)); (*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer));
return MOrErr; return MOrErr;
@ -5344,7 +5347,7 @@ llvm::getOwningLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
Expected<std::unique_ptr<Module>> Expected<std::unique_ptr<Module>>
BitcodeModule::parseModule(LLVMContext &Context) { BitcodeModule::parseModule(LLVMContext &Context) {
return getModuleImpl(Context, true, false); return getModuleImpl(Context, true, false, false);
// TODO: Restore the use-lists to the in-memory state when the bitcode was // TODO: Restore the use-lists to the in-memory state when the bitcode was
// written. We must defer until the Module has been fully materialized. // written. We must defer until the Module has been fully materialized.
} }

View File

@ -86,6 +86,12 @@
using namespace llvm; using namespace llvm;
/// Flag whether we need to import full type definitions for ThinLTO.
/// Currently needed for Darwin and LLDB.
static cl::opt<bool> ImportFullTypeDefinitions(
"import-full-type-definitions", cl::init(false), cl::Hidden,
cl::desc("Import full type definitions for ThinLTO."));
namespace { namespace {
static int64_t unrotateSign(uint64_t U) { return U & 1 ? ~(U >> 1) : U >> 1; } static int64_t unrotateSign(uint64_t U) { return U & 1 ? ~(U >> 1) : U >> 1; }
@ -399,7 +405,7 @@ public:
Stream(Stream), Context(TheModule.getContext()), TheModule(TheModule), Stream(Stream), Context(TheModule.getContext()), TheModule(TheModule),
getTypeByID(getTypeByID) {} getTypeByID(getTypeByID) {}
Error parseMetadata(bool ModuleLevel); Error parseMetadata(bool ModuleLevel, bool IsImporting);
bool hasFwdRefs() const { return MetadataList.hasFwdRefs(); } bool hasFwdRefs() const { return MetadataList.hasFwdRefs(); }
Metadata *getMetadataFwdRef(unsigned Idx) { Metadata *getMetadataFwdRef(unsigned Idx) {
@ -435,7 +441,8 @@ Error error(const Twine &Message) {
/// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing /// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing
/// module level metadata. /// module level metadata.
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) { Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel,
bool IsImporting) {
if (!ModuleLevel && MetadataList.hasFwdRefs()) if (!ModuleLevel && MetadataList.hasFwdRefs())
return error("Invalid metadata: fwd refs into function blocks"); return error("Invalid metadata: fwd refs into function blocks");
@ -709,18 +716,38 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
Metadata *File = getMDOrNull(Record[3]); Metadata *File = getMDOrNull(Record[3]);
unsigned Line = Record[4]; unsigned Line = Record[4];
Metadata *Scope = getDITypeRefOrNull(Record[5]); Metadata *Scope = getDITypeRefOrNull(Record[5]);
Metadata *BaseType = getDITypeRefOrNull(Record[6]); Metadata *BaseType = nullptr;
uint64_t SizeInBits = Record[7]; uint64_t SizeInBits = Record[7];
if (Record[8] > (uint64_t)std::numeric_limits<uint32_t>::max()) if (Record[8] > (uint64_t)std::numeric_limits<uint32_t>::max())
return error("Alignment value is too large"); return error("Alignment value is too large");
uint32_t AlignInBits = Record[8]; uint32_t AlignInBits = Record[8];
uint64_t OffsetInBits = Record[9]; uint64_t OffsetInBits = 0;
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(Record[10]); DINode::DIFlags Flags = static_cast<DINode::DIFlags>(Record[10]);
Metadata *Elements = getMDOrNull(Record[11]); Metadata *Elements = nullptr;
unsigned RuntimeLang = Record[12]; unsigned RuntimeLang = Record[12];
Metadata *VTableHolder = getDITypeRefOrNull(Record[13]); Metadata *VTableHolder = nullptr;
Metadata *TemplateParams = getMDOrNull(Record[14]); Metadata *TemplateParams = nullptr;
auto *Identifier = getMDString(Record[15]); auto *Identifier = getMDString(Record[15]);
// If this module is being parsed so that it can be ThinLTO imported
// into another module, composite types only need to be imported
// as type declarations (unless full type definitions requested).
// Create type declarations up front to save memory. Also, buildODRType
// handles the case where this is type ODRed with a definition needed
// by the importing module, in which case the existing definition is
// used.
if (IsImporting && !ImportFullTypeDefinitions &&
(Tag == dwarf::DW_TAG_enumeration_type ||
Tag == dwarf::DW_TAG_class_type ||
Tag == dwarf::DW_TAG_structure_type ||
Tag == dwarf::DW_TAG_union_type)) {
Flags = Flags | DINode::FlagFwdDecl;
} else {
BaseType = getDITypeRefOrNull(Record[6]);
OffsetInBits = Record[9];
Elements = getMDOrNull(Record[11]);
VTableHolder = getDITypeRefOrNull(Record[13]);
TemplateParams = getMDOrNull(Record[14]);
}
DICompositeType *CT = nullptr; DICompositeType *CT = nullptr;
if (Identifier) if (Identifier)
CT = DICompositeType::buildODRType( CT = DICompositeType::buildODRType(
@ -1281,17 +1308,19 @@ MetadataLoader &MetadataLoader::operator=(MetadataLoader &&RHS) {
return *this; return *this;
} }
MetadataLoader::MetadataLoader(MetadataLoader &&RHS) MetadataLoader::MetadataLoader(MetadataLoader &&RHS)
: Pimpl(std::move(RHS.Pimpl)) {} : Pimpl(std::move(RHS.Pimpl)), IsImporting(RHS.IsImporting) {}
MetadataLoader::~MetadataLoader() = default; MetadataLoader::~MetadataLoader() = default;
MetadataLoader::MetadataLoader(BitstreamCursor &Stream, Module &TheModule, MetadataLoader::MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
BitcodeReaderValueList &ValueList, BitcodeReaderValueList &ValueList,
bool IsImporting,
std::function<Type *(unsigned)> getTypeByID) std::function<Type *(unsigned)> getTypeByID)
: Pimpl(llvm::make_unique<MetadataLoaderImpl>(Stream, TheModule, ValueList, : Pimpl(llvm::make_unique<MetadataLoaderImpl>(Stream, TheModule, ValueList,
getTypeByID)) {} getTypeByID)),
IsImporting(IsImporting) {}
Error MetadataLoader::parseMetadata(bool ModuleLevel) { Error MetadataLoader::parseMetadata(bool ModuleLevel) {
return Pimpl->parseMetadata(ModuleLevel); return Pimpl->parseMetadata(ModuleLevel, IsImporting);
} }
bool MetadataLoader::hasFwdRefs() const { return Pimpl->hasFwdRefs(); } bool MetadataLoader::hasFwdRefs() const { return Pimpl->hasFwdRefs(); }

View File

@ -36,12 +36,14 @@ class Type;
class MetadataLoader { class MetadataLoader {
class MetadataLoaderImpl; class MetadataLoaderImpl;
std::unique_ptr<MetadataLoaderImpl> Pimpl; std::unique_ptr<MetadataLoaderImpl> Pimpl;
/// True if metadata is being parsed for a module being ThinLTO imported.
bool IsImporting = false;
Error parseMetadata(bool ModuleLevel); Error parseMetadata(bool ModuleLevel);
public: public:
~MetadataLoader(); ~MetadataLoader();
MetadataLoader(BitstreamCursor &Stream, Module &TheModule, MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
BitcodeReaderValueList &ValueList, BitcodeReaderValueList &ValueList, bool IsImporting,
std::function<Type *(unsigned)> getTypeByID); std::function<Type *(unsigned)> getTypeByID);
MetadataLoader &operator=(MetadataLoader &&); MetadataLoader &operator=(MetadataLoader &&);
MetadataLoader(MetadataLoader &&); MetadataLoader(MetadataLoader &&);

View File

@ -252,7 +252,8 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
// ModuleSymbolTable. // ModuleSymbolTable.
for (auto BM : *BMsOrErr) { for (auto BM : *BMsOrErr) {
Expected<std::unique_ptr<Module>> MOrErr = Expected<std::unique_ptr<Module>> MOrErr =
BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true); BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true,
/*IsImporting*/ false);
if (!MOrErr) if (!MOrErr)
return MOrErr.takeError(); return MOrErr.takeError();
@ -415,7 +416,8 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule); RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule);
} }
Expected<std::unique_ptr<Module>> MOrErr = Expected<std::unique_ptr<Module>> MOrErr =
BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true); BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true,
/*IsImporting*/ false);
if (!MOrErr) if (!MOrErr)
return MOrErr.takeError(); return MOrErr.takeError();

View File

@ -356,7 +356,8 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,
auto I = ModuleMap.find(Identifier); auto I = ModuleMap.find(Identifier);
assert(I != ModuleMap.end()); assert(I != ModuleMap.end());
return I->second.getLazyModule(Mod.getContext(), return I->second.getLazyModule(Mod.getContext(),
/*ShouldLazyLoadMetadata=*/true); /*ShouldLazyLoadMetadata=*/true,
/*IsImporting*/ true);
}; };
FunctionImporter Importer(CombinedIndex, ModuleLoader); FunctionImporter Importer(CombinedIndex, ModuleLoader);

View File

@ -168,12 +168,13 @@ static void promoteModule(Module &TheModule, const ModuleSummaryIndex &Index) {
static std::unique_ptr<Module> static std::unique_ptr<Module>
loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context, loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context,
bool Lazy) { bool Lazy, bool IsImporting) {
SMDiagnostic Err; SMDiagnostic Err;
Expected<std::unique_ptr<Module>> ModuleOrErr = Expected<std::unique_ptr<Module>> ModuleOrErr =
Lazy ? getLazyBitcodeModule(Buffer, Context, Lazy
/* ShouldLazyLoadMetadata */ true) ? getLazyBitcodeModule(Buffer, Context,
: parseBitcodeFile(Buffer, Context); /* ShouldLazyLoadMetadata */ true, IsImporting)
: parseBitcodeFile(Buffer, Context);
if (!ModuleOrErr) { if (!ModuleOrErr) {
handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) { handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
SMDiagnostic Err = SMDiagnostic(Buffer.getBufferIdentifier(), SMDiagnostic Err = SMDiagnostic(Buffer.getBufferIdentifier(),
@ -191,7 +192,7 @@ crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index,
const FunctionImporter::ImportMapTy &ImportList) { const FunctionImporter::ImportMapTy &ImportList) {
auto Loader = [&](StringRef Identifier) { auto Loader = [&](StringRef Identifier) {
return loadModuleFromBuffer(ModuleMap[Identifier], TheModule.getContext(), return loadModuleFromBuffer(ModuleMap[Identifier], TheModule.getContext(),
/*Lazy=*/true); /*Lazy=*/true, /*IsImporting*/ true);
}; };
FunctionImporter Importer(Index, Loader); FunctionImporter Importer(Index, Loader);
@ -787,7 +788,8 @@ void ThinLTOCodeGenerator::run() {
Context.setDiscardValueNames(LTODiscardValueNames); Context.setDiscardValueNames(LTODiscardValueNames);
// Parse module now // Parse module now
auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false); auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false,
/*IsImporting*/ false);
// CodeGen // CodeGen
ProducedBinaries[count] = codegen(*TheModule); ProducedBinaries[count] = codegen(*TheModule);
@ -933,7 +935,8 @@ void ThinLTOCodeGenerator::run() {
} }
// Parse module now // Parse module now
auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false); auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false,
/*IsImporting*/ false);
// Save temps: original file. // Save temps: original file.
saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc"); saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc");

View File

@ -127,7 +127,8 @@ IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) {
std::vector<std::unique_ptr<Module>> Mods; std::vector<std::unique_ptr<Module>> Mods;
for (auto BM : *BMsOrErr) { for (auto BM : *BMsOrErr) {
Expected<std::unique_ptr<Module>> MOrErr = Expected<std::unique_ptr<Module>> MOrErr =
BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true); BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true,
/*IsImporting*/ false);
if (!MOrErr) if (!MOrErr)
return MOrErr.takeError(); return MOrErr.takeError();

View File

@ -0,0 +1,13 @@
; ModuleID = 'debuginfo-compositetype-import2.c'
source_filename = "debuginfo-compositetype-import2.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: nounwind uwtable
define i32 @main() {
entry:
call void (...) @foo()
ret i32 0
}
declare void @foo(...) #1

View File

@ -0,0 +1,62 @@
; Test to ensure DICompositeType are imported as type declarations
; for ThinLTO
; RUN: opt -module-summary %s -o %t1.bc
; RUN: opt -module-summary %p/Inputs/debuginfo-compositetype-import.ll -o %t2.bc
; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc
; By default, composite types are imported as type declarations
; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t.index.bc -o - | llvm-dis -o - | FileCheck %s
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.out -save-temps \
; RUN: -r %t2.bc,main,plx \
; RUN: -r %t2.bc,foo,l \
; RUN: -r %t1.bc,foo,pl
; RUN: llvm-dis < %t.out.1.3.import.bc | FileCheck %s
; CHECK: distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 50, size: 32, flags: DIFlagFwdDecl, identifier: "enum")
; CHECK: distinct !DICompositeType(tag: DW_TAG_class_type, name: "class", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 728, size: 448, flags: DIFlagFwdDecl, identifier: "class")
; CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, size: 128, flags: DIFlagFwdDecl, identifier: "list")
; CHECK: distinct !DICompositeType(tag: DW_TAG_union_type, file: !{{[0-9]+}}, line: 115, size: 384, flags: DIFlagFwdDecl, identifier: "union")
; Ensure that full type definitions of composite types are imported if requested
; RUN: llvm-lto -import-full-type-definitions -thinlto-action=import %t2.bc -thinlto-index=%t.index.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=FULL
; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.out -save-temps \
; RUN: -import-full-type-definitions \
; RUN: -r %t2.bc,main,plx \
; RUN: -r %t2.bc,foo,l \
; RUN: -r %t1.bc,foo,pl
; RUN: llvm-dis < %t.out.1.3.import.bc | FileCheck %s --check-prefix=FULL
; FULL: distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 50, size: 32, elements: !{{[0-9]+}}, identifier: "enum")
; FULL: distinct !DICompositeType(tag: DW_TAG_class_type, name: "class", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 728, size: 448, elements: !{{[0-9]+}}, identifier: "class")
; FULL: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 309, baseType: !{{[0-9]+}}, size: 128, offset: 64, elements: !{{[0-9]+}}, vtableHolder: !{{[0-9]+}}, templateParams: !{{[0-9]+}}, identifier: "list")
; FULL: distinct !DICompositeType(tag: DW_TAG_union_type, file: !{{[0-9]+}}, line: 115, size: 384, elements: !{{[0-9]+}}, identifier: "union")
; ModuleID = 'debuginfo-compositetype-import.c'
source_filename = "debuginfo-compositetype-import.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: nounwind uwtable
define void @foo() #0 !dbg !6 {
entry:
ret void
}
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3}
!llvm.ident = !{!4}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 (trunk 286863) (llvm/trunk 286875)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!1 = !DIFile(filename: "debuginfo-compositetype-import.c", directory: "")
!2 = !{i32 2, !"Dwarf Version", i32 4}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{!"clang version 4.0.0 (trunk 286863) (llvm/trunk 286875)"}
!5 = !{}
!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, variables: !5)
!7 = !DISubroutineType(types: !8)
!8 = !{!9, !10, !11, !12}
!9 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum", scope: !1, file: !1, line: 50, size: 32, elements: !5, identifier: "enum")
!10 = !DICompositeType(tag: DW_TAG_class_type, name: "class", scope: !1, file: !1, line: 728, size: 448, elements: !5, identifier: "class")
!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "struct", scope: !1, file: !1, line: 309, baseType: !10, size: 128, offset: 64, elements: !5, vtableHolder: !10, templateParams: !5, identifier: "list")
!12 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 115, size: 384, elements: !5, identifier: "union")