Use Module::members -> Dsymbol::codegen to define symbols.

This commit fundamentally changes the way symbol emission in
LDC works: Previously, whenever a declaration was used in some
way, the compiler would check whether it actually needs to be
defined in the currently processed module, based only on the
symbol itself. This lack of contextual information proved to
be a major problem in correctly handling emission of templates
(see e.g. #454).

Now, the DtoResolve…() family of functions and similar only
ever declare the symbols, and definition is handled by doing
a single pass over Module::members for the root module. This
is the same strategy that DMD uses as well, which should
also reduce the maintainance burden down the road (which is
important as during the last few releases, there was pretty
much always a symbol emission related problem slowing us
down).

Our old approach might have been a bit better tuned w.r.t.
avoiding emission of unneeded template instances, but 2.064
will bring improvements here (DMD: FuncDeclaration::toObjFile).
Barring such issues, the change shoud also marginally improve
compile times because of declarations no longer being emitted
when they are not needed.

In the future, we should also consider refactoring the code
so that it no longer directly accesses Dsymbol::ir but uses
wrapper functions that ensure that the appropriate
DtoResolve…() function has been called.

GitHub: Fixes #454.
This commit is contained in:
David Nadlinger
2013-10-13 04:31:41 +02:00
parent b556ad9996
commit 787c147986
22 changed files with 439 additions and 517 deletions

View File

@@ -702,6 +702,12 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
Logger::println("DtoDeclareFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars());
LOG_SCOPE;
if (fdecl->isUnitTestDeclaration() && !global.params.useUnitTests)
{
Logger::println("unit tests not enabled");
return;
}
//printf("declare function: %s\n", fdecl->toPrettyChars());
// intrinsic sanity check
@@ -715,10 +721,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
TypeFunction* f = static_cast<TypeFunction*>(t);
IrFuncTy &irFty = fdecl->irFty;
bool declareOnly = !mustDefineSymbol(fdecl);
if (fdecl->llvmInternal == LLVMva_start)
declareOnly = true;
if (!fdecl->ir.irFunc) {
fdecl->ir.irFunc = new IrFunction(fdecl);
@@ -753,9 +755,16 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName);
if (!func) {
if(fdecl->llvmInternal == LLVMinline_ir)
{
func = DtoInlineIRFunction(fdecl);
}
else
func = LLFunction::Create(functype, DtoLinkage(fdecl), mangledName, gIR->module);
{
// All function declarations are "external" - any other linkage type
// is set when actually defining the function.
func = LLFunction::Create(functype,
llvm::GlobalValue::ExternalLinkage, mangledName, gIR->module);
}
} else if (func->getFunctionType() != functype) {
error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle());
}
@@ -792,35 +801,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
gIR->mainFunc = func;
}
// shared static ctor
if (fdecl->isSharedStaticCtorDeclaration()) {
if (mustDefineSymbol(fdecl)) {
gIR->sharedCtors.push_back(fdecl);
}
}
// shared static dtor
else if (StaticDtorDeclaration *dtorDecl = fdecl->isSharedStaticDtorDeclaration()) {
if (mustDefineSymbol(fdecl)) {
gIR->sharedDtors.push_front(fdecl);
if (dtorDecl->vgate)
gIR->sharedGates.push_front(dtorDecl->vgate);
}
} else
// static ctor
if (fdecl->isStaticCtorDeclaration()) {
if (mustDefineSymbol(fdecl)) {
gIR->ctors.push_back(fdecl);
}
}
// static dtor
else if (StaticDtorDeclaration *dtorDecl = fdecl->isStaticDtorDeclaration()) {
if (mustDefineSymbol(fdecl)) {
gIR->dtors.push_front(fdecl);
if (dtorDecl->vgate)
gIR->gates.push_front(dtorDecl->vgate);
}
}
if (fdecl->neverInline)
{
fdecl->ir.irFunc->setNeverInline();
@@ -909,14 +889,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
}
}
}
if (fdecl->isUnitTestDeclaration() && !declareOnly)
gIR->unitTests.push_back(fdecl);
if (!declareOnly)
Type::sir->addFunctionBody(fdecl->ir.irFunc);
else
assert(func->getLinkage() != llvm::GlobalValue::InternalLinkage);
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -927,15 +899,37 @@ void DtoDefineFunction(FuncDeclaration* fd)
{
DtoDeclareFunction(fd);
if (fd->ir.defined) return;
fd->ir.defined = true;
assert(fd->ir.declared);
if (Logger::enabled())
Logger::println("DtoDefineFunc(%s): %s", fd->toPrettyChars(), fd->loc.toChars());
Logger::println("DtoDefineFunction(%s): %s", fd->toPrettyChars(), fd->loc.toChars());
LOG_SCOPE;
// Be sure to call DtoDeclareFunction first, as LDC_inline_asm functions are
// "defined" there. TODO: Clean this up.
if (fd->ir.defined) return;
fd->ir.defined = true;
if (fd->isUnitTestDeclaration()) {
if (global.params.useUnitTests)
gIR->unitTests.push_back(fd);
else
return;
} else if (fd->isSharedStaticCtorDeclaration()) {
gIR->sharedCtors.push_back(fd);
} else if (StaticDtorDeclaration *dtorDecl = fd->isSharedStaticDtorDeclaration()) {
gIR->sharedDtors.push_front(fd);
if (dtorDecl->vgate)
gIR->sharedGates.push_front(dtorDecl->vgate);
} else if (fd->isStaticCtorDeclaration()) {
gIR->ctors.push_back(fd);
} else if (StaticDtorDeclaration *dtorDecl = fd->isStaticDtorDeclaration()) {
gIR->dtors.push_front(fd);
if (dtorDecl->vgate)
gIR->gates.push_front(dtorDecl->vgate);
}
// if this function is naked, we take over right away! no standard processing!
if (fd->naked)
{
@@ -954,9 +948,6 @@ void DtoDefineFunction(FuncDeclaration* fd)
llvm::Function* func = fd->ir.irFunc->func;
// sanity check
assert(mustDefineSymbol(fd));
// set module owner
fd->ir.DModule = gIR->dmodule;
@@ -972,6 +963,8 @@ void DtoDefineFunction(FuncDeclaration* fd)
if (fd->isMain())
gIR->emitMain = true;
func->setLinkage(DtoLinkage(fd));
// On x86_64, always set 'uwtable' for System V ABI compatibility.
// TODO: Find a better place for this.
if (global.params.targetTriple.getArch() == llvm::Triple::x86_64)