mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
Add '-singleobj' command line switch that will tell LDC to link LLVM modules internally and only emit a single object file.
The switch allows the optimizer and inliner to run on all modules at once and opens the door for template instantiation improvements that should lower compile time and executable size.
This commit is contained in:
@@ -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; }
|
||||
|
||||
50
gen/main.cpp
50
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<bool> singleObj("singleobj",
|
||||
cl::desc("Create only a single output object file"),
|
||||
cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<bool> 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<llvm::Module*> 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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
|
||||
6
gen/toobj.h
Normal file
6
gen/toobj.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef LDC_GEN_TOOBJ_H
|
||||
#define LDC_GEN_TOOBJ_H
|
||||
|
||||
void writeModule(llvm::Module* m, std::string filename);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user