diff --git a/dmd/module.h b/dmd/module.h index ac8f103a..cdf6feb5 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -30,6 +30,7 @@ struct Library; #if IN_LLVM struct DValue; typedef DValue elem; +namespace llvm { class Module; } #else #ifdef IN_GCC union tree_node; typedef union tree_node elem; @@ -133,7 +134,6 @@ struct Module : Package #ifdef _DH void genhdrfile(); // generate D import file #endif - void genobjfile(int multiobj); // void gensymfile(); void gendocfile(); int needModuleInfo(); @@ -171,6 +171,7 @@ struct Module : Package void genmoduleinfo(); // LDC + llvm::Module* genLLVMModule(int multiobj); void buildTargetFiles(); File* buildFilePath(char* forcename, char* path, char* ext); Module *isModule() { return this; } diff --git a/gen/main.cpp b/gen/main.cpp index 63152101..6a5495d7 100644 --- a/gen/main.cpp +++ b/gen/main.cpp @@ -4,6 +4,7 @@ // which uses the llvm license #include "gen/llvm.h" +#include "llvm/Linker.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachineRegistry.h" @@ -32,6 +33,7 @@ #include "gen/logger.h" #include "gen/linker.h" #include "gen/irstate.h" +#include "gen/toobj.h" #include "gen/cl_options.h" #include "gen/cl_helpers.h" @@ -41,6 +43,10 @@ extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv); extern void backend_init(); extern void backend_term(); +static cl::opt singleObj("singleobj", + cl::desc("Create only a single output object file"), + cl::ZeroOrMore); + static cl::opt noDefaultLib("nodefaultlib", cl::desc("Don't add a default library for linking implicitly"), cl::ZeroOrMore); @@ -796,6 +802,9 @@ int main(int argc, char** argv) if (global.errors) fatal(); + // collects llvm modules to be linked if singleobj is passed + std::vector llvmModules; + // Generate output files for (int i = 0; i < modules.dim; i++) { @@ -804,8 +813,16 @@ int main(int argc, char** argv) printf("code %s\n", m->toChars()); if (global.params.obj) { - m->genobjfile(0); - global.params.objfiles->push(m->objfile->name->str); + llvm::Module* lm = m->genLLVMModule(0); + if (!singleObj) + { + m->deleteObjFile(); + writeModule(lm, m->objfile->name->str); + global.params.objfiles->push(m->objfile->name->str); + delete lm; + } + else + llvmModules.push_back(lm); } if (global.errors) m->deleteObjFile(); @@ -815,7 +832,34 @@ int main(int argc, char** argv) m->gendocfile(); } } - + + // internal linking for singleobj + if (singleObj && llvmModules.size() > 0) + { + Module* m = (Module*)modules.data[0]; + char* name = m->toChars(); + char* filename = m->objfile->name->str; + + llvm::Linker linker(name, name); + std::string errormsg; + for (int i = 0; i < llvmModules.size(); i++) + { + if(linker.LinkInModule(llvmModules[i], &errormsg)) + error(errormsg.c_str()); + delete llvmModules[i]; + } + + // workaround for llvm::Linker bug, see llvm #3749 + llvm::GlobalVariable* ctors = linker.getModule()->getGlobalVariable("llvm.global_ctors"); + if (ctors) + while (ctors->getNumUses() > 0) + delete *ctors->use_begin(); + + m->deleteObjFile(); + writeModule(linker.getModule(), filename); + global.params.objfiles->push(filename); + } + backend_term(); if (global.errors) fatal(); diff --git a/gen/toobj.cpp b/gen/toobj.cpp index 4b58d7b6..0284f3bb 100644 --- a/gen/toobj.cpp +++ b/gen/toobj.cpp @@ -70,7 +70,7 @@ void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath); ////////////////////////////////////////////////////////////////////////////////////////// -void Module::genobjfile(int multiobj) +llvm::Module* Module::genLLVMModule(int multiobj) { bool logenabled = Logger::enabled(); if (llvmForceLogging && !logenabled) @@ -85,9 +85,6 @@ void Module::genobjfile(int multiobj) assert(!global.errors); - // start by deleting the old object file - deleteObjFile(); - // name the module std::string mname(toChars()); if (md != 0) @@ -174,17 +171,29 @@ void Module::genobjfile(int multiobj) } } + gIR = NULL; + + if (llvmForceLogging && !logenabled) + { + Logger::disable(); + } + + return ir.module; +} + +void writeModule(llvm::Module* m, std::string filename) +{ // run optimizer - ldc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline); + ldc_optimize_module(m, global.params.optimizeLevel, global.params.llvmInline); // verify the llvm if (!noVerify && (global.params.optimizeLevel >= 0 || global.params.llvmInline)) { std::string verifyErr; Logger::println("Verifying module... again..."); LOG_SCOPE; - if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) + if (llvm::verifyModule(*m,llvm::ReturnStatusAction,&verifyErr)) { - error("%s", verifyErr.c_str()); + //error("%s", verifyErr.c_str()); fatal(); } else { @@ -197,27 +206,27 @@ void Module::genobjfile(int multiobj) // write LLVM bitcode if (global.params.output_bc) { - LLPath bcpath = LLPath(objfile->name->toChars()); + LLPath bcpath = LLPath(filename); bcpath.eraseSuffix(); bcpath.appendSuffix(std::string(global.bc_ext)); Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str()); std::ofstream bos(bcpath.c_str(), std::ios::binary); - llvm::WriteBitcodeToFile(ir.module, bos); + llvm::WriteBitcodeToFile(m, bos); } // write LLVM IR if (global.params.output_ll) { - LLPath llpath = LLPath(objfile->name->toChars()); + LLPath llpath = LLPath(filename); llpath.eraseSuffix(); llpath.appendSuffix(std::string(global.ll_ext)); Logger::println("Writing LLVM asm to: %s\n", llpath.c_str()); std::ofstream aos(llpath.c_str()); - ir.module->print(aos, NULL); + m->print(aos, NULL); } // write native assembly if (global.params.output_s || global.params.output_o) { - LLPath spath = LLPath(objfile->name->toChars()); + LLPath spath = LLPath(filename); spath.eraseSuffix(); spath.appendSuffix(std::string(global.s_ext)); if (!global.params.output_s) { @@ -227,12 +236,12 @@ void Module::genobjfile(int multiobj) std::string err; { llvm::raw_fd_ostream out(spath.c_str(), false, err); - write_asm_to_file(*gTargetMachine, *ir.module, out); + write_asm_to_file(*gTargetMachine, *m, out); } // call gcc to convert assembly to object file if (global.params.output_o) { - LLPath objpath = LLPath(objfile->name->toChars()); + LLPath objpath = LLPath(filename); assemble(spath, objpath); } @@ -240,14 +249,6 @@ void Module::genobjfile(int multiobj) spath.eraseFromDisk(); } } - - delete ir.module; - gIR = NULL; - - if (llvmForceLogging && !logenabled) - { - Logger::disable(); - } } /* ================================================================== */ diff --git a/gen/toobj.h b/gen/toobj.h new file mode 100644 index 00000000..ecc4c0a5 --- /dev/null +++ b/gen/toobj.h @@ -0,0 +1,6 @@ +#ifndef LDC_GEN_TOOBJ_H +#define LDC_GEN_TOOBJ_H + +void writeModule(llvm::Module* m, std::string filename); + +#endif