mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +03:00
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:
parent
fcfeba2001
commit
d9b267a4be
12 changed files with 191 additions and 7 deletions
|
@ -189,6 +189,8 @@ struct Param
|
||||||
|
|
||||||
version(IN_LLVM)
|
version(IN_LLVM)
|
||||||
{
|
{
|
||||||
|
Array!(const(char)*)* bitcodeFiles; // LLVM bitcode files passed on cmdline
|
||||||
|
|
||||||
uint nestedTmpl; // maximum nested template instantiations
|
uint nestedTmpl; // maximum nested template instantiations
|
||||||
|
|
||||||
// Whether to keep all function bodies in .di file generation or to strip
|
// Whether to keep all function bodies in .di file generation or to strip
|
||||||
|
|
|
@ -188,6 +188,8 @@ struct Param
|
||||||
const char *mapfile;
|
const char *mapfile;
|
||||||
|
|
||||||
#if IN_LLVM
|
#if IN_LLVM
|
||||||
|
Array<const char *> *bitcodeFiles; // LLVM bitcode files passed on cmdline
|
||||||
|
|
||||||
uint32_t nestedTmpl; // maximum nested template instantiations
|
uint32_t nestedTmpl; // maximum nested template instantiations
|
||||||
|
|
||||||
// Whether to keep all function bodies in .di file generation or to strip
|
// Whether to keep all function bodies in .di file generation or to strip
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "mars.h"
|
#include "mars.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "scope.h"
|
#include "scope.h"
|
||||||
|
#include "driver/linker.h"
|
||||||
#include "driver/toobj.h"
|
#include "driver/toobj.h"
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
|
@ -25,6 +26,50 @@ extern Module *g_entrypointModule;
|
||||||
/// The module that contains the actual D main() (_Dmain) definition.
|
/// The module that contains the actual D main() (_Dmain) definition.
|
||||||
extern Module *g_dMainModule;
|
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 {
|
namespace ldc {
|
||||||
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
|
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
|
||||||
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr),
|
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(nullptr),
|
||||||
|
@ -52,6 +97,11 @@ CodeGenerator::~CodeGenerator() {
|
||||||
filename = firstModuleObjfileName_;
|
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);
|
writeAndFreeLLModule(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +141,13 @@ void CodeGenerator::finishLLModule(Module *m) {
|
||||||
return;
|
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();
|
m->deleteObjFile();
|
||||||
writeAndFreeLLModule(m->objfile->name->str);
|
writeAndFreeLLModule(m->objfile->name->str);
|
||||||
}
|
}
|
||||||
|
@ -98,10 +155,7 @@ void CodeGenerator::finishLLModule(Module *m) {
|
||||||
void CodeGenerator::writeAndFreeLLModule(const char *filename) {
|
void CodeGenerator::writeAndFreeLLModule(const char *filename) {
|
||||||
ir_->DBuilder.Finalize();
|
ir_->DBuilder.Finalize();
|
||||||
|
|
||||||
// Add the linker options metadata flag.
|
emitLinkerOptions(*ir_, ir_->module, ir_->context());
|
||||||
ir_->module.addModuleFlag(
|
|
||||||
llvm::Module::AppendUnique, "Linker Options",
|
|
||||||
llvm::MDNode::get(ir_->context(), ir_->LinkerMetadataArgs));
|
|
||||||
|
|
||||||
// Emit ldc version as llvm.ident metadata.
|
// Emit ldc version as llvm.ident metadata.
|
||||||
llvm::NamedMDNode *IdentMetadata =
|
llvm::NamedMDNode *IdentMetadata =
|
||||||
|
|
|
@ -19,9 +19,12 @@
|
||||||
#include "gen/optimizer.h"
|
#include "gen/optimizer.h"
|
||||||
#include "gen/programs.h"
|
#include "gen/programs.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
|
#include "llvm/IRReader/IRReader.h"
|
||||||
|
#include "llvm/Linker/Linker.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
#include "llvm/Support/Program.h"
|
#include "llvm/Support/Program.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
|
#include "llvm/Support/SourceMgr.h"
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include "llvm/Support/SystemUtils.h"
|
#include "llvm/Support/SystemUtils.h"
|
||||||
#include <Windows.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 std::string gExePath;
|
||||||
|
|
||||||
static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
|
static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
|
||||||
|
|
|
@ -15,6 +15,19 @@
|
||||||
#ifndef LDC_DRIVER_LINKER_H
|
#ifndef LDC_DRIVER_LINKER_H
|
||||||
#define 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.
|
* Link an executable only from object files.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
|
|
|
@ -389,6 +389,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
|
||||||
global.params.libfiles = new Strings();
|
global.params.libfiles = new Strings();
|
||||||
global.params.objfiles = new Strings();
|
global.params.objfiles = new Strings();
|
||||||
global.params.ddocfiles = new Strings();
|
global.params.ddocfiles = new Strings();
|
||||||
|
global.params.bitcodeFiles = new Strings();
|
||||||
|
|
||||||
global.params.moduleDeps = nullptr;
|
global.params.moduleDeps = nullptr;
|
||||||
global.params.moduleDepsFile = nullptr;
|
global.params.moduleDepsFile = nullptr;
|
||||||
|
@ -1157,17 +1158,27 @@ int cppmain(int argc, char **argv) {
|
||||||
ext = FileName::ext(p);
|
ext = FileName::ext(p);
|
||||||
if (ext) {
|
if (ext) {
|
||||||
#if LDC_POSIX
|
#if LDC_POSIX
|
||||||
if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.bc_ext) == 0)
|
if (strcmp(ext, global.obj_ext) == 0)
|
||||||
#else
|
#else
|
||||||
if (Port::stricmp(ext, global.obj_ext) == 0 ||
|
if (Port::stricmp(ext, global.obj_ext) == 0 ||
|
||||||
Port::stricmp(ext, global.obj_ext_alt) == 0 ||
|
Port::stricmp(ext, global.obj_ext_alt) == 0)
|
||||||
Port::stricmp(ext, global.bc_ext) == 0)
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
global.params.objfiles->push(static_cast<const char *>(files.data[i]));
|
global.params.objfiles->push(static_cast<const char *>(files.data[i]));
|
||||||
continue;
|
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 LDC_POSIX
|
||||||
if (strcmp(ext, "a") == 0)
|
if (strcmp(ext, "a") == 0)
|
||||||
#elif __MINGW32__
|
#elif __MINGW32__
|
||||||
|
|
8
tests/linking/inputs/link_bitcode_import.d
Normal file
8
tests/linking/inputs/link_bitcode_import.d
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module inputs.link_bitcode_import;
|
||||||
|
|
||||||
|
extern(C)
|
||||||
|
struct SomeStrukt {
|
||||||
|
int i;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern(C) void takeStrukt(SomeStrukt*) {};
|
12
tests/linking/inputs/link_bitcode_input.d
Normal file
12
tests/linking/inputs/link_bitcode_input.d
Normal 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);
|
||||||
|
}
|
9
tests/linking/inputs/link_bitcode_input3.d
Normal file
9
tests/linking/inputs/link_bitcode_input3.d
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module inputs.link_bitcode_input3;
|
||||||
|
|
||||||
|
import inputs.link_bitcode_import;
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
SomeStrukt r = {0};
|
||||||
|
takeStrukt(&r);
|
||||||
|
}
|
4
tests/linking/inputs/link_bitcode_libs_input.d
Normal file
4
tests/linking/inputs/link_bitcode_libs_input.d
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
module inputs.link_bitcode_libs_input;
|
||||||
|
|
||||||
|
pragma(lib, "imported_one");
|
||||||
|
pragma(lib, "imported_two");
|
19
tests/linking/link_bitcode.d
Normal file
19
tests/linking/link_bitcode.d
Normal 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 );
|
||||||
|
}
|
18
tests/linking/link_bitcode_libs.d
Normal file
18
tests/linking/link_bitcode_libs.d
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue