mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 17:11:44 +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)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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__
|
||||
|
|
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