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

@@ -478,7 +478,11 @@ struct TypeInfoClassDeclaration : TypeInfoDeclaration
#endif
#if IN_LLVM
void codegen(Ir*);
// TypeInfoClassDeclaration instances are different; they describe
// __ClassZ/__InterfaceZ symbols instead of a TypeInfo_….init one. DMD also
// generates them for SomeInterface.classinfo access, so we can't just
// distinguish between them using tinfo and thus need to override codegen().
void codegen(Ir* p);
void llvmDefine();
#endif
};
@@ -814,7 +818,9 @@ struct FuncDeclaration : Declaration
// functions
FuncDeclarations siblingCallers; // Sibling nested functions which
// called this one
#if IN_DMD
FuncDeclarations deferred; // toObjFile() these functions after this one
#endif
unsigned flags;
#define FUNCFLAGpurityInprocess 1 // working on determining purity

View File

@@ -4735,11 +4735,7 @@ void UnitTestDeclaration::semantic(Scope *sc)
{ sc = scope;
scope = NULL;
}
#if IN_LLVM
if (global.params.useUnitTests && sc->module->isRoot)
#else
if (global.params.useUnitTests)
#endif
{
if (!type)
type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd);

View File

@@ -867,14 +867,6 @@ static LLValue* DtoArrayEqCmp_impl(Loc& loc, const char* func, DValue* l, DValue
if (useti) {
Type* t = l->getType();
LLValue* tival = DtoTypeInfoOf(t);
// DtoTypeInfoOf only does declare, not enough in this case :/
t->vtinfo->codegen(Type::sir);
#if 0
if (Logger::enabled())
Logger::cout() << "typeinfo decl: " << *tival << '\n';
#endif
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
}

View File

@@ -35,24 +35,21 @@
void DtoResolveClass(ClassDeclaration* cd)
{
// make sure the base classes are processed first
ArrayIter<BaseClass> base_iter(cd->baseclasses);
while (base_iter.more())
{
BaseClass* bc = base_iter.get();
if (bc)
{
bc->base->codegen(Type::sir);
}
base_iter.next();
}
if (cd->ir.resolved) return;
cd->ir.resolved = true;
Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
// make sure the base classes are processed first
ArrayIter<BaseClass> base_iter(cd->baseclasses);
while (base_iter.more())
{
BaseClass* bc = base_iter.get();
DtoResolveClass(bc->base);
base_iter.next();
}
// make sure type exists
DtoType(cd->type);
@@ -73,11 +70,6 @@ void DtoResolveClass(ClassDeclaration* cd)
}
}
bool needs_def = mustDefineSymbol(cd);
// emit the ClassZ symbol
LLGlobalVariable* ClassZ = irAggr->getClassInfoSymbol();
// emit the interfaceInfosZ symbol if necessary
if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0)
irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built
@@ -87,43 +79,6 @@ void DtoResolveClass(ClassDeclaration* cd)
{
irAggr->initializeInterface();
}
else
{
// emit the initZ symbol
LLGlobalVariable* initZ = irAggr->getInitSymbol();
// emit the vtblZ symbol
LLGlobalVariable* vtblZ = irAggr->getVtblSymbol();
// perform definition
if (needs_def)
{
// set symbol initializers
initZ->setInitializer(irAggr->getDefaultInit());
vtblZ->setInitializer(irAggr->getVtblInit());
}
}
// emit members
if (cd->members)
{
ArrayIter<Dsymbol> it(*cd->members);
while (!it.done())
{
Dsymbol* member = it.get();
if (member)
member->codegen(Type::sir);
it.next();
}
}
if (needs_def)
{
// emit typeinfo
DtoTypeInfoOf(cd->type);
// define classinfo
ClassZ->setInitializer(irAggr->getClassInfoInit());
}
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -131,7 +86,7 @@ void DtoResolveClass(ClassDeclaration* cd)
DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp)
{
// resolve type
tc->sym->codegen(Type::sir);
DtoResolveClass(tc->sym);
// allocate
LLValue* mem;
@@ -143,7 +98,7 @@ DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp)
// custom allocator
else if (newexp->allocator)
{
newexp->allocator->codegen(Type::sir);
DtoResolveDsymbol(newexp->allocator);
DFuncValue dfn(newexp->allocator, newexp->allocator->ir.irFunc->func);
DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs);
mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom");
@@ -184,7 +139,7 @@ DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp)
{
Logger::println("Calling constructor");
assert(newexp->arguments != NULL);
newexp->member->codegen(Type::sir);
DtoResolveDsymbol(newexp->member);
DFuncValue dfn(newexp->member, newexp->member->ir.irFunc->func, mem);
return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments);
}
@@ -197,7 +152,7 @@ DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp)
void DtoInitClass(TypeClass* tc, LLValue* dst)
{
tc->sym->codegen(Type::sir);
DtoResolveClass(tc->sym);
uint64_t n = tc->sym->structsize - Target::ptrsize * 2;
@@ -365,8 +320,8 @@ DValue* DtoDynamicCastObject(DValue* val, Type* _to)
// call:
// Object _d_dynamic_cast(Object o, ClassInfo c)
ClassDeclaration::object->codegen(Type::sir);
ClassDeclaration::classinfo->codegen(Type::sir);
DtoResolveClass(ClassDeclaration::object);
DtoResolveClass(ClassDeclaration::classinfo);
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast");
LLFunctionType* funcTy = func->getFunctionType();
@@ -378,7 +333,7 @@ DValue* DtoDynamicCastObject(DValue* val, Type* _to)
// ClassInfo c
TypeClass* to = static_cast<TypeClass*>(_to->toBasetype());
to->sym->codegen(Type::sir);
DtoResolveClass(to->sym);
LLValue* cinfo = to->sym->ir.irAggr->getClassInfoSymbol();
// unfortunately this is needed as the implementation of object differs somehow from the declaration
@@ -428,8 +383,8 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* _to)
// call:
// Object _d_interface_cast(void* p, ClassInfo c)
ClassDeclaration::object->codegen(Type::sir);
ClassDeclaration::classinfo->codegen(Type::sir);
DtoResolveClass(ClassDeclaration::object);
DtoResolveClass(ClassDeclaration::classinfo);
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_interface_cast");
LLFunctionType* funcTy = func->getFunctionType();
@@ -440,7 +395,7 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* _to)
// ClassInfo c
TypeClass* to = static_cast<TypeClass*>(_to->toBasetype());
to->sym->codegen(Type::sir);
DtoResolveClass(to->sym);
LLValue* cinfo = to->sym->ir.irAggr->getClassInfoSymbol();
// unfortunately this is needed as the implementation of object differs somehow from the declaration
// this could happen in user code as well :/
@@ -623,7 +578,7 @@ static LLConstant* build_class_dtor(ClassDeclaration* cd)
if (!dtor)
return getNullPtr(getVoidPtrType());
dtor->codegen(Type::sir);
DtoResolveDsymbol(dtor);
return llvm::ConstantExpr::getBitCast(dtor->ir.irFunc->func, getPtrToType(LLType::getInt8Ty(gIR->context())));
}

View File

@@ -14,11 +14,14 @@
#include "init.h"
#include "rmem.h"
#include "template.h"
#include "gen/classes.h"
#include "gen/functions.h"
#include "gen/irstate.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "gen/utils.h"
#include "ir/ir.h"
#include "ir/irtype.h"
#include "ir/irvar.h"
@@ -27,53 +30,129 @@
void Dsymbol::codegen(Ir*)
{
Logger::println("Ignoring Dsymbol::codegen for %s", toPrettyChars());
IF_LOG Logger::println("Ignoring Dsymbol::codegen for %s", toPrettyChars());
}
/* ================================================================== */
void InterfaceDeclaration::codegen(Ir*)
void InterfaceDeclaration::codegen(Ir* p)
{
IF_LOG Logger::println("InterfaceDeclaration::codegen: '%s'", toPrettyChars());
LOG_SCOPE
if (ir.defined) return;
ir.defined = true;
if (type->ty == Terror)
{ error("had semantic errors when compiling");
return;
}
if (members && symtab)
{
DtoResolveDsymbol(this);
// Emit any members (e.g. final functions).
for (ArrayIter<Dsymbol> it(members); !it.done(); it.next())
{
it->codegen(p);
}
// Emit TypeInfo.
DtoTypeInfoOf(type);
// Define __InterfaceZ.
llvm::GlobalVariable *interfaceZ = ir.irAggr->getClassInfoSymbol();
interfaceZ->setInitializer(ir.irAggr->getClassInfoInit());
interfaceZ->setLinkage(DtoExternalLinkage(this));
}
}
/* ================================================================== */
void StructDeclaration::codegen(Ir*)
void StructDeclaration::codegen(Ir* p)
{
IF_LOG Logger::println("StructDeclaration::codegen: '%s'", toPrettyChars());
LOG_SCOPE
if (ir.defined) return;
ir.defined = true;
if (type->ty == Terror)
{ error("had semantic errors when compiling");
return;
}
if (members && symtab)
DtoResolveDsymbol(this);
{
DtoResolveStruct(this);
for (ArrayIter<Dsymbol> it(members); !it.done(); it.next())
{
it->codegen(p);
}
// Define the __initZ symbol.
llvm::GlobalVariable *initZ = ir.irAggr->getInitSymbol();
initZ->setInitializer(ir.irAggr->getDefaultInit());
initZ->setLinkage(DtoExternalLinkage(this));
// emit typeinfo
DtoTypeInfoOf(type);
}
}
/* ================================================================== */
void ClassDeclaration::codegen(Ir*)
void ClassDeclaration::codegen(Ir* p)
{
IF_LOG Logger::println("ClassDeclaration::codegen: '%s'", toPrettyChars());
LOG_SCOPE
if (ir.defined) return;
ir.defined = true;
if (type->ty == Terror)
{ error("had semantic errors when compiling");
return;
}
if (members && symtab)
DtoResolveDsymbol(this);
{
DtoResolveClass(this);
for (ArrayIter<Dsymbol> it(members); !it.done(); it.next())
{
it->codegen(p);
}
llvm::GlobalValue::LinkageTypes const linkage = DtoExternalLinkage(this);
llvm::GlobalVariable *initZ = ir.irAggr->getInitSymbol();
initZ->setInitializer(ir.irAggr->getDefaultInit());
initZ->setLinkage(linkage);
llvm::GlobalVariable *vtbl = ir.irAggr->getVtblSymbol();
vtbl->setInitializer(ir.irAggr->getVtblInit());
vtbl->setLinkage(linkage);
llvm::GlobalVariable *classZ = ir.irAggr->getClassInfoSymbol();
classZ->setInitializer(ir.irAggr->getClassInfoInit());
classZ->setLinkage(linkage);
// No need to do TypeInfo here, it is <name>__classZ for classes in D2.
}
}
/* ================================================================== */
void TupleDeclaration::codegen(Ir* p)
{
Logger::println("TupleDeclaration::codegen(): %s", toChars());
IF_LOG Logger::println("TupleDeclaration::codegen(): '%s'", toPrettyChars());
LOG_SCOPE
if (ir.defined) return;
ir.defined = true;
assert(isexp);
assert(objects);
@@ -92,14 +171,19 @@ void TupleDeclaration::codegen(Ir* p)
void VarDeclaration::codegen(Ir* p)
{
Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars());
IF_LOG Logger::println("VarDeclaration::codegen(): '%s'", toPrettyChars());
LOG_SCOPE;
if (ir.defined) return;
ir.defined = true;
if (type->ty == Terror)
{ error("had semantic errors when compiling");
return;
}
DtoResolveVariable(this);
// just forward aliases
if (aliassym)
{
@@ -108,10 +192,6 @@ void VarDeclaration::codegen(Ir* p)
return;
}
// output the parent aggregate first
if (AggregateDeclaration* ad = isMember())
ad->codegen(p);
// global variable
if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init))
{
@@ -122,37 +202,14 @@ void VarDeclaration::codegen(Ir* p)
"manifest constant being codegen'd!");
#endif
// don't duplicate work
if (this->ir.resolved) return;
this->ir.resolved = true;
this->ir.declared = true;
llvm::GlobalVariable *gvar = llvm::cast<llvm::GlobalVariable>(
this->ir.irGlobal->value);
assert(gvar && "DtoResolveVariable should have created value");
this->ir.irGlobal = new IrGlobal(this);
Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());
const bool isLLConst = isConst() && init;
const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this);
assert(!ir.initialized);
ir.initialized = gIR->dmodule;
std::string llName(mangle());
// Since the type of a global must exactly match the type of its
// initializer, we cannot know the type until after we have emitted the
// latter (e.g. in case of unions, …). However, it is legal for the
// initializer to refer to the address of the variable. Thus, we first
// create a global with the generic type (note the assignment to
// this->ir.irGlobal->value!), and in case we also do an initializer
// with a different type later, swap it out and replace any existing
// uses with bitcasts to the previous type.
llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module,
i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName,
isThreadlocal());
this->ir.irGlobal->value = gvar;
// Check if we are defining or just declaring the global in this module.
if (!(storage_class & STCextern) && mustDefineSymbol(this))
if (!(storage_class & STCextern))
{
// Build the initializer. Might use this->ir.irGlobal->value!
LLConstant *initVal = DtoConstInitializer(loc, type, init);
@@ -161,10 +218,12 @@ void VarDeclaration::codegen(Ir* p)
if (initVal->getType() != gvar->getType()->getElementType())
{
llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc,
*gIR->module, initVal->getType(), isLLConst, llLinkage, 0,
*gIR->module, initVal->getType(), gvar->isConstant(),
llLinkage, 0,
"", // We take on the name of the old global below.
isThreadlocal());
gvar->isThreadLocal());
newGvar->setAlignment(gvar->getAlignment());
newGvar->takeName(gvar);
llvm::Constant* newValue =
@@ -180,17 +239,12 @@ void VarDeclaration::codegen(Ir* p)
assert(!ir.irGlobal->constInit);
ir.irGlobal->constInit = initVal;
gvar->setInitializer(initVal);
gvar->setLinkage(llLinkage);
// Also set up the edbug info.
gIR->DBuilder.EmitGlobalVariable(gvar, this);
}
// Set the alignment (it is important not to use type->alignsize because
// VarDeclarations can have an align() attribute independent of the type
// as well).
if (alignment != STRUCTALIGN_DEFAULT)
gvar->setAlignment(alignment);
// If this global is used from a naked function, we need to create an
// artificial "use" for it, or it could be removed by the optimizer if
// the only reference to it is in inline asm.
@@ -206,9 +260,12 @@ void VarDeclaration::codegen(Ir* p)
void TypedefDeclaration::codegen(Ir*)
{
Logger::print("TypedefDeclaration::codegen: %s\n", toChars());
IF_LOG Logger::println("TypedefDeclaration::codegen: '%s'", toPrettyChars());
LOG_SCOPE;
if (ir.defined) return;
ir.defined = true;
if (type->ty == Terror)
{ error("had semantic errors when compiling");
return;
@@ -222,7 +279,7 @@ void TypedefDeclaration::codegen(Ir*)
void EnumDeclaration::codegen(Ir*)
{
Logger::println("Ignoring EnumDeclaration::codegen for %s", toChars());
IF_LOG Logger::println("Ignoring EnumDeclaration::codegen: '%s'", toPrettyChars());
if (type->ty == Terror)
{ error("had semantic errors when compiling");
@@ -237,7 +294,7 @@ void FuncDeclaration::codegen(Ir* p)
// don't touch function aliases, they don't contribute any new symbols
if (!isFuncAliasDeclaration())
{
DtoResolveDsymbol(this);
DtoDefineFunction(this);
}
}
@@ -245,18 +302,17 @@ void FuncDeclaration::codegen(Ir* p)
void TemplateInstance::codegen(Ir* p)
{
#if LOG
printf("TemplateInstance::codegen('%s', this = %p)\n", toChars(), this);
#endif
if (ignore)
return;
IF_LOG Logger::println("TemplateInstance::codegen: '%s'", toPrettyChars());
LOG_SCOPE
if (ir.defined) return;
ir.defined = true;
if (!errors && members)
{
for (unsigned i = 0; i < members->dim; i++)
{
Dsymbol *s = static_cast<Dsymbol *>(members->data[i]);
s->codegen(p);
(*members)[i]->codegen(p);
}
}
}
@@ -265,14 +321,17 @@ void TemplateInstance::codegen(Ir* p)
void TemplateMixin::codegen(Ir* p)
{
IF_LOG Logger::println("TemplateInstance::codegen: '%s'", toPrettyChars());
LOG_SCOPE
if (ir.defined) return;
ir.defined = true;
if (!errors && members)
{
for (unsigned i = 0; i < members->dim; i++)
{
Dsymbol *s = static_cast<Dsymbol *>(members->data[i]);
if (s->isVarDeclaration())
continue;
s->codegen(p);
(*members)[i]->codegen(p);
}
}
}

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)

View File

@@ -1005,8 +1005,86 @@ void DtoResolveDsymbol(Dsymbol* dsym)
else if (TypeInfoDeclaration* fd = dsym->isTypeInfoDeclaration()) {
DtoResolveTypeInfo(fd);
}
else {
llvm_unreachable("Unsupported DSymbol for DtoResolveDsymbol.");
else if (VarDeclaration* vd = dsym->isVarDeclaration()) {
DtoResolveVariable(vd);
}
}
void DtoResolveVariable(VarDeclaration* vd)
{
if (vd->isTypeInfoDeclaration())
return DtoResolveTypeInfo(static_cast<TypeInfoDeclaration *>(vd));
IF_LOG Logger::println("DtoResolveVariable(%s)", vd->toPrettyChars());
LOG_SCOPE;
// just forward aliases
// TODO: Is this required here or is the check in VarDeclaration::codegen
// sufficient?
if (vd->aliassym)
{
Logger::println("alias sym");
DtoResolveDsymbol(vd->aliassym);
return;
}
if (AggregateDeclaration* ad = vd->isMember())
DtoResolveDsymbol(ad);
// global variable
if (vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init))
{
Logger::println("data segment");
#if 0 // TODO:
assert(!(storage_class & STCmanifest) &&
"manifest constant being codegen'd!");
#endif
// don't duplicate work
if (vd->ir.resolved) return;
vd->ir.resolved = true;
vd->ir.declared = true;
vd->ir.irGlobal = new IrGlobal(vd);
IF_LOG {
if (vd->parent)
Logger::println("parent: %s (%s)", vd->parent->toChars(), vd->parent->kind());
else
Logger::println("parent: null");
}
const bool isLLConst = vd->isConst() && vd->init;
assert(!vd->ir.initialized);
vd->ir.initialized = gIR->dmodule;
std::string llName(vd->mangle());
// Since the type of a global must exactly match the type of its
// initializer, we cannot know the type until after we have emitted the
// latter (e.g. in case of unions, …). However, it is legal for the
// initializer to refer to the address of the variable. Thus, we first
// create a global with the generic type (note the assignment to
// vd->ir.irGlobal->value!), and in case we also do an initializer
// with a different type later, swap it out and replace any existing
// uses with bitcasts to the previous type.
//
// We always start out with external linkage; any other type is set
// when actually defining it in VarDeclaration::codegen.
llvm::GlobalVariable* gvar = getOrCreateGlobal(vd->loc, *gIR->module,
i1ToI8(DtoType(vd->type)), isLLConst, llvm::GlobalValue::ExternalLinkage,
0, llName, vd->isThreadlocal());
vd->ir.irGlobal->value = gvar;
// Set the alignment (it is important not to use type->alignsize because
// VarDeclarations can have an align() attribute independent of the type
// as well).
if (vd->alignment != STRUCTALIGN_DEFAULT)
gvar->setAlignment(vd->alignment);
if (Logger::enabled())
Logger::cout() << *gvar << '\n';
}
}
@@ -1293,7 +1371,7 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init)
else if (StructInitializer* si = init->isStructInitializer())
{
Logger::println("const struct initializer");
si->ad->codegen(Type::sir);
DtoResolveDsymbol(si->ad);
return si->ad->ir.irAggr->createStructInitializer(si);
}
else if (ArrayInitializer* ai = init->isArrayInitializer())
@@ -1502,98 +1580,6 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s
//////////////////////////////////////////////////////////////////////////////////////////
bool mustDefineSymbol(Dsymbol* s)
{
if (FuncDeclaration* fd = s->isFuncDeclaration())
{
// we can't (and probably shouldn't?) define functions
// that weren't semantic3'ed
if (fd->semanticRun < PASSsemantic3)
return false;
// If a function has no body, we cannot possibly emit it (and so it
// cannot be available_externally either).
if (!fd->fbody)
return false;
if (fd->isArrayOp == 1)
return true;
if (global.inExtraInliningSemantic && fd->availableExternally) {
// Emit extra functions if we're inlining.
// These will get available_externally linkage,
// so they shouldn't end up in object code.
assert(fd->type->ty == Tfunction);
// * If we define extra static constructors, static destructors
// and unittests they'll get registered to run, and we won't
// be calling them directly anyway.
// * If it's a large function, don't emit it unnecessarily.
// Use DMD's canInline() to determine whether it's large.
// inlineCost() members have been changed to pay less attention
// to DMDs limitations, but still have some issues. The most glaring
// offenders are any kind of control flow statements other than
// 'if' and 'return'.
if ( !fd->isStaticCtorDeclaration()
&& !fd->isStaticDtorDeclaration()
&& !fd->isUnitTestDeclaration()
&& fd->canInline(true, false, false))
{
return true;
}
// This was only semantic'ed for inlining checks.
// We won't be inlining this, so we only need to emit a declaration.
return false;
}
}
if (VarDeclaration* vd = s->isVarDeclaration())
{
// Never define 'extern' variables.
if (vd->storage_class & STCextern)
return false;
}
// Inlining checks may create some variable and class declarations
// we don't need to emit.
if (global.inExtraInliningSemantic)
{
if (VarDeclaration* vd = s->isVarDeclaration())
if (vd->availableExternally)
return false;
if (ClassDeclaration* cd = s->isClassDeclaration())
if (cd->availableExternally)
return false;
}
TemplateInstance* tinst = DtoIsTemplateInstance(s, true);
if (tinst)
{
if (!global.params.singleObj)
return true;
if (!tinst->emittedInModule)
{
gIR->seenTemplateInstances.insert(tinst);
tinst->emittedInModule = gIR->dmodule;
}
return tinst->emittedInModule == gIR->dmodule;
}
return s->getModule() == gIR->dmodule;
}
//////////////////////////////////////////////////////////////////////////////////////////
bool needsTemplateLinkage(Dsymbol* s)
{
return DtoIsTemplateInstance(s) && mustDefineSymbol(s);
}
//////////////////////////////////////////////////////////////////////////////////////////
bool hasUnalignedFields(Type* t)
{
t = t->toBasetype();
@@ -1734,7 +1720,7 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val)
FuncDeclaration *fd = sd->postblit;
if (fd->storage_class & STCdisable)
fd->toParent()->error(loc, "is not copyable because it is annotated with @disable");
fd->codegen(Type::sir);
DtoResolveFunction(fd);
Expressions args;
DFuncValue dfn(fd, fd->ir.irFunc->func, val);
DtoCallFunction(loc, Type::basic[Tvoid], &dfn, &args);
@@ -1867,14 +1853,14 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl)
else if (ClassInfoDeclaration* cid = vd->isClassInfoDeclaration())
{
Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars());
cid->cd->codegen(Type::sir);;
DtoResolveClass(cid->cd);
return new DVarValue(type, vd, cid->cd->ir.irAggr->getClassInfoSymbol());
}
// typeinfo
else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration())
{
Logger::println("TypeInfoDeclaration");
tid->codegen(Type::sir);
DtoResolveTypeInfo(tid);
assert(tid->ir.getIrValue());
LLType* vartype = DtoType(type);
LLValue* m = tid->ir.getIrValue();
@@ -1923,7 +1909,7 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl)
// take care of forward references of global variables
const bool isGlobal = vd->isDataseg() || (vd->storage_class & STCextern);
if (isGlobal)
vd->codegen(Type::sir);
DtoResolveDsymbol(vd);
assert(vd->ir.isSet() && "Variable not resolved.");
@@ -1952,19 +1938,15 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl)
if (FuncDeclaration* fdecl = decl->isFuncDeclaration())
{
Logger::println("FuncDeclaration");
LLValue* func = 0;
fdecl = fdecl->toAliasFunc();
if (fdecl->llvmInternal == LLVMinline_asm)
{
// TODO: Is this needed? If so, what about other intrinsics?
error("special ldc inline asm is not a normal function");
fatal();
}
else if (fdecl->llvmInternal != LLVMva_arg)
{
fdecl->codegen(Type::sir);
func = fdecl->ir.irFunc->func;
}
return new DFuncValue(fdecl, func);
DtoResolveFunction(fdecl);
return new DFuncValue(fdecl, fdecl->ir.irFunc->func);
}
if (SymbolDeclaration* sdecl = decl->isSymbolDeclaration())
@@ -1975,7 +1957,7 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl)
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
assert(ts->sym);
ts->sym->codegen(Type::sir);
DtoResolveStruct(ts->sym);
LLValue* initsym = ts->sym->ir.irAggr->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
@@ -2011,7 +1993,7 @@ llvm::Constant* DtoConstSymbolAddress(const Loc& loc, Declaration* decl)
return NULL;
}
vd->codegen(Type::sir);
DtoResolveVariable(vd);
LLConstant* llc = llvm::dyn_cast<LLConstant>(vd->ir.getIrValue());
assert(llc);
return llc;
@@ -2019,7 +2001,7 @@ llvm::Constant* DtoConstSymbolAddress(const Loc& loc, Declaration* decl)
// static function
else if (FuncDeclaration* fd = decl->isFuncDeclaration())
{
fd->codegen(Type::sir);
DtoResolveFunction(fd);
IrFunction* irfunc = fd->ir.irFunc;
return irfunc->func;
}

View File

@@ -102,9 +102,15 @@ DValue* DtoPaintType(Loc& loc, DValue* val, Type* to);
// is template instance check, returns module where instantiated
TemplateInstance* DtoIsTemplateInstance(Dsymbol* s, bool checkLiteralOwner = false);
/// Generate code for the symbol.
/// Dispatches as appropriate.
/// Makes sure the declarations corresponding to the given D symbol have been
/// emitted to the currently processed LLVM module.
///
/// This means that dsym->ir can be expected to set to reasonable values.
///
/// This function does *not* emit any (function, variable) *definitions*; this
/// is done by Dsymbol::codegen.
void DtoResolveDsymbol(Dsymbol* dsym);
void DtoResolveVariable(VarDeclaration* var);
// declaration inside a declarationexp
void DtoVarDeclaration(VarDeclaration* var);
@@ -135,12 +141,6 @@ void findDefaultTarget();
/// Fixup an overloaded intrinsic name string.
void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name);
/// Returns true if the symbol should be defined in the current module, not just declared.
bool mustDefineSymbol(Dsymbol* s);
/// Returns true if the symbol needs template linkage, or just external.
bool needsTemplateLinkage(Dsymbol* s);
/// Returns true if there is any unaligned type inside the aggregate.
bool hasUnalignedFields(Type* t);

View File

@@ -398,9 +398,6 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir)
dsym->codegen(sir);
}
// emit function bodies
sir->emitFunctionBodies();
// for singleobj-compilation, fully emit all seen template instances
if (global.params.singleObj)
{
@@ -410,9 +407,6 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir)
for (it = ir.seenTemplateInstances.begin(); it != end; ++it)
(*it)->codegen(sir);
ir.seenTemplateInstances.clear();
// emit any newly added function bodies
sir->emitFunctionBodies();
}
}
@@ -532,8 +526,8 @@ void Module::genmoduleinfo()
std::vector<LLConstant*> classInits;
for (size_t i = 0; i < aclasses.dim; i++)
{
ClassDeclaration* cd = static_cast<ClassDeclaration*>(aclasses.data[i]);
cd->codegen(Type::sir);
ClassDeclaration* cd = aclasses[i];
DtoResolveClass(cd);
if (cd->isInterfaceDeclaration())
{
@@ -638,6 +632,7 @@ void Module::genmoduleinfo()
// create and set initializer
LLGlobalVariable *moduleInfoSym = moduleInfoSymbol();
b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym);
moduleInfoSym->setLinkage(llvm::GlobalValue::ExternalLinkage);
// build the modulereference and ctor for registering it
LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSym);

View File

@@ -85,6 +85,7 @@ void ExpStatement::toNakedIR(IRState *p)
// enum decls should always be safe
// make sure the symbols gets processed
// TODO: codegen() here is likely incorrect
d->declaration->codegen(Type::sir);
}

View File

@@ -20,8 +20,7 @@
RTTIBuilder::RTTIBuilder(AggregateDeclaration* base_class)
{
// make sure the base typeinfo class has been processed
base_class->codegen(Type::sir);
DtoResolveDsymbol(base_class);
base = base_class;
basetype = static_cast<TypeClass*>(base->type);
@@ -136,7 +135,7 @@ void RTTIBuilder::push_funcptr(FuncDeclaration* fd, Type* castto)
{
if (fd)
{
fd->codegen(Type::sir);
DtoResolveDsymbol(fd);
LLConstant* F = fd->ir.irFunc->func;
if (castto)
F = DtoBitCast(F, DtoType(castto));
@@ -177,7 +176,9 @@ void RTTIBuilder::finalize(LLType* type, LLValue* value)
LLConstant* tiInit = LLConstantStruct::get(st, inits);
// set the initializer
isaGlobalVar(value)->setInitializer(tiInit);
llvm::GlobalVariable* gvar = llvm::cast<llvm::GlobalVariable>(value);
gvar->setInitializer(tiInit);
gvar->setLinkage(TYPEINFO_LINKAGE_TYPE);
}
LLConstant* RTTIBuilder::get_constant(LLStructType *initType)

View File

@@ -55,32 +55,6 @@ void DtoResolveStruct(StructDeclaration* sd)
assert(!vd->ir.irField);
(void)new IrField(vd);
}
// perform definition
bool emitGlobalData = mustDefineSymbol(sd);
if (emitGlobalData)
{
// emit the initZ symbol
LLGlobalVariable* initZ = iraggr->getInitSymbol();
// set initZ initializer
initZ->setInitializer(iraggr->getDefaultInit());
}
// emit members
if (sd->members)
{
for (ArrayIter<Dsymbol> it(sd->members); !it.done(); it.next())
{
it.get()->codegen(Type::sir);
}
}
if (emitGlobalData)
{
// emit typeinfo
DtoTypeInfoOf(sd->type);
}
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -13,6 +13,7 @@
#include "id.h"
#include "init.h"
#include "mtype.h"
#include "module.h"
#include "port.h"
#include "rmem.h"
#include "template.h"
@@ -200,8 +201,7 @@ LLConstant* VarExp::toConstElem(IRState* p)
Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
ts->sym->codegen(Type::sir);
DtoResolveStruct(ts->sym);
return ts->sym->ir.irAggr->getDefaultInit();
}
@@ -1186,7 +1186,7 @@ LLConstant* CastExp::toConstElem(IRState* p)
else if (tb->ty == Tpointer && e1->op == TOKvar) {
VarDeclaration *vd = static_cast<VarExp*>(e1)->var->isVarDeclaration();
assert(vd);
vd->codegen(Type::sir);
DtoResolveVariable(vd);
LLConstant *value = vd->ir.irGlobal ? isaConstant(vd->ir.irGlobal->value) : 0;
if (!value)
goto Lerr;
@@ -1355,7 +1355,7 @@ DValue* AddrExp::toElem(IRState* p)
//Logger::println("FuncDeclaration");
FuncDeclaration* fd = fv->func;
assert(fd);
fd->codegen(Type::sir);
DtoResolveFunction(fd);
return new DFuncValue(fd, fd->ir.irFunc->func);
}
else if (v->isIm()) {
@@ -1407,7 +1407,7 @@ LLConstant* AddrExp::toConstElem(IRState* p)
VarDeclaration* vd = vexp->var->isVarDeclaration();
assert(vd);
assert(vd->type->toBasetype()->ty == Tsarray);
vd->codegen(Type::sir);
DtoResolveVariable(vd);
assert(vd->ir.irGlobal);
// get index
@@ -1632,7 +1632,6 @@ DValue* DotVarExp::toElem(IRState* p)
}
else
{
fdecl->codegen(Type::sir);
funcval = fdecl->ir.irFunc->func;
}
assert(funcval);
@@ -2123,7 +2122,7 @@ DValue* NewExp::toElem(IRState* p)
if (allocator)
{
// custom allocator
allocator->codegen(Type::sir);
DtoResolveDsymbol(allocator);
DFuncValue dfn(allocator, allocator->ir.irFunc->func);
DValue* res = DtoCallFunction(loc, NULL, &dfn, newargs);
mem = DtoBitCast(res->getRVal(), DtoType(ntype->pointerTo()), ".newstruct_custom");
@@ -2139,7 +2138,7 @@ DValue* NewExp::toElem(IRState* p)
}
else {
assert(ts->sym);
ts->sym->codegen(Type::sir);
DtoResolveStruct(ts->sym);
DtoAggrCopy(mem, ts->sym->ir.irAggr->getInitSymbol());
}
if (ts->sym->isNested() && ts->sym->vthis)
@@ -2150,7 +2149,7 @@ DValue* NewExp::toElem(IRState* p)
{
Logger::println("Calling constructor");
assert(arguments != NULL);
member->codegen(Type::sir);
DtoResolveDsymbol(member);
DFuncValue dfn(member, member->ir.irFunc->func, mem);
DtoCallFunction(loc, ts, &dfn, arguments);
}
@@ -2313,7 +2312,7 @@ DValue* AssertExp::toElem(IRState* p)
(invdecl = static_cast<TypeStruct*>(condty->nextOf())->sym->inv) != NULL)
{
Logger::print("calling struct invariant");
static_cast<TypeStruct*>(condty->nextOf())->sym->codegen(Type::sir);
DtoResolveFunction(invdecl);
DFuncValue invfunc(invdecl, invdecl->ir.irFunc->func, cond->getRVal());
DtoCallFunction(loc, NULL, &invfunc, NULL);
}
@@ -2541,7 +2540,21 @@ DValue* DelegateExp::toElem(IRState* p)
llvm_unreachable("Delegate to interface method not implemented.");
else
{
func->codegen(Type::sir);
DtoResolveFunction(func);
// We need to actually codegen the function here, as literals are not
// added to the module member list.
if (func->semanticRun == PASSsemantic3done)
{
Dsymbol *owner = func->toParent();
while (!owner->isTemplateInstance() && owner->toParent())
owner = owner->toParent();
if (owner->isTemplateInstance() || owner == p->dmodule)
{
func->codegen(Type::sir);
}
}
castfptr = func->ir.irFunc->func;
}
@@ -2785,6 +2798,8 @@ DValue* FuncExp::toElem(IRState* p)
if (fd->isNested()) Logger::println("nested");
Logger::println("kind = %s", fd->kind());
// We need to actually codegen the function here, as literals are not added
// to the module member list.
fd->codegen(Type::sir);
assert(fd->ir.irFunc->func);
@@ -2852,6 +2867,8 @@ LLConstant* FuncExp::toConstElem(IRState* p)
return 0;
}
// We need to actually codegen the function here, as literals are not added
// to the module member list.
fd->codegen(Type::sir);
assert(fd->ir.irFunc->func);
@@ -2987,7 +3004,7 @@ DValue* StructLiteralExp::toElem(IRState* p)
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
assert(ts->sym);
ts->sym->codegen(Type::sir);
DtoResolveStruct(ts->sym);
LLValue* initsym = ts->sym->ir.irAggr->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
@@ -2997,7 +3014,7 @@ DValue* StructLiteralExp::toElem(IRState* p)
if (inProgressMemory) return new DVarValue(type, inProgressMemory);
// make sure the struct is fully resolved
sd->codegen(Type::sir);
DtoResolveStruct(sd);
// alloca a stack slot
inProgressMemory = DtoRawAlloca(DtoType(type), 0, ".structliteral");
@@ -3101,13 +3118,13 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p)
Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
ts->sym->codegen(Type::sir);
DtoResolveStruct(ts->sym);
return ts->sym->ir.irAggr->getDefaultInit();
}
// make sure the struct is resolved
sd->codegen(Type::sir);
DtoResolveStruct(sd);
std::map<VarDeclaration*, llvm::Constant*> varInits;
const size_t nexprs = elements->dim;
@@ -3129,8 +3146,7 @@ llvm::Constant* ClassReferenceExp::toConstElem(IRState *p)
LOG_SCOPE;
ClassDeclaration* origClass = originalClass();
origClass->codegen(Type::sir);
DtoResolveClass(origClass);
if (value->globalVar)
{

View File

@@ -294,22 +294,17 @@ LLValue* DtoDelegateEquals(TOK op, LLValue* lhs, LLValue* rhs)
LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
{
const bool mustDefine = mustDefineSymbol(sym);
// global/static variable
if (VarDeclaration* vd = sym->isVarDeclaration())
{
if (mustDefine)
{
IF_LOG Logger::println("Variable %savailable externally: %s",
(vd->availableExternally ? "" : "not "), vd->toChars());
}
IF_LOG Logger::println("Variable %savailable externally: %s",
(vd->availableExternally ? "" : "not "), vd->toChars());
// generated by inlining semantics run
if (vd->availableExternally && mustDefine)
if (vd->availableExternally)
return llvm::GlobalValue::AvailableExternallyLinkage;
// template
if (needsTemplateLinkage(sym))
if (DtoIsTemplateInstance(sym))
return templateLinkage;
// Currently, we have to consider all variables, even function-local
@@ -330,11 +325,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
}
else if (FuncDeclaration* fdecl = sym->isFuncDeclaration())
{
if (mustDefine)
{
IF_LOG Logger::println("Function %savailable externally: %s",
(fdecl->availableExternally ? "" : "not "), fdecl->toChars());
}
IF_LOG Logger::println("Function %savailable externally: %s",
(fdecl->availableExternally ? "" : "not "), fdecl->toChars());
assert(fdecl->type->ty == Tfunction);
TypeFunction* ft = static_cast<TypeFunction*>(fdecl->type);
@@ -347,7 +339,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
// available_externally. Naked functions are turned into module-level
// inline asm and are thus declaration-only as far as the LLVM IR level
// is concerned.
if (fdecl->availableExternally && mustDefine && !fdecl->naked)
if (fdecl->availableExternally && !fdecl->naked)
return llvm::GlobalValue::AvailableExternallyLinkage;
// array operations are always template linkage
@@ -357,7 +349,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
// template instances should have weak linkage
// but only if there's a body, and it's not naked
// otherwise we make it external
if (needsTemplateLinkage(fdecl) && fdecl->fbody && !fdecl->naked)
if (DtoIsTemplateInstance(fdecl) && fdecl->fbody && !fdecl->naked)
return templateLinkage;
// extern(C) functions are always external
@@ -375,16 +367,14 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
// class
else if (ClassDeclaration* cd = sym->isClassDeclaration())
{
if (mustDefine)
{
IF_LOG Logger::println("Class %savailable externally: %s",
(cd->availableExternally ? "" : "not "), vd->toChars());
}
IF_LOG Logger::println("Class %savailable externally: %s",
(cd->availableExternally ? "" : "not "), vd->toChars());
// generated by inlining semantics run
if (cd->availableExternally && mustDefine)
if (cd->availableExternally)
return llvm::GlobalValue::AvailableExternallyLinkage;
// template
if (needsTemplateLinkage(cd))
if (DtoIsTemplateInstance(cd))
return templateLinkage;
}
else
@@ -392,10 +382,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
llvm_unreachable("not global/function");
}
// If the function needs to be defined in the current module, check if it
// is a nested function and we can declare it as internal.
bool canInternalize = mustDefine;
// Check if sym is a nested function and we can declare it as internal.
//
// Nested naked functions and the implicitly generated __require/__ensure
// functions for in/out contracts cannot be internalized. The reason
// for the latter is that contract functions, despite being nested, can be
@@ -403,39 +391,28 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
// interface methods (where __require/__ensure are emitted to the module
// where the interface is declared, but an actual interface implementation
// can be in a completely different place).
if (canInternalize)
{
if (FuncDeclaration* fd = sym->isFuncDeclaration())
{
if ((fd->naked != 0) ||
(fd->ident == Id::require) || (fd->ident == Id::ensure))
{
canInternalize = false;
}
}
}
// Any symbol nested in a function that cannot be inlined can't be
// referenced directly from outside that function, so we can give
// such symbols internal linkage. This holds even if nested indirectly,
// such as member functions of aggregates nested in functions.
//
// Note: This must be checked after things like template member-ness or
// symbols nested in templates would get duplicated for each module,
// breaking things like
// ---
// int counter(T)() { static int i; return i++; }"
// ---
// if instances get emitted in multiple object files because they'd use
// different instances of 'i'.
// TODO: Check if we are giving away too much inlining potential due to
// canInline being overly conservative here.
if (canInternalize)
FuncDeclaration* fd = sym->isFuncDeclaration();
if (!fd || (!fd->naked && fd->ident != Id::require && fd->ident != Id::ensure))
{
// Any symbol nested in a function that cannot be inlined can't be
// referenced directly from outside that function, so we can give
// such symbols internal linkage. This holds even if nested indirectly,
// such as member functions of aggregates nested in functions.
//
// Note: This must be checked after things like template member-ness or
// symbols nested in templates would get duplicated for each module,
// breaking things like
// ---
// int counter(T)() { static int i; return i++; }"
// ---
// if instances get emitted in multiple object files because they'd use
// different instances of 'i'.
// TODO: Check if we are giving away too much inlining potential due to
// canInline being overly conservative here.
for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent)
{
FuncDeclaration *fd = parent->isFuncDeclaration();
if (fd && !fd->canInline(fd->needThis(), false, false))
FuncDeclaration *parentFd = parent->isFuncDeclaration();
if (parentFd && !parentFd->canInline(parentFd->needThis(), false, false))
{
// We also cannot internalize nested functions which are
// leaked to the outside via a templated return type, because
@@ -444,8 +421,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
// Since we can't easily determine if this is really the case
// here, just don't internalize it if the parent returns a
// template at all, to be safe.
TypeFunction* tf = static_cast<TypeFunction*>(fd->type);
if (!DtoIsTemplateInstance(tf->next->toDsymbol(fd->scope)))
TypeFunction* tf = static_cast<TypeFunction*>(parentFd->type);
if (!DtoIsTemplateInstance(tf->next->toDsymbol(parentFd->scope)))
return llvm::GlobalValue::InternalLinkage;
}
}
@@ -468,8 +445,8 @@ static bool isAvailableExternally(Dsymbol* sym)
llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym)
{
if (needsTemplateLinkage(sym)) {
if (isAvailableExternally(sym) && mustDefineSymbol(sym))
if (DtoIsTemplateInstance(sym)) {
if (isAvailableExternally(sym))
return llvm::GlobalValue::AvailableExternallyLinkage;
return templateLinkage;
}
@@ -479,9 +456,9 @@ llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym)
llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym)
{
if (needsTemplateLinkage(sym))
if (DtoIsTemplateInstance(sym))
return templateLinkage;
else if (isAvailableExternally(sym) && mustDefineSymbol(sym))
else if (isAvailableExternally(sym))
return llvm::GlobalValue::AvailableExternallyLinkage;
else
return llvm::GlobalValue::ExternalLinkage;

View File

@@ -17,7 +17,6 @@
struct TypeInfoDeclaration;
void DtoResolveTypeInfo(TypeInfoDeclaration* tid);
void DtoDeclareTypeInfo(TypeInfoDeclaration* tid);
void DtoConstInitTypeInfo(TypeInfoDeclaration* tid);
#endif

View File

@@ -282,40 +282,8 @@ int TypeClass::builtinTypeInfo()
// (wut?)
//////////////////////////////////////////////////////////////////////////////
void DtoResolveTypeInfo(TypeInfoDeclaration* tid);
void DtoDeclareTypeInfo(TypeInfoDeclaration* tid);
void TypeInfoDeclaration::codegen(Ir*)
static void emitTypeMetadata(TypeInfoDeclaration *tid)
{
DtoResolveTypeInfo(this);
}
void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
{
if (tid->ir.resolved) return;
tid->ir.resolved = true;
Logger::println("DtoResolveTypeInfo(%s)", tid->toChars());
LOG_SCOPE;
std::string mangle(tid->mangle());
IrGlobal* irg = new IrGlobal(tid);
irg->value = gIR->module->getGlobalVariable(mangle);
if (!irg->value) {
if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var
irg->type = Type::typeinfo->type->irtype->isClass()->getMemoryLLType();
else
irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars());
irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true,
TYPEINFO_LINKAGE_TYPE, NULL, mangle);
} else {
irg->type = irg->value->getType()->getContainedType(0);
}
tid->ir.irGlobal = irg;
// We don't want to generate metadata for non-concrete types (such as tuple
// types, slice types, typeof(expr), etc.), void and function types (without
// an indirection), as there must be a valid LLVM undef value of that type.
@@ -324,13 +292,14 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
Type* t = tid->tinfo->toBasetype();
if (t->ty < Terror && t->ty != Tvoid && t->ty != Tfunction && t->ty != Tident) {
// Add some metadata for use by optimization passes.
std::string metaname = std::string(TD_PREFIX) + mangle;
std::string metaname(TD_PREFIX);
metaname += tid->mangle();
llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname);
if (!meta) {
// Construct the fields
MDNodeField* mdVals[TD_NumFields];
mdVals[TD_TypeInfo] = llvm::cast<MDNodeField>(irg->value);
mdVals[TD_TypeInfo] = llvm::cast<MDNodeField>(tid->ir.irGlobal->value);
mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo));
// Construct the metadata and insert it into the module.
@@ -339,39 +308,59 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
llvm::makeArrayRef(mdVals, TD_NumFields)));
}
}
DtoDeclareTypeInfo(tid);
}
void DtoDeclareTypeInfo(TypeInfoDeclaration* tid)
void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
{
DtoResolveTypeInfo(tid);
if (tid->ir.resolved) return;
tid->ir.resolved = true;
if (tid->ir.declared) return;
tid->ir.declared = true;
// TypeInfo instances (except ClassInfo ones) are always emitted as weak
// symbols when they are used.
tid->codegen(Type::sir);
}
Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars());
void TypeInfoDeclaration::codegen(Ir*)
{
Logger::println("TypeInfoDeclaration::codegen(%s)", toPrettyChars());
LOG_SCOPE;
if (ir.defined) return;
ir.defined = true;
std::string mangled(mangle());
if (Logger::enabled())
{
std::string mangled(tid->mangle());
Logger::println("type = '%s'", tid->tinfo->toChars());
Logger::println("type = '%s'", tinfo->toChars());
Logger::println("typeinfo mangle: %s", mangled.c_str());
}
IrGlobal* irg = tid->ir.irGlobal;
assert(irg->value != NULL);
IrGlobal* irg = new IrGlobal(this);
ir.irGlobal = irg;
irg->value = gIR->module->getGlobalVariable(mangled);
if (irg->value) {
irg->type = irg->value->getType()->getContainedType(0);
assert(irg->type->isStructTy());
} else {
if (tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var
irg->type = Type::typeinfo->type->irtype->isClass()->getMemoryLLType();
else
irg->type = LLStructType::create(gIR->context(), toPrettyChars());
irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true,
llvm::GlobalValue::ExternalLinkage, NULL, mangled);
}
emitTypeMetadata(this);
// this is a declaration of a builtin __initZ var
if (tid->tinfo->builtinTypeInfo()) {
if (tinfo->builtinTypeInfo()) {
LLGlobalVariable* g = isaGlobalVar(irg->value);
g->setLinkage(llvm::GlobalValue::ExternalLinkage);
return;
}
// define custom typedef
tid->llvmDefine();
llvmDefine();
}
/* ========================================================================= */
@@ -613,7 +602,7 @@ void TypeInfoStructDeclaration::llvmDefine()
fatal();
}
sd->codegen(Type::sir);
DtoResolveStruct(sd);
IrAggr* iraggr = sd->ir.irAggr;
RTTIBuilder b(Type::typeinfostruct);
@@ -739,20 +728,31 @@ void TypeInfoStructDeclaration::llvmDefine()
/* ========================================================================= */
void TypeInfoClassDeclaration::codegen(Ir*i)
void TypeInfoClassDeclaration::codegen(Ir* p)
{
IrGlobal* irg = new IrGlobal(this);
// For classes, the TypeInfo is in fact a ClassInfo instance and emitted
// as a __ClassZ symbol. For interfaces, the __InterfaceZ symbol is
// referenced as "info" member in a (normal) TypeInfo_Interface instance.
IrGlobal *irg = new IrGlobal(this);
ir.irGlobal = irg;
assert(tinfo->ty == Tclass);
TypeClass *tc = static_cast<TypeClass *>(tinfo);
tc->sym->codegen(Type::sir); // make sure class is resolved
DtoResolveClass(tc->sym);
irg->value = tc->sym->ir.irAggr->getClassInfoSymbol();
irg->type = irg->value->getType()->getContainedType(0);
if (!tc->sym->isInterfaceDeclaration())
{
emitTypeMetadata(this);
}
}
void TypeInfoClassDeclaration::llvmDefine()
{
llvm_unreachable("TypeInfoClassDeclaration should not be called for D2");
llvm_unreachable("TypeInfoClassDeclaration::llvmDefine() should not be called, "
"as a custom Dsymbol::codegen() override is used");
}
/* ========================================================================= */
@@ -765,7 +765,7 @@ void TypeInfoInterfaceDeclaration::llvmDefine()
// make sure interface is resolved
assert(tinfo->ty == Tclass);
TypeClass *tc = static_cast<TypeClass *>(tinfo);
tc->sym->codegen(Type::sir);
DtoResolveClass(tc->sym);
RTTIBuilder b(Type::typeinfointerface);

View File

@@ -47,18 +47,3 @@ Ir::Ir()
: irs(NULL)
{
}
void Ir::addFunctionBody(IrFunction * f)
{
functionbodies.push_back(f);
}
void Ir::emitFunctionBodies()
{
while (!functionbodies.empty())
{
IrFunction* irf = functionbodies.front();
functionbodies.pop_front();
DtoDefineFunction(irf->decl);
}
}

View File

@@ -31,9 +31,6 @@ public:
void setState(IRState* p) { irs = p; }
IRState* getState() { return irs; }
void addFunctionBody(IrFunction* f);
void emitFunctionBodies();
private:
IRState* irs;

View File

@@ -61,10 +61,8 @@ LLGlobalVariable * IrAggr::getInitSymbol()
initname.append(aggrdecl->mangle());
initname.append("6__initZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
init = getOrCreateGlobal(aggrdecl->loc,
*gIR->module, init_type, true, _linkage, NULL, initname);
*gIR->module, init_type, true, llvm::GlobalValue::ExternalLinkage, NULL, initname);
// set alignment
init->setAlignment(type->alignsize());

View File

@@ -57,9 +57,9 @@ struct IrAggr
/// Builds the __vtblZ initializer constant lazily.
LLConstant* getVtblInit();
/// Create the __ClassZ symbol lazily.
/// Create the __ClassZ/__InterfaceZ symbol lazily.
LLGlobalVariable* getClassInfoSymbol();
/// Builds the __ClassZ initializer constant lazily.
/// Builds the __ClassZ/__InterfaceZ initializer constant lazily.
LLConstant* getClassInfoInit();
/// Create the __interfaceInfos symbol lazily.

View File

@@ -53,12 +53,10 @@ LLGlobalVariable * IrAggr::getVtblSymbol()
initname.append(aggrdecl->mangle());
initname.append("6__vtblZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl();
vtbl = getOrCreateGlobal(aggrdecl->loc,
*gIR->module, vtblTy, true, _linkage, NULL, initname);
*gIR->module, vtblTy, true, llvm::GlobalValue::ExternalLinkage, NULL, initname);
return vtbl;
}
@@ -79,8 +77,9 @@ LLGlobalVariable * IrAggr::getClassInfoSymbol()
else
initname.append("7__ClassZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
// The type is also ClassInfo for interfaces the actual TypeInfo for them
// is a TypeInfo_Interface instance that references __ClassZ in its "base"
// member.
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
DtoType(cinfo->type);
IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass();
@@ -88,7 +87,8 @@ LLGlobalVariable * IrAggr::getClassInfoSymbol()
// classinfos cannot be constants since they're used as locks for synchronized
classInfo = getOrCreateGlobal(aggrdecl->loc,
*gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname);
*gIR->module, tc->getMemoryLLType(), false,
llvm::GlobalValue::ExternalLinkage, NULL, initname);
// Generate some metadata on this ClassInfo if it's for a class.
ClassDeclaration* classdecl = aggrdecl->isClassDeclaration();
@@ -138,9 +138,8 @@ LLGlobalVariable * IrAggr::getInterfaceArraySymbol()
name.append(cd->mangle());
name.append("16__interfaceInfosZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
classInterfacesArray = getOrCreateGlobal(cd->loc, *gIR->module,
array_type, true, _linkage, NULL, name);
array_type, true, llvm::GlobalValue::ExternalLinkage, NULL, name);
return classInterfacesArray;
}
@@ -182,7 +181,7 @@ LLConstant * IrAggr::getVtblInit()
}
else
{
fd->codegen(Type::sir);
DtoResolveFunction(fd);
assert(fd->ir.irFunc && "invalid vtbl function");
c = fd->ir.irFunc->func;
if (cd->isFuncHidden(fd))
@@ -320,7 +319,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
assert((!fd->isAbstract() || fd->fbody) &&
"null symbol in interface implementation vtable");
fd->codegen(Type::sir);
DtoResolveFunction(fd);
assert(fd->ir.irFunc && "invalid vtbl function");
LLFunction *fn = fd->ir.irFunc->func;
@@ -380,9 +379,6 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
// build the vtbl constant
llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false);
// create the global variable to hold it
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
std::string mangle("_D");
mangle.append(cd->mangle());
mangle.append("11__interface");
@@ -393,7 +389,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
*gIR->module,
vtbl_constant->getType(),
true,
_linkage,
llvm::GlobalValue::ExternalLinkage,
vtbl_constant,
mangle
);

View File

@@ -34,7 +34,7 @@ IRLandingPadCatchInfo::IRLandingPadCatchInfo(Catch* catchstmt_, llvm::BasicBlock
assert(catchStmt->type);
catchType = catchStmt->type->toBasetype()->isClassHandle();
assert(catchType);
catchType->codegen(Type::sir);
DtoResolveClass(catchType);
if (catchStmt->var) {
if (!catchStmt->var->nestedrefs.dim) {