Skip to content

Commit a61f5e3

Browse files
committed
[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
1 parent 3ca147e commit a61f5e3

File tree

10 files changed

+173
-51
lines changed

10 files changed

+173
-51
lines changed

llvm/include/llvm/Bitcode/BitcodeReader.h

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ namespace llvm {
6161
friend Expected<std::vector<BitcodeModule>>
6262
getBitcodeModuleList(MemoryBufferRef Buffer);
6363

64-
Expected<std::unique_ptr<Module>>
65-
getModuleImpl(LLVMContext &Context, bool MaterializeAll,
66-
bool ShouldLazyLoadMetadata);
64+
Expected<std::unique_ptr<Module>> getModuleImpl(LLVMContext &Context,
65+
bool MaterializeAll,
66+
bool ShouldLazyLoadMetadata,
67+
bool IsImporting);
6768

6869
public:
6970
StringRef getBuffer() const {
@@ -74,8 +75,11 @@ namespace llvm {
7475

7576
/// Read the bitcode module and prepare for lazy deserialization of function
7677
/// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well.
77-
Expected<std::unique_ptr<Module>>
78-
getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata);
78+
/// If IsImporting is true, this module is being parsed for ThinLTO
79+
/// importing into another module.
80+
Expected<std::unique_ptr<Module>> getLazyModule(LLVMContext &Context,
81+
bool ShouldLazyLoadMetadata,
82+
bool IsImporting);
7983

8084
/// Read the entire bitcode module and return it.
8185
Expected<std::unique_ptr<Module>> parseModule(LLVMContext &Context);
@@ -93,18 +97,20 @@ namespace llvm {
9397

9498
/// Read the header of the specified bitcode buffer and prepare for lazy
9599
/// deserialization of function bodies. If ShouldLazyLoadMetadata is true,
96-
/// lazily load metadata as well.
100+
/// lazily load metadata as well. If IsImporting is true, this module is
101+
/// being parsed for ThinLTO importing into another module.
97102
Expected<std::unique_ptr<Module>>
98103
getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context,
99-
bool ShouldLazyLoadMetadata = false);
104+
bool ShouldLazyLoadMetadata = false,
105+
bool IsImporting = false);
100106

101107
/// Like getLazyBitcodeModule, except that the module takes ownership of
102108
/// the memory buffer if successful. If successful, this moves Buffer. On
103-
/// error, this *does not* move Buffer.
104-
Expected<std::unique_ptr<Module>>
105-
getOwningLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
106-
LLVMContext &Context,
107-
bool ShouldLazyLoadMetadata = false);
109+
/// error, this *does not* move Buffer. If IsImporting is true, this module is
110+
/// being parsed for ThinLTO importing into another module.
111+
Expected<std::unique_ptr<Module>> getOwningLazyBitcodeModule(
112+
std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
113+
bool ShouldLazyLoadMetadata = false, bool IsImporting = false);
108114

109115
/// Read the header of the specified bitcode buffer and extract just the
110116
/// triple information. If successful, this returns a string. On error, this

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,8 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
488488

489489
/// \brief Main interface to parsing a bitcode buffer.
490490
/// \returns true if an error occurred.
491-
Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false);
491+
Error parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata = false,
492+
bool IsImporting = false);
492493

493494
static uint64_t decodeSignRotatedValue(uint64_t V);
494495

@@ -3084,9 +3085,10 @@ Error BitcodeReader::parseModule(uint64_t ResumeBit,
30843085
}
30853086
}
30863087

3087-
Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata) {
3088+
Error BitcodeReader::parseBitcodeInto(Module *M, bool ShouldLazyLoadMetadata,
3089+
bool IsImporting) {
30883090
TheModule = M;
3089-
MDLoader = MetadataLoader(Stream, *M, ValueList,
3091+
MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting,
30903092
[&](unsigned ID) { return getTypeByID(ID); });
30913093
return parseModule(0, ShouldLazyLoadMetadata);
30923094
}
@@ -5220,7 +5222,7 @@ llvm::getBitcodeModuleList(MemoryBufferRef Buffer) {
52205222
/// everything.
52215223
Expected<std::unique_ptr<Module>>
52225224
BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
5223-
bool ShouldLazyLoadMetadata) {
5225+
bool ShouldLazyLoadMetadata, bool IsImporting) {
52245226
BitstreamCursor Stream(Buffer);
52255227

52265228
std::string ProducerIdentification;
@@ -5243,7 +5245,8 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
52435245
M->setMaterializer(R);
52445246

52455247
// Delay parsing Metadata if ShouldLazyLoadMetadata is true.
5246-
if (Error Err = R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata))
5248+
if (Error Err =
5249+
R->parseBitcodeInto(M.get(), ShouldLazyLoadMetadata, IsImporting))
52475250
return std::move(Err);
52485251

52495252
if (MaterializeAll) {
@@ -5259,9 +5262,9 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
52595262
}
52605263

52615264
Expected<std::unique_ptr<Module>>
5262-
BitcodeModule::getLazyModule(LLVMContext &Context,
5263-
bool ShouldLazyLoadMetadata) {
5264-
return getModuleImpl(Context, false, ShouldLazyLoadMetadata);
5265+
BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata,
5266+
bool IsImporting) {
5267+
return getModuleImpl(Context, false, ShouldLazyLoadMetadata, IsImporting);
52655268
}
52665269

52675270
// Parse the specified bitcode buffer, returning the function info index.
@@ -5323,28 +5326,28 @@ static Expected<BitcodeModule> getSingleModule(MemoryBufferRef Buffer) {
53235326
}
53245327

53255328
Expected<std::unique_ptr<Module>>
5326-
llvm::getLazyBitcodeModule(MemoryBufferRef Buffer,
5327-
LLVMContext &Context, bool ShouldLazyLoadMetadata) {
5329+
llvm::getLazyBitcodeModule(MemoryBufferRef Buffer, LLVMContext &Context,
5330+
bool ShouldLazyLoadMetadata, bool IsImporting) {
53285331
Expected<BitcodeModule> BM = getSingleModule(Buffer);
53295332
if (!BM)
53305333
return BM.takeError();
53315334

5332-
return BM->getLazyModule(Context, ShouldLazyLoadMetadata);
5335+
return BM->getLazyModule(Context, ShouldLazyLoadMetadata, IsImporting);
53335336
}
53345337

5335-
Expected<std::unique_ptr<Module>>
5336-
llvm::getOwningLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
5337-
LLVMContext &Context,
5338-
bool ShouldLazyLoadMetadata) {
5339-
auto MOrErr = getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata);
5338+
Expected<std::unique_ptr<Module>> llvm::getOwningLazyBitcodeModule(
5339+
std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext &Context,
5340+
bool ShouldLazyLoadMetadata, bool IsImporting) {
5341+
auto MOrErr = getLazyBitcodeModule(*Buffer, Context, ShouldLazyLoadMetadata,
5342+
IsImporting);
53405343
if (MOrErr)
53415344
(*MOrErr)->setOwnedMemoryBuffer(std::move(Buffer));
53425345
return MOrErr;
53435346
}
53445347

53455348
Expected<std::unique_ptr<Module>>
53465349
BitcodeModule::parseModule(LLVMContext &Context) {
5347-
return getModuleImpl(Context, true, false);
5350+
return getModuleImpl(Context, true, false, false);
53485351
// TODO: Restore the use-lists to the in-memory state when the bitcode was
53495352
// written. We must defer until the Module has been fully materialized.
53505353
}

llvm/lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@
8686

8787
using namespace llvm;
8888

89+
/// Flag whether we need to import full type definitions for ThinLTO.
90+
/// Currently needed for Darwin and LLDB.
91+
static cl::opt<bool> ImportFullTypeDefinitions(
92+
"import-full-type-definitions", cl::init(false), cl::Hidden,
93+
cl::desc("Import full type definitions for ThinLTO."));
94+
8995
namespace {
9096

9197
static int64_t unrotateSign(uint64_t U) { return U & 1 ? ~(U >> 1) : U >> 1; }
@@ -399,7 +405,7 @@ class MetadataLoader::MetadataLoaderImpl {
399405
Stream(Stream), Context(TheModule.getContext()), TheModule(TheModule),
400406
getTypeByID(getTypeByID) {}
401407

402-
Error parseMetadata(bool ModuleLevel);
408+
Error parseMetadata(bool ModuleLevel, bool IsImporting);
403409

404410
bool hasFwdRefs() const { return MetadataList.hasFwdRefs(); }
405411
Metadata *getMetadataFwdRef(unsigned Idx) {
@@ -435,7 +441,8 @@ Error error(const Twine &Message) {
435441

436442
/// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing
437443
/// module level metadata.
438-
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
444+
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel,
445+
bool IsImporting) {
439446
if (!ModuleLevel && MetadataList.hasFwdRefs())
440447
return error("Invalid metadata: fwd refs into function blocks");
441448

@@ -709,18 +716,38 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
709716
Metadata *File = getMDOrNull(Record[3]);
710717
unsigned Line = Record[4];
711718
Metadata *Scope = getDITypeRefOrNull(Record[5]);
712-
Metadata *BaseType = getDITypeRefOrNull(Record[6]);
719+
Metadata *BaseType = nullptr;
713720
uint64_t SizeInBits = Record[7];
714721
if (Record[8] > (uint64_t)std::numeric_limits<uint32_t>::max())
715722
return error("Alignment value is too large");
716723
uint32_t AlignInBits = Record[8];
717-
uint64_t OffsetInBits = Record[9];
724+
uint64_t OffsetInBits = 0;
718725
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(Record[10]);
719-
Metadata *Elements = getMDOrNull(Record[11]);
726+
Metadata *Elements = nullptr;
720727
unsigned RuntimeLang = Record[12];
721-
Metadata *VTableHolder = getDITypeRefOrNull(Record[13]);
722-
Metadata *TemplateParams = getMDOrNull(Record[14]);
728+
Metadata *VTableHolder = nullptr;
729+
Metadata *TemplateParams = nullptr;
723730
auto *Identifier = getMDString(Record[15]);
731+
// If this module is being parsed so that it can be ThinLTO imported
732+
// into another module, composite types only need to be imported
733+
// as type declarations (unless full type definitions requested).
734+
// Create type declarations up front to save memory. Also, buildODRType
735+
// handles the case where this is type ODRed with a definition needed
736+
// by the importing module, in which case the existing definition is
737+
// used.
738+
if (IsImporting && !ImportFullTypeDefinitions &&
739+
(Tag == dwarf::DW_TAG_enumeration_type ||
740+
Tag == dwarf::DW_TAG_class_type ||
741+
Tag == dwarf::DW_TAG_structure_type ||
742+
Tag == dwarf::DW_TAG_union_type)) {
743+
Flags = Flags | DINode::FlagFwdDecl;
744+
} else {
745+
BaseType = getDITypeRefOrNull(Record[6]);
746+
OffsetInBits = Record[9];
747+
Elements = getMDOrNull(Record[11]);
748+
VTableHolder = getDITypeRefOrNull(Record[13]);
749+
TemplateParams = getMDOrNull(Record[14]);
750+
}
724751
DICompositeType *CT = nullptr;
725752
if (Identifier)
726753
CT = DICompositeType::buildODRType(
@@ -1281,17 +1308,19 @@ MetadataLoader &MetadataLoader::operator=(MetadataLoader &&RHS) {
12811308
return *this;
12821309
}
12831310
MetadataLoader::MetadataLoader(MetadataLoader &&RHS)
1284-
: Pimpl(std::move(RHS.Pimpl)) {}
1311+
: Pimpl(std::move(RHS.Pimpl)), IsImporting(RHS.IsImporting) {}
12851312

12861313
MetadataLoader::~MetadataLoader() = default;
12871314
MetadataLoader::MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
12881315
BitcodeReaderValueList &ValueList,
1316+
bool IsImporting,
12891317
std::function<Type *(unsigned)> getTypeByID)
12901318
: Pimpl(llvm::make_unique<MetadataLoaderImpl>(Stream, TheModule, ValueList,
1291-
getTypeByID)) {}
1319+
getTypeByID)),
1320+
IsImporting(IsImporting) {}
12921321

12931322
Error MetadataLoader::parseMetadata(bool ModuleLevel) {
1294-
return Pimpl->parseMetadata(ModuleLevel);
1323+
return Pimpl->parseMetadata(ModuleLevel, IsImporting);
12951324
}
12961325

12971326
bool MetadataLoader::hasFwdRefs() const { return Pimpl->hasFwdRefs(); }

llvm/lib/Bitcode/Reader/MetadataLoader.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ class Type;
3636
class MetadataLoader {
3737
class MetadataLoaderImpl;
3838
std::unique_ptr<MetadataLoaderImpl> Pimpl;
39+
/// True if metadata is being parsed for a module being ThinLTO imported.
40+
bool IsImporting = false;
3941
Error parseMetadata(bool ModuleLevel);
4042

4143
public:
4244
~MetadataLoader();
4345
MetadataLoader(BitstreamCursor &Stream, Module &TheModule,
44-
BitcodeReaderValueList &ValueList,
46+
BitcodeReaderValueList &ValueList, bool IsImporting,
4547
std::function<Type *(unsigned)> getTypeByID);
4648
MetadataLoader &operator=(MetadataLoader &&);
4749
MetadataLoader(MetadataLoader &&);

llvm/lib/LTO/LTO.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
252252
// ModuleSymbolTable.
253253
for (auto BM : *BMsOrErr) {
254254
Expected<std::unique_ptr<Module>> MOrErr =
255-
BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true);
255+
BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true,
256+
/*IsImporting*/ false);
256257
if (!MOrErr)
257258
return MOrErr.takeError();
258259

@@ -415,7 +416,8 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
415416
RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule);
416417
}
417418
Expected<std::unique_ptr<Module>> MOrErr =
418-
BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true);
419+
BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true,
420+
/*IsImporting*/ false);
419421
if (!MOrErr)
420422
return MOrErr.takeError();
421423

llvm/lib/LTO/LTOBackend.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,
356356
auto I = ModuleMap.find(Identifier);
357357
assert(I != ModuleMap.end());
358358
return I->second.getLazyModule(Mod.getContext(),
359-
/*ShouldLazyLoadMetadata=*/true);
359+
/*ShouldLazyLoadMetadata=*/true,
360+
/*IsImporting*/ true);
360361
};
361362

362363
FunctionImporter Importer(CombinedIndex, ModuleLoader);

llvm/lib/LTO/ThinLTOCodeGenerator.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,13 @@ static void promoteModule(Module &TheModule, const ModuleSummaryIndex &Index) {
168168

169169
static std::unique_ptr<Module>
170170
loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context,
171-
bool Lazy) {
171+
bool Lazy, bool IsImporting) {
172172
SMDiagnostic Err;
173173
Expected<std::unique_ptr<Module>> ModuleOrErr =
174-
Lazy ? getLazyBitcodeModule(Buffer, Context,
175-
/* ShouldLazyLoadMetadata */ true)
176-
: parseBitcodeFile(Buffer, Context);
174+
Lazy
175+
? getLazyBitcodeModule(Buffer, Context,
176+
/* ShouldLazyLoadMetadata */ true, IsImporting)
177+
: parseBitcodeFile(Buffer, Context);
177178
if (!ModuleOrErr) {
178179
handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
179180
SMDiagnostic Err = SMDiagnostic(Buffer.getBufferIdentifier(),
@@ -191,7 +192,7 @@ crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index,
191192
const FunctionImporter::ImportMapTy &ImportList) {
192193
auto Loader = [&](StringRef Identifier) {
193194
return loadModuleFromBuffer(ModuleMap[Identifier], TheModule.getContext(),
194-
/*Lazy=*/true);
195+
/*Lazy=*/true, /*IsImporting*/ true);
195196
};
196197

197198
FunctionImporter Importer(Index, Loader);
@@ -787,7 +788,8 @@ void ThinLTOCodeGenerator::run() {
787788
Context.setDiscardValueNames(LTODiscardValueNames);
788789

789790
// Parse module now
790-
auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false);
791+
auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false,
792+
/*IsImporting*/ false);
791793

792794
// CodeGen
793795
ProducedBinaries[count] = codegen(*TheModule);
@@ -933,7 +935,8 @@ void ThinLTOCodeGenerator::run() {
933935
}
934936

935937
// Parse module now
936-
auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false);
938+
auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false,
939+
/*IsImporting*/ false);
937940

938941
// Save temps: original file.
939942
saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc");

llvm/lib/Object/IRObjectFile.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) {
127127
std::vector<std::unique_ptr<Module>> Mods;
128128
for (auto BM : *BMsOrErr) {
129129
Expected<std::unique_ptr<Module>> MOrErr =
130-
BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true);
130+
BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true,
131+
/*IsImporting*/ false);
131132
if (!MOrErr)
132133
return MOrErr.takeError();
133134

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; ModuleID = 'debuginfo-compositetype-import2.c'
2+
source_filename = "debuginfo-compositetype-import2.c"
3+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
; Function Attrs: nounwind uwtable
7+
define i32 @main() {
8+
entry:
9+
call void (...) @foo()
10+
ret i32 0
11+
}
12+
13+
declare void @foo(...) #1

0 commit comments

Comments
 (0)