Skip to content

Commit

Permalink
Use Module::members -> Dsymbol::codegen to define symbols.
Browse files Browse the repository at this point in the history
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. ldc-developers#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 ldc-developers#454.
  • Loading branch information
dnadlinger committed Oct 13, 2013
1 parent b556ad9 commit 787c147
Show file tree
Hide file tree
Showing 22 changed files with 437 additions and 515 deletions.
8 changes: 7 additions & 1 deletion dmd2/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down Expand Up @@ -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
Expand Down
4 changes: 0 additions & 4 deletions dmd2/func.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 0 additions & 8 deletions gen/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}

Expand Down
81 changes: 18 additions & 63 deletions gen/classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,21 @@

void DtoResolveClass(ClassDeclaration* cd)
{
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();
if (bc)
{
bc->base->codegen(Type::sir);
}
DtoResolveClass(bc->base);
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 type exists
DtoType(cd->type);

Expand All @@ -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
Expand All @@ -87,51 +79,14 @@ 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());
}
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp)
{
// resolve type
tc->sym->codegen(Type::sir);
DtoResolveClass(tc->sym);

// allocate
LLValue* mem;
Expand All @@ -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");
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;

Expand Down Expand Up @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -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 :/
Expand Down Expand Up @@ -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())));
}

Expand Down
Loading

0 comments on commit 787c147

Please sign in to comment.