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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to