Add support for lazily linking bitcode files (using a new
-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
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index a747b92..4d5d4bf 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -25,6 +25,7 @@
bitwriter
codegen
ipo
+ linker
selectiondag
)
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index b565bb1..696b99f 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -16,7 +16,7 @@
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 \
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 82f9196..c9f5a5c 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -19,6 +19,8 @@
// 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;
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index f1a2f6e..9697bc6 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -25,6 +25,7 @@
private:
unsigned Act;
llvm::OwningPtr<llvm::Module> TheModule;
+ llvm::Module *LinkModule;
llvm::LLVMContext *VMContext;
bool OwnsVMContext;
@@ -46,6 +47,11 @@
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();
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index c5d232a..1a6008e 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -196,6 +196,8 @@
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">;
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 5b69888..9962ea8 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -128,6 +128,9 @@
/// 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;
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 11d6075..db2bab9 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -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"
@@ -18,9 +19,11 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
//
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 @@
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 @@
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;
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index a4851f1..6950647 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1078,6 +1078,7 @@
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
index 0000000..7740406
--- /dev/null
+++ b/test/CodeGen/link-bitcode-file.c
@@ -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
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index e6d0f1a..0df9210 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,11 +1,11 @@
set( LLVM_USED_LIBS
+ clangFrontendTool
clangAST
clangAnalysis
clangBasic
clangCodeGen
clangDriver
clangFrontend
- clangFrontendTool
clangIndex
clangLex
clangParse
@@ -26,6 +26,7 @@
codegen
instrumentation
ipo
+ linker
selectiondag
)
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 6b34a99..c7d91a7 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -30,7 +30,7 @@
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 \