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:
Christian Kamm
2009-03-07 19:38:00 +01:00
parent ed9591d81f
commit 95f12f04f1
4 changed files with 78 additions and 26 deletions

View File

@@ -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; }

View File

@@ -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();

View File

@@ -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
View File

@@ -0,0 +1,6 @@
#ifndef LDC_GEN_TOOBJ_H
#define LDC_GEN_TOOBJ_H
void writeModule(llvm::Module* m, std::string filename);
#endif