tejohnson created this revision. tejohnson added reviewers: joker.eph, dexonsmith. tejohnson added subscribers: cfe-commits, davidxl. tejohnson added a dependency: D15024: [ThinLTO] Support for specifying function index from pass manager. Herald added a subscriber: joker.eph.
Adds new option -fthinlto-backend=<file> to invoke the LTO pipeline along with function importing via clang using the supplied function summary index file. This supports invoking the parallel ThinLTO backend processes in a distributed build environment via clang. Additionally, this causes the module linker to be invoked on the bitcode file being compiled to perform any necessary promotion and renaming of locals that are exported via the function summary index file. Add a couple tests that confirm we get expected errors when we try to use the new option on a file that isn't bitcode, or specify an invalid index file. The tests also confirm that we trigger the expected function import pass. Depends on D15024 http://reviews.llvm.org/D15025 Files: include/clang/Driver/Options.td include/clang/Driver/Types.h include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/CodeGen/CodeGenAction.cpp lib/Driver/Tools.cpp lib/Driver/Types.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/thinlto_backend.c test/Driver/thinlto_backend.c
Index: test/Driver/thinlto_backend.c =================================================================== --- /dev/null +++ test/Driver/thinlto_backend.c @@ -0,0 +1,12 @@ +// RUN: %clang -target x86_64-unknown-linux -O2 %s -flto=thin -c -o %t.o +// RUN: %clang -target x86_64-unknown-linux -O2 -flto=thin -fuse-ld=gold -o %t %t.o + +// -fthinlto_backend should be passed to cc1 +// RUN: %clang -target x86_64-unknown-linux -O2 -o %t1.o -x ir %t.o -c -fthinlto-backend=%t.thinlto.bc -### 2> %t +// RUN: FileCheck -check-prefix=CHECK-THINLTOBE-ACTION < %t %s +// CHECK-THINLTOBE-ACTION: -fthinlto-backend= + +// Ensure clang driver gives the expected error for incorrect input type +// RUN: not %clang -target x86_64-unknown-linux -O2 -o %t1.o %s -c -fthinlto-backend=%t.thinlto.bc 2> %t +// RUN: FileCheck -check-prefix=CHECK-WARNING < %t %s +// CHECK-WARNING: error: invalid argument '-fthinlto-backend={{.*}}' only allowed with '-x ir' Index: test/CodeGen/thinlto_backend.c =================================================================== --- /dev/null +++ test/CodeGen/thinlto_backend.c @@ -0,0 +1,17 @@ +// RUN: %clang -target x86_64-unknown-linux -O2 %s -flto=thin -c -o %t.o +// RUN: %clang -target x86_64-unknown-linux -O2 -flto=thin -fuse-ld=gold -o %t %t.o + +// Ensure clang -cc1 give expected error for incorrect input type +// RUN: not %clang_cc1 -target x86_64-unknown-linux -O2 -o %t1.o %s -c -fthinlto-backend=%t.thinlto.bc 2> %t +// RUN: FileCheck -check-prefix=CHECK-WARNING < %t %s +// CHECK-WARNING: error: invalid argument '-fthinlto-backend={{.*}}' only allowed with '-x ir' + +// Ensure we get expected error for missing index file +// RUN: %clang -target x86_64-unknown-linux -O2 -o %t1.o -x ir %t.o -c -fthinlto-backend=bad.thinlto.bc 2> %t +// RUN: FileCheck -check-prefix=CHECK-ERROR < %t %s +// CHECK-ERROR: Error loading index file 'bad.thinlto.bc': No such file or directory + +// Ensure Function Importing pass added +// RUN: %clang -target x86_64-unknown-linux -O2 -o %t1.o -x ir %t.o -c -fthinlto-backend=%t.thinlto.bc -mllvm -debug-pass=Structure 2> %t +// RUN: FileCheck -check-prefix=CHECK-PASS < %t %s +// CHECK-PASS: Function Importing Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -521,6 +521,12 @@ Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ); Opts.EmitFunctionSummary = A && A->containsValue("thin"); + if (Arg *A = Args.getLastArg(OPT_fthinlto_backend_EQ)) { + if (IK != IK_LLVM_IR) + Diags.Report(diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-x ir"; + Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_backend_EQ); + } Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); Index: lib/Driver/Types.cpp =================================================================== --- lib/Driver/Types.cpp +++ lib/Driver/Types.cpp @@ -128,6 +128,19 @@ } } +bool types::isLLVMIR(ID Id) { + switch (Id) { + default: + return false; + + case TY_LLVM_IR: + case TY_LLVM_BC: + case TY_LTO_IR: + case TY_LTO_BC: + return true; + } +} + bool types::isCuda(ID Id) { switch (Id) { default: Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3413,6 +3413,13 @@ Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); } + if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_backend_EQ)) { + if (!types::isLLVMIR(Input.getType())) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) + << "-x ir"; + Args.AddLastArg(CmdArgs, options::OPT_fthinlto_backend_EQ); + } + // We normally speed up the clang process a bit by skipping destructors at // exit, but when we're generating diagnostics we can rely on some of the // cleanup. Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -27,9 +27,11 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/FunctionInfo.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" +#include "llvm/Object/FunctionIndexObjectFile.h" #include "llvm/Pass.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" @@ -39,6 +41,24 @@ using namespace llvm; namespace clang { +/// Diagnostic handler used by invocations of Linker::LinkModules +static void linkerDiagnosticHandler(const DiagnosticInfo &DI, + const llvm::Module *LinkModule, + DiagnosticsEngine &Diags) { + if (DI.getSeverity() != DS_Error) + return; + + std::string MsgStorage; + { + raw_string_ostream Stream(MsgStorage); + DiagnosticPrinterRawOStream DP(Stream); + DI.print(DP); + } + + Diags.Report(diag::err_fe_cannot_link_module) + << LinkModule->getModuleIdentifier() << MsgStorage; +} + class BackendConsumer : public ASTConsumer { virtual void anchor(); DiagnosticsEngine &Diags; @@ -167,7 +187,7 @@ llvm::Module *LinkModule = I.second.get(); if (Linker::LinkModules(M, LinkModule, [=](const DiagnosticInfo &DI) { - linkerDiagnosticHandler(DI, LinkModule); + linkerDiagnosticHandler(DI, LinkModule, Diags); }, LinkFlags)) return; @@ -233,9 +253,6 @@ ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc); } - void linkerDiagnosticHandler(const llvm::DiagnosticInfo &DI, - const llvm::Module *LinkModule); - static void DiagnosticHandler(const llvm::DiagnosticInfo &DI, void *Context) { ((BackendConsumer *)Context)->DiagnosticHandlerImpl(DI); @@ -545,22 +562,6 @@ EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure); } -void BackendConsumer::linkerDiagnosticHandler(const DiagnosticInfo &DI, - const llvm::Module *LinkModule) { - if (DI.getSeverity() != DS_Error) - return; - - std::string MsgStorage; - { - raw_string_ostream Stream(MsgStorage); - DiagnosticPrinterRawOStream DP(Stream); - DI.print(DP); - } - - Diags.Report(diag::err_fe_cannot_link_module) - << LinkModule->getModuleIdentifier() << MsgStorage; -} - /// \brief This function is invoked when the backend needs /// to report something to the user. void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { @@ -785,6 +786,45 @@ TheModule->setTargetTriple(TargetOpts.Triple); } + // If we are performing ThinLTO backend compilation (indicated by + // a non-empty index file option), then we need to invoke the module + // linker for the current module that we are importing into. This + // is because the module linker will need to promote to global scope + // and rename any local values that are potentially exported to other + // modules. Do this early so that the rest of the compilation sees the + // promoted symbols. + if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) { + // TODO: Stash this on the module object so we can reuse in + // the FunctionImport pass? + ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr = + llvm::getFunctionIndexForFile(CI.getCodeGenOpts().ThinLTOIndexFile, + [=, &CI](const DiagnosticInfo &DI) { + linkerDiagnosticHandler( + DI, TheModule.get(), + CI.getDiagnostics()); + }, + TheModule.get()); + if (std::error_code EC = IndexOrErr.getError()) { + std::string Error = EC.message(); + errs() << "Error loading index file '" + << CI.getCodeGenOpts().ThinLTOIndexFile << "': " << Error + << "\n"; + return; + } + std::unique_ptr<FunctionInfoIndex> Index = std::move(IndexOrErr.get()); + assert(Index); + std::unique_ptr<llvm::Module> Combined(new llvm::Module( + TheModule->getModuleIdentifier(), TheModule->getContext())); + if (Linker::LinkModules(Combined.get(), TheModule.get(), + [=, &CI](const DiagnosticInfo &DI) { + linkerDiagnosticHandler(DI, TheModule.get(), + CI.getDiagnostics()); + }, llvm::Linker::Flags::None, Index.get())) + return; + + TheModule = std::move(Combined); + } + LLVMContext &Ctx = TheModule->getContext(); Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler); EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(), TargetOpts, Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -284,6 +284,29 @@ Inlining = CodeGenOpts.NoInlining; } + // If we are performing a ThinLTO backend compile, invoke the LTO + // pipeline and initialize the FunctionImportIndexFile field. + if (!CodeGenOpts.ThinLTOIndexFile.empty()) { + legacy::PassManager *MPM = getPerModulePasses(); + PassManagerBuilder PMB; + Triple TargetTriple(TheModule->getTargetTriple()); + PMB.LibraryInfo = createTLII(TargetTriple, CodeGenOpts); + PMB.Inliner = createFunctionInliningPass(); + PMB.VerifyInput = true; + // Disable the verification pass in -asserts builds. +#ifdef NDEBUG + PMB.VerifyOutput = false; +#else + PMB.VerifyOutput = true; +#endif + PMB.LoopVectorize = true; + PMB.SLPVectorize = true; + PMB.FunctionImportIndexFile = CodeGenOpts.ThinLTOIndexFile; + PMB.OptLevel = OptLevel; + PMB.populateLTOPassManager(*MPM); + return; + } + PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts); PMBuilder.OptLevel = OptLevel; PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize; Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -167,6 +167,10 @@ /// Name of the profile file to use as input for -fprofile-instr-use std::string InstrProfileInput; + /// Name of the function summary index file to use for ThinLTO function + /// importing. + std::string ThinLTOIndexFile; + /// The EABI version to use std::string EABIVersion; Index: include/clang/Driver/Types.h =================================================================== --- include/clang/Driver/Types.h +++ include/clang/Driver/Types.h @@ -63,6 +63,9 @@ /// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers). bool isCXX(ID Id); + /// Is this LLVM IR. + bool isLLVMIR(ID Id); + /// isCuda - Is this a CUDA input. bool isCuda(ID Id); Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -693,6 +693,9 @@ HelpText<"Enable LTO in 'full' mode">; def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>, HelpText<"Disable LTO mode (default)">; +def fthinlto_backend_EQ : Joined<["-"], "fthinlto-backend=">, + Flags<[CC1Option]>, Group<f_Group>, + HelpText<"Perform ThinLTO backend using provided function summary index">; def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group<f_Group>, Flags<[DriverOption, CoreOption]>; def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits