tejohnson updated this revision to Diff 41542.
tejohnson added a comment.
- Address Mehdi's comments.
http://reviews.llvm.org/D15025
Files:
include/clang/CodeGen/CodeGenAction.h
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
@@ -26,10 +26,12 @@
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/FunctionInfo.h"
#include "llvm/IR/LLVMContext.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) {
@@ -737,6 +738,11 @@
SM.print(nullptr, llvm::errs());
}
+void CodeGenAction::diagnosticHandler(const DiagnosticInfo &DI) {
+ linkerDiagnosticHandler(DI, TheModule.get(),
+ getCompilerInstance().getDiagnostics());
+}
+
void CodeGenAction::ExecuteAction() {
// If this is an IR file, we have to treat it specially.
if (getCurrentFileKind() == IK_LLVM_IR) {
@@ -785,6 +791,44 @@
TheModule->setTargetTriple(TargetOpts.Triple);
}
+ using namespace std::placeholders;
+ std::function<void(const llvm::DiagnosticInfo &)> DiagHandler =
+ std::bind(&CodeGenAction::diagnosticHandler, this, _1);
+
+ // 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()) {
+ ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
+ llvm::getFunctionIndexForFile(CI.getCodeGenOpts().ThinLTOIndexFile,
+ DiagHandler, 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(), DiagHandler,
+ llvm::Linker::Flags::None, Index.get()))
+ return;
+
+ TheModule = std::move(Combined);
+ // Stash on the module object so it can be used by the function
+ // importing pass. TODO: set this on Combined before we invoke
+ // LinkModules above, and change the module linker to access
+ // from the destination module instead of passing as parameter.
+ TheModule->setFunctionIndex(std::move(Index));
+ }
+
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,30 @@
Inlining = CodeGenOpts.NoInlining;
}
+ // If we are performing a ThinLTO backend compile, invoke the LTO
+ // pipeline and set the ImportFunctions flag. This is the same pipeline
+ // setup for LTO compiles invoked via the gold plugin and the llvm-lto tool.
+ if (!CodeGenOpts.ThinLTOIndexFile.empty() && !CodeGenOpts.DisableLLVMOpts) {
+ 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 = CodeGenOpts.VectorizeLoop;
+ PMB.SLPVectorize = CodeGenOpts.VectorizeSLP;
+ PMB.ImportFunctions = true;
+ 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>;
Index: include/clang/CodeGen/CodeGenAction.h
===================================================================
--- include/clang/CodeGen/CodeGenAction.h
+++ include/clang/CodeGen/CodeGenAction.h
@@ -16,6 +16,7 @@
namespace llvm {
class LLVMContext;
class Module;
+ class DiagnosticInfo;
}
namespace clang {
@@ -31,6 +32,9 @@
llvm::LLVMContext *VMContext;
bool OwnsVMContext;
+ /// Diagnostic handler to use for this action.
+ void diagnosticHandler(const llvm::DiagnosticInfo &DI);
+
protected:
/// Create a new code generation action. If the optional \p _VMContext
/// parameter is supplied, the action uses it without taking ownership,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits