]> granicus.if.org Git - clang/commitdiff
Add support for lazily linking bitcode files (using a new
authorPeter Collingbourne <peter@pcc.me.uk>
Sun, 30 Oct 2011 17:30:44 +0000 (17:30 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Sun, 30 Oct 2011 17:30:44 +0000 (17:30 +0000)
-mlink-bitcode-file flag), and more generally llvm::Modules, before
running optimisations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143314 91177308-0d34-0410-b5e6-96231b3b80d8

examples/clang-interpreter/CMakeLists.txt
examples/clang-interpreter/Makefile
include/clang/Basic/DiagnosticFrontendKinds.td
include/clang/CodeGen/CodeGenAction.h
include/clang/Driver/CC1Options.td
include/clang/Frontend/CodeGenOptions.h
lib/CodeGen/CodeGenAction.cpp
lib/Frontend/CompilerInvocation.cpp
test/CodeGen/link-bitcode-file.c [new file with mode: 0644]
tools/driver/CMakeLists.txt
tools/driver/Makefile

index a747b92a76cb67d900e56bcc9944c2f3485826f1..4d5d4bf9445cced124dc4c3534bceaaab6ca96c8 100644 (file)
@@ -25,6 +25,7 @@ set(LLVM_LINK_COMPONENTS
     bitwriter
     codegen
     ipo
+    linker
     selectiondag
   )
 
index b565bb172b077509989c104ee23bfaddb3609042..696b99ffdbffdb40ec219b8dd0cfe01c1cea4f11 100644 (file)
@@ -16,7 +16,7 @@ NO_INSTALL = 1
 TOOL_NO_EXPORTS = 1
 
 LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
-       selectiondag asmparser instrumentation
+       linker selectiondag asmparser instrumentation
 USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
            clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
            clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
index 82f91961e713e1c3dd5a043adfcb117936a626d7..c9f5a5c48634be4ed30ae2df42dfd5480dd5f918 100644 (file)
@@ -19,6 +19,8 @@ def err_fe_invalid_ast_action : Error<"invalid action for AST input">,
 // Error generated by the backend.
 def err_fe_inline_asm : Error<"%0">, CatInlineAsm;
 def note_fe_inline_asm_here : Note<"instantiated into assembly here">;
+def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">,
+  DefaultFatal;
 
 
 
index f1a2f6eb455ded19a9128970804f951dfea8719f..9697bc62afd053cda0d8818a3ea156dfd53bc705 100644 (file)
@@ -25,6 +25,7 @@ class CodeGenAction : public ASTFrontendAction {
 private:
   unsigned Act;
   llvm::OwningPtr<llvm::Module> TheModule;
+  llvm::Module *LinkModule;
   llvm::LLVMContext *VMContext;
   bool OwnsVMContext;
 
@@ -46,6 +47,11 @@ protected:
 public:
   ~CodeGenAction();
 
+  /// setLinkModule - Set the link module to be used by this action.  If a link
+  /// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty,
+  /// the action will load it from the specified file.
+  void setLinkModule(llvm::Module *Mod) { LinkModule = Mod; }
+
   /// takeModule - Take the generated LLVM module, for use after the action has
   /// been run. The result may be null on failure.
   llvm::Module *takeModule();
index c5d232abf661f9a2ee56e810b47b7e3e32a14b12..1a6008e7797f11ccc5cbfb130bee087edc341066 100644 (file)
@@ -196,6 +196,8 @@ def mms_bitfields : Flag<"-mms-bitfields">,
   HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">;
 def mstackrealign : Flag<"-mstackrealign">,
   HelpText<"Force realign the stack at entry to every function.">;
+def mlink_bitcode_file : Separate<"-mlink-bitcode-file">,
+  HelpText<"Link the given bitcode file before performing optimizations.">;
 def O : Joined<"-O">, HelpText<"Optimization level">;
 def Os : Flag<"-Os">, HelpText<"Optimize for size">;
 def Oz : Flag<"-Oz">, HelpText<"Optimize for size, regardless of performance">;
index 5b698889f6eda3de5d4512fd0365647252cd8c3a..9962ea8cf92c955f8b234ce5cc1118a9dd8fe0aa 100644 (file)
@@ -128,6 +128,9 @@ public:
   /// The float precision limit to use, if non-empty.
   std::string LimitFloatPrecision;
 
+  /// The name of the bitcode file to link before optzns.
+  std::string LinkBitcodeFile;
+
   /// The kind of inlining to perform.
   InliningMethod Inlining;
 
index 11d6075582fe8b630f14f147bac8dae5e0fd3cc4..db2bab9bf61875c6560831a93840bc0b1d0bcbd1 100644 (file)
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "llvm/LLVMContext.h"
+#include "llvm/Linker.h"
 #include "llvm/Module.h"
 #include "llvm/Pass.h"
 #include "llvm/ADT/OwningPtr.h"
+#include "llvm/Bitcode/ReaderWriter.h"
 #include "llvm/Support/IRReader.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/SourceMgr.h"
@@ -42,7 +45,7 @@ namespace clang {
 
     llvm::OwningPtr<CodeGenerator> Gen;
 
-    llvm::OwningPtr<llvm::Module> TheModule;
+    llvm::OwningPtr<llvm::Module> TheModule, LinkModule;
 
   public:
     BackendConsumer(BackendAction action, DiagnosticsEngine &_Diags,
@@ -50,7 +53,9 @@ namespace clang {
                     const TargetOptions &targetopts,
                     const LangOptions &langopts,
                     bool TimePasses,
-                    const std::string &infile, raw_ostream *OS,
+                    const std::string &infile,
+                    llvm::Module *LinkModule,
+                    raw_ostream *OS,
                     LLVMContext &C) :
       Diags(_Diags),
       Action(action),
@@ -59,11 +64,13 @@ namespace clang {
       LangOpts(langopts),
       AsmOutStream(OS),
       LLVMIRGeneration("LLVM IR Generation Time"),
-      Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)) {
+      Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
+      LinkModule(LinkModule) {
       llvm::TimePassesIsEnabled = TimePasses;
     }
 
     llvm::Module *takeModule() { return TheModule.take(); }
+    llvm::Module *takeLinkModule() { return LinkModule.take(); }
 
     virtual void Initialize(ASTContext &Ctx) {
       Context = &Ctx;
@@ -122,6 +129,17 @@ namespace clang {
       assert(TheModule.get() == M &&
              "Unexpected module change during IR generation");
 
+      // Link LinkModule into this module if present, preserving its validity.
+      if (LinkModule) {
+        std::string ErrorMsg;
+        if (Linker::LinkModules(M, LinkModule.get(), Linker::PreserveSource,
+                                &ErrorMsg)) {
+          Diags.Report(diag::err_fe_cannot_link_module)
+            << LinkModule->getModuleIdentifier() << ErrorMsg;
+          return;
+        }
+      }
+
       // Install an inline asm handler so that diagnostics get printed through
       // our diagnostics hooks.
       LLVMContext &Ctx = TheModule->getContext();
@@ -238,7 +256,8 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
 //
 
 CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext)
-  : Act(_Act), VMContext(_VMContext ? _VMContext : new LLVMContext),
+  : Act(_Act), LinkModule(0),
+    VMContext(_VMContext ? _VMContext : new LLVMContext),
     OwnsVMContext(!_VMContext) {}
 
 CodeGenAction::~CodeGenAction() {
@@ -254,6 +273,10 @@ void CodeGenAction::EndSourceFileAction() {
   if (!getCompilerInstance().hasASTConsumer())
     return;
 
+  // If we were given a link module, release consumer's ownership of it.
+  if (LinkModule)
+    BEConsumer->takeLinkModule();
+
   // Steal the module from the consumer.
   TheModule.reset(BEConsumer->takeModule());
 }
@@ -294,12 +317,36 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
   if (BA != Backend_EmitNothing && !OS)
     return 0;
 
+  llvm::Module *LinkModuleToUse = LinkModule;
+
+  // If we were not given a link module, and the user requested that one be
+  // loaded from bitcode, do so now.
+  const std::string &LinkBCFile = CI.getCodeGenOpts().LinkBitcodeFile;
+  if (!LinkModuleToUse && !LinkBCFile.empty()) {
+    std::string ErrorStr;
+
+    llvm::MemoryBuffer *BCBuf =
+      CI.getFileManager().getBufferForFile(LinkBCFile, &ErrorStr);
+    if (!BCBuf) {
+      CI.getDiagnostics().Report(diag::err_cannot_open_file)
+        << LinkBCFile << ErrorStr;
+      return 0;
+    }
+
+    LinkModuleToUse = getLazyBitcodeModule(BCBuf, *VMContext, &ErrorStr);
+    if (!LinkModuleToUse) {
+      CI.getDiagnostics().Report(diag::err_cannot_open_file)
+        << LinkBCFile << ErrorStr;
+      return 0;
+    }
+  }
+
   BEConsumer = 
       new BackendConsumer(BA, CI.getDiagnostics(),
                           CI.getCodeGenOpts(), CI.getTargetOpts(),
                           CI.getLangOpts(),
-                          CI.getFrontendOpts().ShowTimers, InFile, OS.take(),
-                          *VMContext);
+                          CI.getFrontendOpts().ShowTimers, InFile,
+                          LinkModuleToUse, OS.take(), *VMContext);
   return BEConsumer;
 }
 
index a4851f1740a541908d9eb901cdac27179aee3d54..6950647cab451ea0891025d604b01462d8e02030 100644 (file)
@@ -1078,6 +1078,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
   Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
   Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
   Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
+  Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
 
   if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
     StringRef Name = A->getValue(Args);
diff --git a/test/CodeGen/link-bitcode-file.c b/test/CodeGen/link-bitcode-file.c
new file mode 100644 (file)
index 0000000..7740406
--- /dev/null
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -emit-llvm-bc -o %t.bc %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NO-BC %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s 2>&1 | FileCheck -check-prefix=CHECK-BC %s
+
+int f(void);
+
+#ifdef BITCODE
+
+// CHECK-BC: 'f': symbol multiply defined
+int f(void) {
+  return 42;
+}
+
+#else
+
+// CHECK-NO-BC: define i32 @g
+// CHECK-NO-BC: ret i32 42
+int g(void) {
+  return f();
+}
+
+// CHECK-NO-BC: define i32 @f
+
+#endif
index e6d0f1ac3763cdcbf9752cbc7075da471b6e9711..0df921052746479a8e69e6061c36de729a4155ff 100644 (file)
@@ -1,11 +1,11 @@
 set( LLVM_USED_LIBS
+  clangFrontendTool
   clangAST
   clangAnalysis
   clangBasic
   clangCodeGen
   clangDriver
   clangFrontend
-  clangFrontendTool
   clangIndex
   clangLex
   clangParse
@@ -26,6 +26,7 @@ set( LLVM_LINK_COMPONENTS
   codegen
   instrumentation
   ipo
+  linker
   selectiondag
   )
 
index 6b34a991bf1894f16393578facb4deb409c2d87f..c7d91a728d22a6670a6a032ec5f2ba8825ce18b9 100644 (file)
@@ -30,7 +30,7 @@ TOOL_INFO_PLIST := Info.plist
 include $(CLANG_LEVEL)/../../Makefile.config
 
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
-                   instrumentation ipo selectiondag
+                   instrumentation ipo linker selectiondag
 USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
            clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
            clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \