diff --git a/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h b/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h --- a/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h +++ b/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -41,6 +41,8 @@ #include "llvm/ADT/StringSet.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" +#include "llvm/LTO/Config.h" +#include "llvm/LTO/LTO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/ToolOutputFile.h" @@ -73,6 +75,10 @@ LTOCodeGenerator(LLVMContext &Context); ~LTOCodeGenerator(); + /// Return a lto::Config object which contains the options set in + /// LTOCodeGenerator. + lto::Config toConfig() const; + /// Merge given module. Return true on success. /// /// Resets \a HasVerifiedInput. @@ -165,14 +171,14 @@ /// if the compilation was not successful. std::unique_ptr<MemoryBuffer> compileOptimized(); - /// Compile the merged optimized module into out.size() output files each + /// Compile the merged optimized module \p ParallelismLevel output files each /// representing a linkable partition of the module. If out contains more - /// than one element, code generation is done in parallel with out.size() - /// threads. Output files will be written to members of out. Returns true on - /// success. + /// than one element, code generation is done in parallel with \p + /// ParallelismLevel threads. Output files will be written to the streams + /// created using the \p AddStream callback. Returns true on success. /// /// Calls \a verifyMergedModuleOnce(). - bool compileOptimized(ArrayRef<raw_pwrite_stream *> Out); + bool compileOptimized(lto::AddStreamFn AddStream, unsigned ParallelismLevel); /// Enable the Freestanding mode: indicate that the optimizer should not /// assume builtins are present on the target. @@ -188,8 +194,6 @@ void DiagnosticHandler(const DiagnosticInfo &DI); private: - void initializeLTOPasses(); - /// Verify the merged module on first call. /// /// Sets \a HasVerifiedInput on first call and doesn't run again on the same diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -37,6 +37,7 @@ #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" #include "llvm/LTO/LTO.h" +#include "llvm/LTO/LTOBackend.h" #include "llvm/LTO/legacy/LTOModule.h" #include "llvm/LTO/legacy/UpdateCompilerUsed.h" #include "llvm/Linker/Linker.h" @@ -123,41 +124,29 @@ TheLinker(new Linker(*MergedModule)) { Context.setDiscardValueNames(LTODiscardValueNames); Context.enableDebugTypeODRUniquing(); - initializeLTOPasses(); } LTOCodeGenerator::~LTOCodeGenerator() {} -// Initialize LTO passes. Please keep this function in sync with -// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO -// passes are initialized. -void LTOCodeGenerator::initializeLTOPasses() { - PassRegistry &R = *PassRegistry::getPassRegistry(); - - initializeInternalizeLegacyPassPass(R); - initializeIPSCCPLegacyPassPass(R); - initializeGlobalOptLegacyPassPass(R); - initializeConstantMergeLegacyPassPass(R); - initializeDAHPass(R); - initializeInstructionCombiningPassPass(R); - initializeSimpleInlinerPass(R); - initializePruneEHPass(R); - initializeGlobalDCELegacyPassPass(R); - initializeOpenMPOptLegacyPassPass(R); - initializeArgPromotionPass(R); - initializeJumpThreadingPass(R); - initializeSROALegacyPassPass(R); - initializeAttributorLegacyPassPass(R); - initializeAttributorCGSCCLegacyPassPass(R); - initializePostOrderFunctionAttrsLegacyPassPass(R); - initializeReversePostOrderFunctionAttrsLegacyPassPass(R); - initializeGlobalsAAWrapperPassPass(R); - initializeLegacyLICMPassPass(R); - initializeMergedLoadStoreMotionLegacyPassPass(R); - initializeGVNLegacyPassPass(R); - initializeMemCpyOptLegacyPassPass(R); - initializeDCELegacyPassPass(R); - initializeCFGSimplifyPassPass(R); +lto::Config LTOCodeGenerator::toConfig() const { + lto::Config Conf; + Conf.CGFileType = FileType; + Conf.CPU = MCpu; + Conf.MAttrs = MAttrs; + Conf.RelocModel = RelocModel; + Conf.Options = Options; + Conf.CodeModel = None; + Conf.StatsFile = LTOStatsFile; + Conf.OptLevel = OptLevel; + Conf.Freestanding = Freestanding; + Conf.PTO.LoopVectorization = OptLevel > 1; + Conf.PTO.SLPVectorization = OptLevel > 1; + Conf.DisableVerify = DisableVerify; + Conf.PreCodeGenPassesHook = [](legacy::PassManager &PM) { + PM.add(createObjCARCContractPass()); + }; + + return Conf; } void LTOCodeGenerator::setAsmUndefinedRefs(LTOModule *Mod) { @@ -268,38 +257,35 @@ bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) { // make unique temp output file to put generated code SmallString<128> Filename; - int FD; - StringRef Extension - (FileType == CGFT_AssemblyFile ? "s" : "o"); + auto AddStream = + [&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> { + StringRef Extension(FileType == CGFT_AssemblyFile ? "s" : "o"); - std::error_code EC = - sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); - if (EC) { - emitError(EC.message()); - return false; - } + int FD; + std::error_code EC = + sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); + if (EC) + emitError(EC.message()); - // generate object file - ToolOutputFile objFile(Filename, FD); + return std::make_unique<lto::NativeObjectStream>( + std::make_unique<llvm::raw_fd_ostream>(FD, true)); + }; - bool genResult = compileOptimized(&objFile.os()); - objFile.os().close(); - if (objFile.os().has_error()) { - emitError((Twine("could not write object file: ") + Filename + ": " + - objFile.os().error().message()) - .str()); - objFile.os().clear_error(); - sys::fs::remove(Twine(Filename)); - return false; - } + bool genResult = compileOptimized(AddStream, 1); - objFile.keep(); if (!genResult) { sys::fs::remove(Twine(Filename)); return false; } + // If statistics were requested, save them to the specified file or + // print them out after codegen. + if (StatsFile) + PrintStatisticsJSON(StatsFile->os()); + else if (AreStatisticsEnabled()) + PrintStatistics(); + NativeObjectPath = Filename.c_str(); *Name = NativeObjectPath.c_str(); return true; @@ -568,36 +554,25 @@ // Write LTOPostLink flag for passes that require all the modules. MergedModule->addModuleFlag(Module::Error, "LTOPostLink", 1); - // Instantiate the pass manager to organize the passes. - legacy::PassManager passes; - // Add an appropriate DataLayout instance for this module... MergedModule->setDataLayout(TargetMach->createDataLayout()); - passes.add( - createTargetTransformInfoWrapperPass(TargetMach->getTargetIRAnalysis())); - - Triple TargetTriple(TargetMach->getTargetTriple()); - PassManagerBuilder PMB; - PMB.LoopVectorize = true; - PMB.SLPVectorize = true; - PMB.Inliner = createFunctionInliningPass(); - PMB.LibraryInfo = new TargetLibraryInfoImpl(TargetTriple); - if (Freestanding) - PMB.LibraryInfo->disableAllFunctions(); - PMB.OptLevel = OptLevel; - PMB.VerifyInput = !DisableVerify; - PMB.VerifyOutput = !DisableVerify; - - PMB.populateLTOPassManager(passes); + lto::Config Conf = toConfig(); - // Run our queue of passes all at once now, efficiently. - passes.run(*MergedModule); + ModuleSummaryIndex CombinedIndex(false); + TargetMach = createTargetMachine(); + if (!opt(Conf, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false, + /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, + /*CmdArgs*/ std::vector<uint8_t>())) { + emitError("LTO middle-end optimizations failed"); + return false; + } return true; } -bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) { +bool LTOCodeGenerator::compileOptimized(lto::AddStreamFn AddStream, + unsigned ParallelismLevel) { if (!this->determineTarget()) return false; @@ -605,20 +580,17 @@ // been called in optimize(), this call will return early. verifyMergedModuleOnce(); - legacy::PassManager preCodeGenPasses; - - // If the bitcode files contain ARC code and were compiled with optimization, - // the ObjCARCContractPass must be run, so do it unconditionally here. - preCodeGenPasses.add(createObjCARCContractPass()); - preCodeGenPasses.run(*MergedModule); - // Re-externalize globals that may have been internalized to increase scope // for splitting restoreLinkageForExternals(); - splitCodeGen( - *MergedModule, Out, {}, [&]() { return createTargetMachine(); }, FileType, - ShouldRestoreGlobalsLinkage); + lto::Config Conf = toConfig(); + ModuleSummaryIndex CombinedIndex(false); + + Error Err = + backend(Conf, AddStream, ParallelismLevel, *MergedModule, CombinedIndex); + assert(!Err && "unexpected code-generation failure"); + (void)Err; // If statistics were requested, save them to the specified file or // print them out after codegen. diff --git a/llvm/test/LTO/X86/disable-verify.ll b/llvm/test/LTO/X86/disable-verify.ll --- a/llvm/test/LTO/X86/disable-verify.ll +++ b/llvm/test/LTO/X86/disable-verify.ll @@ -7,7 +7,7 @@ ; -disable-verify should disable verification from the optimization pipeline. ; CHECK: Pass Arguments: -; CHECK-NOT: -verify +; CHECK-NOT: -verify {{.*}} -verify ; VERIFY: Pass Arguments: {{.*}} -verify {{.*}} -verify diff --git a/llvm/test/tools/lto/print-stats.ll b/llvm/test/tools/lto/print-stats.ll --- a/llvm/test/tools/lto/print-stats.ll +++ b/llvm/test/tools/lto/print-stats.ll @@ -5,5 +5,12 @@ target triple = "x86_64-apple-macosx10.8.0" +define i32 @test(i32 %a) { + %r = add i32 %a, 1 + %r.1 = add i32 1, %a + %r.2 = add i32 %r, %r.1 + ret i32 %r.2 +} + ; STATS: Statistics Collected ; NO_STATS-NOT: Statistics Collected diff --git a/llvm/tools/llvm-lto/llvm-lto.cpp b/llvm/tools/llvm-lto/llvm-lto.cpp --- a/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/llvm/tools/llvm-lto/llvm-lto.cpp @@ -1041,25 +1041,24 @@ error("writing merged module failed."); } - std::list<ToolOutputFile> OSs; - std::vector<raw_pwrite_stream *> OSPtrs; - for (unsigned I = 0; I != Parallelism; ++I) { + auto AddStream = + [&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> { std::string PartFilename = OutputFilename; if (Parallelism != 1) - PartFilename += "." + utostr(I); + PartFilename += "." + utostr(Task); + std::error_code EC; - OSs.emplace_back(PartFilename, EC, sys::fs::OF_None); + auto S = + std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None); if (EC) error("error opening the file '" + PartFilename + "': " + EC.message()); - OSPtrs.push_back(&OSs.back().os()); - } + return std::make_unique<lto::NativeObjectStream>(std::move(S)); + }; - if (!CodeGen.compileOptimized(OSPtrs)) + if (!CodeGen.compileOptimized(AddStream, Parallelism)) // Diagnostic messages should have been printed by the handler. error("error compiling the code"); - for (ToolOutputFile &OS : OSs) - OS.keep(); } else { if (Parallelism != 1) error("-j must be specified together with -o");