Skip to content

Commit

Permalink
Backport of "Avoid using llvm::Linker" to master.
Browse files Browse the repository at this point in the history
See pull request #974 for the original code.
  • Loading branch information
redstar committed Jun 27, 2015
1 parent d7347a5 commit d1e764c
Show file tree
Hide file tree
Showing 39 changed files with 751 additions and 810 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ env:
- LLVM_PACKAGE="llvm-3.5 llvm-3.5-dev libedit2 libedit-dev"
- LLVM_PACKAGE="llvm-3.5 llvm-3.5-dev libedit2 libedit-dev" OPTS="-DTEST_COVERAGE=ON"
- LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev" TEST_DEBUG=1
- LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev"
- LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev" OPTS="-DMULTILIB=ON" TEST_BITNESS=32
- LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev" OPTS="-DMULTILIB=ON" TEST_BITNESS=64
- LLVM_PACKAGE="llvm-3.7 llvm-3.7-dev libedit2 libedit-dev" TEST_DEBUG=1
- LLVM_PACKAGE="llvm-3.7 llvm-3.7-dev libedit2 libedit-dev"
matrix:
allow_failures:
- env: LLVM_PACKAGE="llvm-3.4 llvm-3.4-dev" OPTS="-DMULTILIB=ON" TEST_BITNESS=32
- env: LLVM_PACKAGE="llvm-3.4 llvm-3.4-dev" OPTS="-DMULTILIB=ON" TEST_BITNESS=64
- env: LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev" TEST_DEBUG=1
- env: LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev"
- env: LLVM_PACKAGE="llvm-3.6 llvm-3.6-dev libedit2 libedit-dev" OPTS="-DMULTILIB=ON" TEST_BITNESS=32
- env: LLVM_PACKAGE="llvm-3.7 llvm-3.7-dev libedit2 libedit-dev" TEST_DEBUG=1
- env: LLVM_PACKAGE="llvm-3.7 llvm-3.7-dev libedit2 libedit-dev"
script:
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ file(GLOB IR_SRC ir/*.cpp)
file(GLOB IR_HDR ir/*.h)
set(DRV_SRC
driver/cl_options.cpp
driver/codegenerator.cpp
driver/configfile.cpp
driver/targetmachine.cpp
driver/toobj.cpp
Expand All @@ -239,6 +240,7 @@ set(DRV_SRC
set(DRV_HDR
driver/linker.h
driver/cl_options.h
driver/codegenerator.h
driver/configfile.h
driver/ldc-version.h
driver/targetmachine.h
Expand Down
12 changes: 0 additions & 12 deletions dmd2/dsymbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,12 @@ class DeleteDeclaration;
struct HdrGenState;
class OverloadSet;
struct AA;
#if IN_LLVM
class TypeInfoDeclaration;
class ClassInfoDeclaration;
#endif
#ifdef IN_GCC
typedef union tree_node TYPE;
#else
struct TYPE;
#endif

#if IN_LLVM
struct IRState;
namespace llvm
{
class Value;
}
#endif

struct Ungag
{
unsigned oldgag;
Expand Down
1 change: 0 additions & 1 deletion dmd2/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do
// LDC
llvmForceLogging = false;
noModuleInfo = false;
moduleInfoVar = NULL;
this->doDocComment = doDocComment;
this->doHdrGen = doHdrGen;
this->arrayfuncs = 0;
Expand Down
2 changes: 0 additions & 2 deletions dmd2/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,9 @@ class Module : public Package
llvm::Module* genLLVMModule(llvm::LLVMContext& context);
void buildTargetFiles(bool singleObj, bool library);
File* buildFilePath(const char* forcename, const char* path, const char* ext);
llvm::GlobalVariable* moduleInfoSymbol();

bool llvmForceLogging;
bool noModuleInfo; /// Do not emit any module metadata.
llvm::GlobalVariable* moduleInfoVar;

// array ops emitted in this module already
AA *arrayfuncs;
Expand Down
221 changes: 221 additions & 0 deletions driver/codegenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
//===-- codegenerator.cpp -------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//

#include "driver/codegenerator.h"

#include "id.h"
#include "mars.h"
#include "module.h"
#include "parse.h"
#include "scope.h"
#include "driver/toobj.h"
#include "gen/logger.h"
#include "gen/runtime.h"

void codegenModule(IRState *irs, Module *m, bool emitFullModuleInfo);

namespace {
Module *g_entrypointModule = 0;
Module *g_dMainModule = 0;
}

/// Callback to generate a C main() function, invoked by the frontend.
void genCmain(Scope *sc) {
if (g_entrypointModule) return;

/* The D code to be generated is provided as D source code in the form of a
* string.
* Note that Solaris, for unknown reasons, requires both a main() and an
* _main()
*/
static utf8_t code[] = "extern(C) {\n\
int _d_run_main(int argc, char **argv, void* mainFunc);\n\
int _Dmain(char[][] args);\n\
int main(int argc, char **argv) { return _d_run_main(argc, argv, &_Dmain); }\n\
version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); }\n\
}\n\
pragma(LDC_no_moduleinfo);\n\
";

Identifier *id = Id::entrypoint;
Module *m = new Module("__entrypoint.d", id, 0, 0);

Parser p(m, code, sizeof(code) / sizeof(code[0]), 0);
p.scanloc = Loc();
p.nextToken();
m->members = p.parseModule();
assert(p.token.value == TOKeof);

char v = global.params.verbose;
global.params.verbose = 0;
m->importedFrom = m;
m->importAll(0);
m->semantic();
m->semantic2();
m->semantic3();
global.params.verbose = v;

g_entrypointModule = m;
g_dMainModule = sc->module;
}

namespace {
/// Emits a declaration for the given symbol, which is assumed to be of type
/// i8*, and defines a second globally visible i8* that contains the address
/// of the first symbol.
void emitSymbolAddrGlobal(llvm::Module &lm, const char *symbolName,
const char *addrName) {
llvm::Type *voidPtr =
llvm::PointerType::get(llvm::Type::getInt8Ty(lm.getContext()), 0);
llvm::GlobalVariable *targetSymbol = new llvm::GlobalVariable(
lm, voidPtr, false, llvm::GlobalValue::ExternalWeakLinkage, 0,
symbolName);
new llvm::GlobalVariable(
lm, voidPtr, false, llvm::GlobalValue::ExternalLinkage,
llvm::ConstantExpr::getBitCast(targetSymbol, voidPtr), addrName);
}
}

namespace ldc {
CodeGenerator::CodeGenerator(llvm::LLVMContext &context, bool singleObj)
: context_(context), moduleCount_(0), singleObj_(singleObj), ir_(0),
firstModuleObjfileName_(0) {
if (!ClassDeclaration::object) {
error(Loc(), "declaration for class Object not found; druntime not "
"configured properly");
fatal();
}
}

CodeGenerator::~CodeGenerator() {
if (singleObj_) {
const char *oname;
const char *filename;
if ((oname = global.params.exefile) ||
(oname = global.params.objname)) {
filename = FileName::forceExt(oname, global.obj_ext);
if (global.params.objdir) {
filename = FileName::combine(global.params.objdir,
FileName::name(filename));
}
} else {
filename = firstModuleObjfileName_;
}

writeAndFreeLLModule(filename);
}
}

void CodeGenerator::prepareLLModule(Module *m) {
if (!firstModuleObjfileName_) {
firstModuleObjfileName_ = m->objfile->name->str;
}
++moduleCount_;

if (singleObj_ && ir_) return;

assert(!ir_);

// See http://llvm.org/bugs/show_bug.cgi?id=11479 – just use the source file
// name, as it should not collide with a symbol name used somewhere in the
// module.
ir_ = new IRState(m->srcfile->toChars(), context_);
ir_->module.setTargetTriple(global.params.targetTriple.str());
ir_->module.setDataLayout(gDataLayout->getStringRepresentation());

// TODO: Make ldc::DIBuilder per-Module to be able to emit several CUs for
// singleObj compilations?
ir_->DBuilder.EmitCompileUnit(m);

IrDsymbol::resetAll();
}

void CodeGenerator::finishLLModule(Module *m) {
if (singleObj_) return;

m->deleteObjFile();
writeAndFreeLLModule(m->objfile->name->str);
}

void CodeGenerator::writeAndFreeLLModule(const char *filename) {
ir_->DBuilder.Finalize();

#if LDC_LLVM_VER >= 303
// Add the linker options metadata flag.
ir_->module.addModuleFlag(
llvm::Module::AppendUnique, "Linker Options",
llvm::MDNode::get(ir_->context(), ir_->LinkerMetadataArgs));
#endif

#if LDC_LLVM_VER >= 304
// Emit ldc version as llvm.ident metadata.
llvm::NamedMDNode *IdentMetadata =
ir_->module.getOrInsertNamedMetadata("llvm.ident");
std::string Version("ldc version ");
Version.append(global.ldc_version);
#if LDC_LLVM_VER >= 306
llvm::Metadata *IdentNode[] =
#else
llvm::Value *IdentNode[] =
#endif
{llvm::MDString::get(ir_->context(), Version)};
IdentMetadata->addOperand(llvm::MDNode::get(ir_->context(), IdentNode));
#endif

writeModule(&ir_->module, filename);
global.params.objfiles->push(const_cast<char *>(filename));
delete ir_;
ir_ = 0;
}

void CodeGenerator::emit(Module *m) {
bool const loggerWasEnabled = Logger::enabled();
if (m->llvmForceLogging && !loggerWasEnabled) {
Logger::enable();
}

IF_LOG Logger::println("CodeGenerator::emit(%s)", m->toPrettyChars());
LOG_SCOPE;

if (global.params.verbose_cg) {
printf("codegen: %s (%s)\n", m->toPrettyChars(), m->srcfile->toChars());
}

if (global.errors) {
Logger::println("Aborting because of errors");
fatal();
}

prepareLLModule(m);

// If we are compiling to a single object file then only the first module needs
// to generate a call to _d_dso_registry(). All other modules only add a module
// reference.
// FIXME Find better name.
const bool emitFullModuleInfo = !singleObj_ || (singleObj_ && moduleCount_ == 1);
codegenModule(ir_, m, emitFullModuleInfo);
if (m == g_dMainModule) {
codegenModule(ir_, g_entrypointModule, emitFullModuleInfo);

// On Linux, strongly define the excecutabe BSS bracketing symbols in
// the main module for druntime use (see rt.sections_linux).
if (global.params.isLinux) {
emitSymbolAddrGlobal(ir_->module, "__bss_start",
"_d_execBssBegAddr");
emitSymbolAddrGlobal(ir_->module, "_end", "_d_execBssEndAddr");
}
}

finishLLModule(m);

if (m->llvmForceLogging && !loggerWasEnabled) {
Logger::disable();
}
}
}
46 changes: 46 additions & 0 deletions driver/codegenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- driver/codegenerator.h - D module codegen entry point ---*- C++ -*-===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// Contains ldc::CodeGenerator, which is the main entry point for emitting code
// for one or more D modules to LLVM IR and subsequently to whatever output
// format has been chosen globally.
//
// Currently reads parts of the configuration from global.params, as the code
// has been extracted straight out of main(). This should be cleaned up in the
// future.
//
//===----------------------------------------------------------------------===//

#ifndef LDC_DRIVER_CODEGENERATOR_H
#define LDC_DRIVER_CODEGENERATOR_H

#include "gen/irstate.h"

namespace ldc {

class CodeGenerator {
public:
CodeGenerator(llvm::LLVMContext &context, bool singleObj);
~CodeGenerator();
void emit(Module *m);

private:
void prepareLLModule(Module *m);
void finishLLModule(Module *m);
void writeAndFreeLLModule(const char *filename);

llvm::LLVMContext &context_;
int moduleCount_;
bool const singleObj_;
IRState *ir_;
const char *firstModuleObjfileName_;
};
}

#endif
5 changes: 0 additions & 5 deletions driver/linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
#include "gen/optimizer.h"
#include "gen/programs.h"
#include "llvm/ADT/Triple.h"
#if LDC_LLVM_VER >= 305
#include "llvm/Linker/Linker.h"
#else
#include "llvm/Linker.h"
#endif
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Path.h"
Expand Down
Loading

0 comments on commit d1e764c

Please sign in to comment.