Skip to content

Commit 6a59f05

Browse files
committed
[LTO] Use lto::backend for code generation.
This patch updates LTOCodeGenerator to use the utilities provided by LTOBackend to run middle-end optimizations and backend code generation. This is a first step towards unifying the code used by libLTO's C API and the newer, C++ interface (see PR41541). The immediate motivation is to allow using the new pass manager when doing LTO using libLTO's C API, which is used on Darwin, among others. With the changes, there are no codegen/stats differences when building MultiSource/SPEC2000/SPEC2006 on Darwin X86 with LTO, compared to without the patch. Reviewed By: steven_wu Differential Revision: https://reviews.llvm.org/D94487
1 parent 3949a3e commit 6a59f05

File tree

5 files changed

+85
-103
lines changed

5 files changed

+85
-103
lines changed

llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#include "llvm/ADT/StringSet.h"
4242
#include "llvm/IR/GlobalValue.h"
4343
#include "llvm/IR/Module.h"
44+
#include "llvm/LTO/Config.h"
45+
#include "llvm/LTO/LTO.h"
4446
#include "llvm/Support/CommandLine.h"
4547
#include "llvm/Support/Error.h"
4648
#include "llvm/Support/ToolOutputFile.h"
@@ -73,6 +75,10 @@ struct LTOCodeGenerator {
7375
LTOCodeGenerator(LLVMContext &Context);
7476
~LTOCodeGenerator();
7577

78+
/// Return a lto::Config object which contains the options set in
79+
/// LTOCodeGenerator.
80+
lto::Config toConfig() const;
81+
7682
/// Merge given module. Return true on success.
7783
///
7884
/// Resets \a HasVerifiedInput.
@@ -165,14 +171,14 @@ struct LTOCodeGenerator {
165171
/// if the compilation was not successful.
166172
std::unique_ptr<MemoryBuffer> compileOptimized();
167173

168-
/// Compile the merged optimized module into out.size() output files each
174+
/// Compile the merged optimized module \p ParallelismLevel output files each
169175
/// representing a linkable partition of the module. If out contains more
170-
/// than one element, code generation is done in parallel with out.size()
171-
/// threads. Output files will be written to members of out. Returns true on
172-
/// success.
176+
/// than one element, code generation is done in parallel with \p
177+
/// ParallelismLevel threads. Output files will be written to the streams
178+
/// created using the \p AddStream callback. Returns true on success.
173179
///
174180
/// Calls \a verifyMergedModuleOnce().
175-
bool compileOptimized(ArrayRef<raw_pwrite_stream *> Out);
181+
bool compileOptimized(lto::AddStreamFn AddStream, unsigned ParallelismLevel);
176182

177183
/// Enable the Freestanding mode: indicate that the optimizer should not
178184
/// assume builtins are present on the target.
@@ -188,8 +194,6 @@ struct LTOCodeGenerator {
188194
void DiagnosticHandler(const DiagnosticInfo &DI);
189195

190196
private:
191-
void initializeLTOPasses();
192-
193197
/// Verify the merged module on first call.
194198
///
195199
/// Sets \a HasVerifiedInput on first call and doesn't run again on the same

llvm/lib/LTO/LTOCodeGenerator.cpp

Lines changed: 57 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "llvm/IR/Verifier.h"
3838
#include "llvm/InitializePasses.h"
3939
#include "llvm/LTO/LTO.h"
40+
#include "llvm/LTO/LTOBackend.h"
4041
#include "llvm/LTO/legacy/LTOModule.h"
4142
#include "llvm/LTO/legacy/UpdateCompilerUsed.h"
4243
#include "llvm/Linker/Linker.h"
@@ -123,41 +124,29 @@ LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context)
123124
TheLinker(new Linker(*MergedModule)) {
124125
Context.setDiscardValueNames(LTODiscardValueNames);
125126
Context.enableDebugTypeODRUniquing();
126-
initializeLTOPasses();
127127
}
128128

129129
LTOCodeGenerator::~LTOCodeGenerator() {}
130130

131-
// Initialize LTO passes. Please keep this function in sync with
132-
// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO
133-
// passes are initialized.
134-
void LTOCodeGenerator::initializeLTOPasses() {
135-
PassRegistry &R = *PassRegistry::getPassRegistry();
136-
137-
initializeInternalizeLegacyPassPass(R);
138-
initializeIPSCCPLegacyPassPass(R);
139-
initializeGlobalOptLegacyPassPass(R);
140-
initializeConstantMergeLegacyPassPass(R);
141-
initializeDAHPass(R);
142-
initializeInstructionCombiningPassPass(R);
143-
initializeSimpleInlinerPass(R);
144-
initializePruneEHPass(R);
145-
initializeGlobalDCELegacyPassPass(R);
146-
initializeOpenMPOptLegacyPassPass(R);
147-
initializeArgPromotionPass(R);
148-
initializeJumpThreadingPass(R);
149-
initializeSROALegacyPassPass(R);
150-
initializeAttributorLegacyPassPass(R);
151-
initializeAttributorCGSCCLegacyPassPass(R);
152-
initializePostOrderFunctionAttrsLegacyPassPass(R);
153-
initializeReversePostOrderFunctionAttrsLegacyPassPass(R);
154-
initializeGlobalsAAWrapperPassPass(R);
155-
initializeLegacyLICMPassPass(R);
156-
initializeMergedLoadStoreMotionLegacyPassPass(R);
157-
initializeGVNLegacyPassPass(R);
158-
initializeMemCpyOptLegacyPassPass(R);
159-
initializeDCELegacyPassPass(R);
160-
initializeCFGSimplifyPassPass(R);
131+
lto::Config LTOCodeGenerator::toConfig() const {
132+
lto::Config Conf;
133+
Conf.CGFileType = FileType;
134+
Conf.CPU = MCpu;
135+
Conf.MAttrs = MAttrs;
136+
Conf.RelocModel = RelocModel;
137+
Conf.Options = Options;
138+
Conf.CodeModel = None;
139+
Conf.StatsFile = LTOStatsFile;
140+
Conf.OptLevel = OptLevel;
141+
Conf.Freestanding = Freestanding;
142+
Conf.PTO.LoopVectorization = OptLevel > 1;
143+
Conf.PTO.SLPVectorization = OptLevel > 1;
144+
Conf.DisableVerify = DisableVerify;
145+
Conf.PreCodeGenPassesHook = [](legacy::PassManager &PM) {
146+
PM.add(createObjCARCContractPass());
147+
};
148+
149+
return Conf;
161150
}
162151

163152
void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) {
@@ -268,38 +257,35 @@ bool LTOCodeGenerator::writeMergedModules(StringRef Path) {
268257
bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) {
269258
// make unique temp output file to put generated code
270259
SmallString<128> Filename;
271-
int FD;
272260

273-
StringRef Extension
274-
(FileType == CGFT_AssemblyFile ? "s" : "o");
261+
auto AddStream =
262+
[&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
263+
StringRef Extension(FileType == CGFT_AssemblyFile ? "s" : "o");
275264

276-
std::error_code EC =
277-
sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename);
278-
if (EC) {
279-
emitError(EC.message());
280-
return false;
281-
}
265+
int FD;
266+
std::error_code EC =
267+
sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename);
268+
if (EC)
269+
emitError(EC.message());
282270

283-
// generate object file
284-
ToolOutputFile objFile(Filename, FD);
271+
return std::make_unique<lto::NativeObjectStream>(
272+
std::make_unique<llvm::raw_fd_ostream>(FD, true));
273+
};
285274

286-
bool genResult = compileOptimized(&objFile.os());
287-
objFile.os().close();
288-
if (objFile.os().has_error()) {
289-
emitError((Twine("could not write object file: ") + Filename + ": " +
290-
objFile.os().error().message())
291-
.str());
292-
objFile.os().clear_error();
293-
sys::fs::remove(Twine(Filename));
294-
return false;
295-
}
275+
bool genResult = compileOptimized(AddStream, 1);
296276

297-
objFile.keep();
298277
if (!genResult) {
299278
sys::fs::remove(Twine(Filename));
300279
return false;
301280
}
302281

282+
// If statistics were requested, save them to the specified file or
283+
// print them out after codegen.
284+
if (StatsFile)
285+
PrintStatisticsJSON(StatsFile->os());
286+
else if (AreStatisticsEnabled())
287+
PrintStatistics();
288+
303289
NativeObjectPath = Filename.c_str();
304290
*Name = NativeObjectPath.c_str();
305291
return true;
@@ -568,57 +554,43 @@ bool LTOCodeGenerator::optimize() {
568554
// Write LTOPostLink flag for passes that require all the modules.
569555
MergedModule->addModuleFlag(Module::Error, "LTOPostLink", 1);
570556

571-
// Instantiate the pass manager to organize the passes.
572-
legacy::PassManager passes;
573-
574557
// Add an appropriate DataLayout instance for this module...
575558
MergedModule->setDataLayout(TargetMach->createDataLayout());
576559

577-
passes.add(
578-
createTargetTransformInfoWrapperPass(TargetMach->getTargetIRAnalysis()));
579-
580-
Triple TargetTriple(TargetMach->getTargetTriple());
581-
PassManagerBuilder PMB;
582-
PMB.LoopVectorize = true;
583-
PMB.SLPVectorize = true;
584-
PMB.Inliner = createFunctionInliningPass();
585-
PMB.LibraryInfo = new TargetLibraryInfoImpl(TargetTriple);
586-
if (Freestanding)
587-
PMB.LibraryInfo->disableAllFunctions();
588-
PMB.OptLevel = OptLevel;
589-
PMB.VerifyInput = !DisableVerify;
590-
PMB.VerifyOutput = !DisableVerify;
591-
592-
PMB.populateLTOPassManager(passes);
560+
lto::Config Conf = toConfig();
593561

594-
// Run our queue of passes all at once now, efficiently.
595-
passes.run(*MergedModule);
562+
ModuleSummaryIndex CombinedIndex(false);
563+
TargetMach = createTargetMachine();
564+
if (!opt(Conf, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false,
565+
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
566+
/*CmdArgs*/ std::vector<uint8_t>())) {
567+
emitError("LTO middle-end optimizations failed");
568+
return false;
569+
}
596570

597571
return true;
598572
}
599573

600-
bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) {
574+
bool LTOCodeGenerator::compileOptimized(lto::AddStreamFn AddStream,
575+
unsigned ParallelismLevel) {
601576
if (!this->determineTarget())
602577
return false;
603578

604579
// We always run the verifier once on the merged module. If it has already
605580
// been called in optimize(), this call will return early.
606581
verifyMergedModuleOnce();
607582

608-
legacy::PassManager preCodeGenPasses;
609-
610-
// If the bitcode files contain ARC code and were compiled with optimization,
611-
// the ObjCARCContractPass must be run, so do it unconditionally here.
612-
preCodeGenPasses.add(createObjCARCContractPass());
613-
preCodeGenPasses.run(*MergedModule);
614-
615583
// Re-externalize globals that may have been internalized to increase scope
616584
// for splitting
617585
restoreLinkageForExternals();
618586

619-
splitCodeGen(
620-
*MergedModule, Out, {}, [&]() { return createTargetMachine(); }, FileType,
621-
ShouldRestoreGlobalsLinkage);
587+
lto::Config Conf = toConfig();
588+
ModuleSummaryIndex CombinedIndex(false);
589+
590+
Error Err =
591+
backend(Conf, AddStream, ParallelismLevel, *MergedModule, CombinedIndex);
592+
assert(!Err && "unexpected code-generation failure");
593+
(void)Err;
622594

623595
// If statistics were requested, save them to the specified file or
624596
// print them out after codegen.

llvm/test/LTO/X86/disable-verify.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ target triple = "x86_64-apple-macosx10.10.0"
77

88
; -disable-verify should disable verification from the optimization pipeline.
99
; CHECK: Pass Arguments:
10-
; CHECK-NOT: -verify
10+
; CHECK-NOT: -verify {{.*}} -verify
1111

1212
; VERIFY: Pass Arguments: {{.*}} -verify {{.*}} -verify
1313

llvm/test/tools/lto/print-stats.ll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,12 @@
55

66
target triple = "x86_64-apple-macosx10.8.0"
77

8+
define i32 @test(i32 %a) {
9+
%r = add i32 %a, 1
10+
%r.1 = add i32 1, %a
11+
%r.2 = add i32 %r, %r.1
12+
ret i32 %r.2
13+
}
14+
815
; STATS: Statistics Collected
916
; NO_STATS-NOT: Statistics Collected

llvm/tools/llvm-lto/llvm-lto.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,25 +1041,24 @@ int main(int argc, char **argv) {
10411041
error("writing merged module failed.");
10421042
}
10431043

1044-
std::list<ToolOutputFile> OSs;
1045-
std::vector<raw_pwrite_stream *> OSPtrs;
1046-
for (unsigned I = 0; I != Parallelism; ++I) {
1044+
auto AddStream =
1045+
[&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
10471046
std::string PartFilename = OutputFilename;
10481047
if (Parallelism != 1)
1049-
PartFilename += "." + utostr(I);
1048+
PartFilename += "." + utostr(Task);
1049+
10501050
std::error_code EC;
1051-
OSs.emplace_back(PartFilename, EC, sys::fs::OF_None);
1051+
auto S =
1052+
std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None);
10521053
if (EC)
10531054
error("error opening the file '" + PartFilename + "': " + EC.message());
1054-
OSPtrs.push_back(&OSs.back().os());
1055-
}
1055+
return std::make_unique<lto::NativeObjectStream>(std::move(S));
1056+
};
10561057

1057-
if (!CodeGen.compileOptimized(OSPtrs))
1058+
if (!CodeGen.compileOptimized(AddStream, Parallelism))
10581059
// Diagnostic messages should have been printed by the handler.
10591060
error("error compiling the code");
10601061

1061-
for (ToolOutputFile &OS : OSs)
1062-
OS.keep();
10631062
} else {
10641063
if (Parallelism != 1)
10651064
error("-j must be specified together with -o");

0 commit comments

Comments
 (0)