Accept LLVM bitcode files (*.bc) on the commandline and add the code to the first source file on the cmdline (the first emitted module).

This commit is contained in:
Johan Engelen 2016-05-11 14:19:30 +02:00
parent fcfeba2001
commit d9b267a4be
12 changed files with 191 additions and 7 deletions

View file

@ -189,6 +189,8 @@ struct Param
version(IN_LLVM)
{
Array!(const(char)*)* bitcodeFiles; // LLVM bitcode files passed on cmdline
uint nestedTmpl; // maximum nested template instantiations
// Whether to keep all function bodies in .di file generation or to strip

View file

@ -188,6 +188,8 @@ struct Param
const char *mapfile;
#if IN_LLVM
Array<const char *> *bitcodeFiles; // LLVM bitcode files passed on cmdline
uint32_t nestedTmpl; // maximum nested template instantiations
// Whether to keep all function bodies in .di file generation or to strip

View file

@ -13,6 +13,7 @@
#include "mars.h"
#include "module.h"
#include "scope.h"
#include "driver/linker.h"
#include "driver/toobj.h"
#include "gen/logger.h"
#include "gen/runtime.h"
@ -25,6 +26,50 @@ extern Module *g_entrypointModule;
/// The module that contains the actual D main() (_Dmain) definition.
extern Module *g_dMainModule;
namespace {
/// Add the linker options metadata flag.
/// If the flag is already present, merge it with the new data.
void emitLinkerOptions(IRState &irs, llvm::Module &M, llvm::LLVMContext &ctx) {
if (!M.getModuleFlag("Linker Options")) {
M.addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
llvm::MDNode::get(ctx, irs.LinkerMetadataArgs));
} else {
// Merge the Linker Options with the pre-existing one
// (this can happen when passing a .bc file on the commandline)
auto *moduleFlags = M.getModuleFlagsMetadata();
for (unsigned i = 0, e = moduleFlags->getNumOperands(); i < e; ++i) {
auto *flag = moduleFlags->getOperand(i);
if (flag->getNumOperands() < 3)
continue;
auto optionsMDString =
llvm::dyn_cast_or_null<llvm::MDString>(flag->getOperand(1));
if (!optionsMDString || optionsMDString->getString() != "Linker Options")
continue;
// If we reach here, we found the Linker Options flag.
// Add the old Linker Options to our LinkerMetadataArgs list.
auto *oldLinkerOptions = llvm::cast<llvm::MDNode>(flag->getOperand(2));
for (const auto &Option : oldLinkerOptions->operands()) {
irs.LinkerMetadataArgs.push_back(Option);
}
// Replace Linker Options with a newly created list.
llvm::Metadata *Ops[3] = {
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
llvm::Type::getInt32Ty(ctx), llvm::Module::AppendUnique)),
llvm::MDString::get(ctx, "Linker Options"),
llvm::MDNode::get(ctx, irs.LinkerMetadataArgs)};
moduleFlags->setOperand(i, llvm::MDNode::get(ctx, Ops));
break;
}
}
}
}
namespace ldc {
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr),
@ -52,6 +97,11 @@ CodeGenerator::~CodeGenerator() {
filename = firstModuleObjfileName_;
}
// If there are bitcode files passed on the cmdline, add them after all
// other source files have been added to the (singleobj) module.
insertBitcodeFiles(ir_->module, ir_->context(),
*global.params.bitcodeFiles);
writeAndFreeLLModule(filename);
}
}
@ -91,6 +141,13 @@ void CodeGenerator::finishLLModule(Module *m) {
return;
}
// Add bitcode files passed on the cmdline to
// the first module only, to avoid duplications.
if (moduleCount_ == 1) {
insertBitcodeFiles(ir_->module, ir_->context(),
*global.params.bitcodeFiles);
}
m->deleteObjFile();
writeAndFreeLLModule(m->objfile->name->str);
}
@ -98,10 +155,7 @@ void CodeGenerator::finishLLModule(Module *m) {
void CodeGenerator::writeAndFreeLLModule(const char *filename) {
ir_->DBuilder.Finalize();
// Add the linker options metadata flag.
ir_->module.addModuleFlag(
llvm::Module::AppendUnique, "Linker Options",
llvm::MDNode::get(ir_->context(), ir_->LinkerMetadataArgs));
emitLinkerOptions(*ir_, ir_->module, ir_->context());
// Emit ldc version as llvm.ident metadata.
llvm::NamedMDNode *IdentMetadata =

View file

@ -19,9 +19,12 @@
#include "gen/optimizer.h"
#include "gen/programs.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#if _WIN32
#include "llvm/Support/SystemUtils.h"
#include <Windows.h>
@ -103,6 +106,35 @@ static std::string getOutputName(bool const sharedLib) {
//////////////////////////////////////////////////////////////////////////////
namespace {
/// Insert an LLVM bitcode file into the module
void insertBitcodeIntoModule(const char *bcFile, llvm::Module &M,
llvm::LLVMContext &Context) {
Logger::println("*** Linking-in bitcode file %s ***", bcFile);
llvm::SMDiagnostic Err;
std::unique_ptr<llvm::Module> loadedModule =
getLazyIRFileModule(bcFile, Err, Context);
if (!loadedModule) {
error(Loc(), "Error when loading LLVM bitcode file: %s", bcFile);
return;
}
llvm::Linker(M).linkInModule(std::move(loadedModule));
}
}
/// Insert LLVM bitcode files into the module
void insertBitcodeFiles(llvm::Module &M, llvm::LLVMContext &Ctx,
Array<const char *> &bitcodeFiles) {
for (const char *fname : bitcodeFiles) {
insertBitcodeIntoModule(fname, M, Ctx);
}
}
//////////////////////////////////////////////////////////////////////////////
static std::string gExePath;
static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {

View file

@ -15,6 +15,19 @@
#ifndef LDC_DRIVER_LINKER_H
#define LDC_DRIVER_LINKER_H
namespace llvm {
class Module;
class LLVMContext;
}
template <typename TYPE> struct Array;
/**
* Inserts bitcode files passed on the commandline into a module.
*/
void insertBitcodeFiles(llvm::Module &M, llvm::LLVMContext &Ctx,
Array<const char *> &bitcodeFiles);
/**
* Link an executable only from object files.
* @return 0 on success.

View file

@ -389,6 +389,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
global.params.libfiles = new Strings();
global.params.objfiles = new Strings();
global.params.ddocfiles = new Strings();
global.params.bitcodeFiles = new Strings();
global.params.moduleDeps = nullptr;
global.params.moduleDepsFile = nullptr;
@ -1157,17 +1158,27 @@ int cppmain(int argc, char **argv) {
ext = FileName::ext(p);
if (ext) {
#if LDC_POSIX
if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.bc_ext) == 0)
if (strcmp(ext, global.obj_ext) == 0)
#else
if (Port::stricmp(ext, global.obj_ext) == 0 ||
Port::stricmp(ext, global.obj_ext_alt) == 0 ||
Port::stricmp(ext, global.bc_ext) == 0)
Port::stricmp(ext, global.obj_ext_alt) == 0)
#endif
{
global.params.objfiles->push(static_cast<const char *>(files.data[i]));
continue;
}
// Detect LLVM bitcode files on commandline
#if LDC_POSIX
if (strcmp(ext, global.bc_ext) == 0)
#else
if (Port::stricmp(ext, global.bc_ext) == 0)
#endif
{
global.params.bitcodeFiles->push(static_cast<const char *>(files.data[i]));
continue;
}
#if LDC_POSIX
if (strcmp(ext, "a") == 0)
#elif __MINGW32__

View file

@ -0,0 +1,8 @@
module inputs.link_bitcode_import;
extern(C)
struct SomeStrukt {
int i;
}
extern(C) void takeStrukt(SomeStrukt*) {};

View file

@ -0,0 +1,12 @@
module inputs.link_bitcode_input;
extern(C) int return_seven() {
return 7;
}
import inputs.link_bitcode_import;
void bar()
{
SomeStrukt r = {1};
takeStrukt(&r);
}

View file

@ -0,0 +1,9 @@
module inputs.link_bitcode_input3;
import inputs.link_bitcode_import;
void foo()
{
SomeStrukt r = {0};
takeStrukt(&r);
}

View file

@ -0,0 +1,4 @@
module inputs.link_bitcode_libs_input;
pragma(lib, "imported_one");
pragma(lib, "imported_two");

View file

@ -0,0 +1,19 @@
// Test linking with an LLVM bitcode file
// RUN: %ldc -c -output-bc -I%S %S/inputs/link_bitcode_input.d -of=%t.bc
// RUN: %ldc -c -output-bc -I%S %S/inputs/link_bitcode_import.d -of=%t2.bc
// RUN: %ldc -c -output-bc -I%S %S/inputs/link_bitcode_input3.d -of=%t3.bc
// RUN: %ldc -c -singleobj -output-bc %t.bc %t3.bc %s
// RUN: %ldc -c -singleobj -I%S %t.bc %s %S/inputs/link_bitcode_input3.d
// RUN: %ldc -c -singleobj -I%S %t.bc %S/inputs/link_bitcode_input3.d %s
// RUN: %ldc -c -I%S %t.bc %S/inputs/link_bitcode_input3.d %s
// RUN: %ldc %t.bc %t2.bc %t3.bc -run %s
// RUN: %ldc %t.bc %S/inputs/link_bitcode_import.d %t3.bc -run %s
// Defined in input/link_bitcode_input.d
extern(C) int return_seven();
void main() {
assert( return_seven() == 7 );
}

View file

@ -0,0 +1,18 @@
// Test passing of LLVM bitcode file with Linker Options set
// Linker Options are currently only set on Windows platform, so we must (cross-)compile to Windows
// REQUIRES: target_X86
// RUN: %ldc -mtriple=x86_64-windows -c -output-bc %S/inputs/link_bitcode_libs_input.d -of=%t.bc \
// RUN: && %ldc -mtriple=x86_64-windows -c -singleobj -output-ll %t.bc %s -of=%t.ll \
// RUN: && FileCheck %s < %t.ll
pragma(lib, "library_one");
pragma(lib, "library_two");
// CHECK: !"Linker Options", ![[ATTR_TUPLE:[0-9]+]]
// CHECK: ![[ATTR_TUPLE]] = !{![[ATTR_LIB1:[0-9]+]], ![[ATTR_LIB2:[0-9]+]], ![[ATTR_LIB3:[0-9]+]], ![[ATTR_LIB4:[0-9]+]]}
// CHECK: ![[ATTR_LIB1]]{{.*}}library_one
// CHECK: ![[ATTR_LIB2]]{{.*}}library_two
// CHECK: ![[ATTR_LIB3]]{{.*}}imported_one
// CHECK: ![[ATTR_LIB4]]{{.*}}imported_two