mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-15 04:13:14 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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())));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
50
gen/toir.cpp
50
gen/toir.cpp
@@ -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)
|
||||
{
|
||||
|
||||
103
gen/tollvm.cpp
103
gen/tollvm.cpp
@@ -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;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
struct TypeInfoDeclaration;
|
||||
void DtoResolveTypeInfo(TypeInfoDeclaration* tid);
|
||||
void DtoDeclareTypeInfo(TypeInfoDeclaration* tid);
|
||||
void DtoConstInitTypeInfo(TypeInfoDeclaration* tid);
|
||||
|
||||
#endif
|
||||
|
||||
110
gen/typinf.cpp
110
gen/typinf.cpp
@@ -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);
|
||||
|
||||
|
||||
15
ir/ir.cpp
15
ir/ir.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
3
ir/ir.h
3
ir/ir.h
@@ -31,9 +31,6 @@ public:
|
||||
void setState(IRState* p) { irs = p; }
|
||||
IRState* getState() { return irs; }
|
||||
|
||||
void addFunctionBody(IrFunction* f);
|
||||
void emitFunctionBodies();
|
||||
|
||||
private:
|
||||
IRState* irs;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user