ldc/gen/classes.cpp
Tomas Lindquist Olsen fc480b7fd8 SWITCHED TO LLVM 2.5 !
Applied patch from ticket #129 to compile against latest LLVM. Thanks Frits van Bommel.

Fixed implicit return by asm block at the end of a function on x86-32. Other architectures will produce an error at the moment. Adding support for new targets is fairly simple.

Fixed return calling convention for complex numbers, ST and ST(1) were switched around.

Added some testcases.

I've run a dstress test and there are no regressions. However, the runtime does not seem to compile with symbolic debug information. -O3 -release -inline works well and is what I used for the dstress run. Tango does not compile, a small workaround is needed in tango.io.digest.Digest.Digest.hexDigest. See ticket #206 .
2009-02-08 05:26:54 +01:00

1653 lines
49 KiB
C++

#include "gen/llvm.h"
#include "mtype.h"
#include "aggregate.h"
#include "init.h"
#include "declaration.h"
#include "gen/irstate.h"
#include "gen/tollvm.h"
#include "gen/llvmhelpers.h"
#include "gen/arrays.h"
#include "gen/logger.h"
#include "gen/classes.h"
#include "gen/structs.h"
#include "gen/functions.h"
#include "gen/runtime.h"
#include "gen/dvalue.h"
#include "ir/irstruct.h"
//////////////////////////////////////////////////////////////////////////////////////////
// adds the base interfaces of b and the given iri to IrStruct's interfaceMap
static void add_base_interfaces(IrStruct* to, IrInterface* iri, BaseClass* b)
{
for (unsigned j = 0; j < b->baseInterfaces_dim; j++)
{
BaseClass *bc = &b->baseInterfaces[j];
// add to map
if (to->interfaceMap.find(bc->base) == to->interfaceMap.end())
{
to->interfaceMap.insert(std::make_pair(bc->base, iri));
}
// add base interfaces
add_base_interfaces(to, iri, bc);
}
}
// adds interface b to target, if newinstance != 0, then target must provide all
// functions required to implement b (it reimplements b)
static void add_interface(ClassDeclaration* target, BaseClass* b, int newinstance)
{
Logger::println("adding interface: %s", b->base->toChars());
LOG_SCOPE;
InterfaceDeclaration* inter = b->base->isInterfaceDeclaration();
DtoResolveClass(inter);
assert(inter);
IrStruct* irstruct = target->ir.irStruct;
assert(irstruct);
// add interface to map/list
// if it's already inserted in the map, it's because another interface has it as baseclass
// but if it appears here, it's because we're reimplementing it, so we overwrite the IrInterface entry
IrInterface* iri;
bool overwrite = false;
if (irstruct->interfaceMap.find(inter) != irstruct->interfaceMap.end())
{
overwrite = true;
}
iri = new IrInterface(b);
// add to map
if (overwrite)
irstruct->interfaceMap[b->base] = iri;
else
irstruct->interfaceMap.insert(std::make_pair(b->base, iri));
// add to ordered list
irstruct->interfaceVec.push_back(iri);
// add to classinfo interfaces
if (newinstance)
irstruct->classInfoInterfaces.push_back(iri);
// recursively assign this iri to all base interfaces
add_base_interfaces(irstruct, iri, b);
// build the interface vtable
b->fillVtbl(target, &iri->vtblDecls, newinstance);
// add the vtable type
assert(inter->type->ir.type);
irstruct->types.push_back( inter->type->ir.type->get() );
// set and increment index
iri->index = irstruct->index++;
}
//////////////////////////////////////////////////////////////////////////////////////////
static void add_class_data(ClassDeclaration* target, ClassDeclaration* cd)
{
Logger::println("Adding data from class: %s", cd->toChars());
LOG_SCOPE;
// recurse into baseClasses
if (cd->baseClass)
{
add_class_data(target, cd->baseClass);
//offset = baseClass->structsize;
}
// add members
Array* arr = cd->members;
for (int k=0; k < arr->dim; k++) {
Dsymbol* s = (Dsymbol*)arr->data[k];
s->toObjFile(0);
}
// add interfaces
if (cd->vtblInterfaces)
{
Logger::println("num vtbl interfaces: %u", cd->vtblInterfaces->dim);
for (int i = 0; i < cd->vtblInterfaces->dim; i++)
{
BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i];
assert(b);
// create new instances only for explicitly derived interfaces
add_interface(target, b, (cd == target));
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
static void DtoResolveInterface(InterfaceDeclaration* cd)
{
if (cd->ir.resolved) return;
cd->ir.resolved = true;
Logger::println("DtoResolveInterface(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
// get the TypeClass
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
// create the IrStruct, we need somewhere to store the classInfo
assert(!cd->ir.irStruct);
IrStruct* irstruct = new IrStruct(cd);
cd->ir.irStruct = irstruct;
// handle base interfaces
if (cd->baseclasses.dim)
{
Logger::println("num baseclasses: %u", cd->baseclasses.dim);
LOG_SCOPE;
for (int i=0; i<cd->baseclasses.dim; i++)
{
BaseClass* bc = (BaseClass*)cd->baseclasses.data[i];
Logger::println("baseclass %d: %s", i, bc->base->toChars());
InterfaceDeclaration* id = bc->base->isInterfaceDeclaration();
assert(id);
DtoResolveInterface(id);
// add to interfaceInfos
IrInterface* iri = new IrInterface(bc);
irstruct->interfaceVec.push_back(iri);
irstruct->classInfoInterfaces.push_back(iri);
}
}
// create the type
const LLType* t = LLArrayType::get(getVoidPtrType(), cd->vtbl.dim);
assert(!ts->ir.type);
ts->ir.type = new LLPATypeHolder(getPtrToType(t));
// request declaration
gIR->declareList.push_back(cd);
// handle members
// like "nested" interfaces
Array* arr = cd->members;
for (int k=0; k < arr->dim; k++) {
Dsymbol* s = (Dsymbol*)arr->data[k];
s->toObjFile(0);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// FIXME: this needs to be cleaned up
void DtoResolveClass(ClassDeclaration* cd)
{
if (InterfaceDeclaration* id = cd->isInterfaceDeclaration())
{
DtoResolveInterface(id);
return;
}
if (cd->ir.resolved) return;
cd->ir.resolved = true;
Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
//printf("resolve class: %s\n", cd->toPrettyChars());
// get the TypeClass
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
// create the IrStruct
assert(!cd->ir.irStruct);
IrStruct* irstruct = new IrStruct(cd);
cd->ir.irStruct = irstruct;
// create the type
ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get());
// if it just a forward declaration?
if (cd->sizeok != 1)
{
// just name the type
gIR->module->addTypeName(cd->mangle(), ts->ir.type->get());
return;
}
// resolve the base class
if (cd->baseClass) {
DtoResolveClass(cd->baseClass);
}
// push state
gIR->structs.push_back(irstruct);
// add vtable
irstruct->types.push_back(getPtrToType(irstruct->vtblTy.get()));
irstruct->index++;
// add monitor
irstruct->types.push_back(getVoidPtrType());
irstruct->index++;
// add class data fields and interface vtables recursively
add_class_data(cd, cd);
// check if errors occured while building interface vtables
if (global.errors)
fatal();
// create type
assert(irstruct->index == irstruct->types.size());
const LLType* structtype = irstruct->build();
// refine abstract types for stuff like: class C {C next;}
llvm::PATypeHolder* spa = ts->ir.type;
llvm::cast<llvm::OpaqueType>(spa->get())->refineAbstractTypeTo(structtype);
structtype = isaStruct(spa->get());
// name the type
gIR->module->addTypeName(cd->mangle(), ts->ir.type->get());
// refine vtable type
// void*[vtbl.dim]
llvm::cast<llvm::OpaqueType>(irstruct->vtblTy.get())->refineAbstractTypeTo(LLArrayType::get(getVoidPtrType(), cd->vtbl.dim));
// log
// if (Logger::enabled())
// Logger::cout() << "final class type: " << *ts->ir.type->get() << '\n';
// pop state
gIR->structs.pop_back();
// queue declare
gIR->declareList.push_back(cd);
}
//////////////////////////////////////////////////////////////////////////////////////////
static void DtoDeclareInterface(InterfaceDeclaration* cd)
{
if (cd->ir.declared) return;
cd->ir.declared = true;
Logger::println("DtoDeclareInterface(%s): %s", cd->toPrettyChars(), cd->locToChars());
LOG_SCOPE;
assert(cd->ir.irStruct);
IrStruct* irstruct = cd->ir.irStruct;
// get interface info type
const llvm::StructType* infoTy = DtoInterfaceInfoType();
// interface info array
if (!irstruct->interfaceVec.empty()) {
// symbol name
std::string nam = "_D";
nam.append(cd->mangle());
nam.append("16__interfaceInfosZ");
llvm::GlobalValue::LinkageTypes linkage = DtoLinkage(cd);
// resolve array type
const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size());
// declare global
irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, linkage, NULL, nam, gIR->module);
// do each interface info
unsigned idx = 0;
size_t n = irstruct->interfaceVec.size();
for (size_t i=0; i < n; i++)
{
IrInterface* iri = irstruct->interfaceVec[i];
ClassDeclaration* id = iri->decl;
// always create interfaceinfos
LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)};
iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2);
idx++;
}
}
// declare the classinfo
DtoDeclareClassInfo(cd);
// request const init
gIR->constInitList.push_back(cd);
// emit typeinfo and request definition
if (mustDefineSymbol(cd))
{
gIR->defineList.push_back(cd);
DtoTypeInfoOf(cd->type, false);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// FIXME: this needs to be cleaned up
void DtoDeclareClass(ClassDeclaration* cd)
{
if (InterfaceDeclaration* id = cd->isInterfaceDeclaration())
{
DtoDeclareInterface(id);
return;
}
if (cd->ir.declared) return;
cd->ir.declared = true;
Logger::println("DtoDeclareClass(%s): %s", cd->toPrettyChars(), cd->locToChars());
LOG_SCOPE;
//printf("declare class: %s\n", cd->toPrettyChars());
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
assert(cd->ir.irStruct);
IrStruct* irstruct = cd->ir.irStruct;
gIR->structs.push_back(irstruct);
bool needs_definition = false;
if (mustDefineSymbol(cd)) {
needs_definition = true;
}
llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(cd);
// create vtbl symbol
std::string varname("_D");
varname.append(cd->mangle());
varname.append("6__vtblZ");
irstruct->vtbl = new llvm::GlobalVariable(irstruct->vtblInitTy.get(), true, _linkage, 0, varname, gIR->module);
// get interface info type
const llvm::StructType* infoTy = DtoInterfaceInfoType();
// interface info array
if (!irstruct->interfaceVec.empty()) {
// symbol name
std::string nam = "_D";
nam.append(cd->mangle());
nam.append("16__interfaceInfosZ");
// resolve array type
const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size());
// declare global
irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, _linkage, NULL, nam, gIR->module);
}
// DMD gives abstract classes a full ClassInfo, so we do it as well
// interface vtables
unsigned idx = 0;
for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i)
{
IrInterface* iri = *i;
ClassDeclaration* id = iri->decl;
std::string nam("_D");
nam.append(cd->mangle());
nam.append("11__interface");
nam.append(id->mangle());
nam.append("6__vtblZ");
iri->vtbl = new llvm::GlobalVariable(iri->vtblInitTy.get(), true, _linkage, 0, nam, gIR->module);
// always set the interface info as it's need as the first vtbl entry
LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)};
iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2);
idx++;
}
// initZ init
std::string initname("_D");
initname.append(cd->mangle());
initname.append("6__initZ");
// initZ global
llvm::GlobalVariable* initvar = new llvm::GlobalVariable(irstruct->initOpaque.get(), true, _linkage, NULL, initname, gIR->module);
irstruct->init = initvar;
gIR->structs.pop_back();
// request const init
gIR->constInitList.push_back(cd);
// define ? (set initializers)
if (needs_definition)
gIR->defineList.push_back(cd);
// classinfo
DtoDeclareClassInfo(cd);
// do typeinfo ?
if (needs_definition)
DtoTypeInfoOf(cd->type, false);
}
//////////////////////////////////////////////////////////////////////////////
// adds data fields and interface vtables to the constant initializer of class cd
static size_t init_class_initializer(std::vector<LLConstant*>& inits, ClassDeclaration* target, ClassDeclaration* cd, size_t offsetbegin)
{
// first do baseclasses
if (cd->baseClass)
{
offsetbegin = init_class_initializer(inits, target, cd->baseClass, offsetbegin);
}
Logger::println("adding data of %s to %s starting at %lu", cd->toChars(), target->toChars(), offsetbegin);
LOG_SCOPE;
// add default fields
VarDeclaration** fields = (VarDeclaration**)cd->fields.data;
size_t nfields = cd->fields.dim;
std::vector<VarDeclaration*> defVars;
defVars.reserve(nfields);
size_t lastoffset = offsetbegin;
size_t lastsize = 0;
// find fields that contribute to default
for (size_t i=0; i<nfields; i++)
{
VarDeclaration* var = fields[i];
// only add vars that don't overlap
size_t offset = var->offset;
size_t size = var->type->size();
if (offset >= lastoffset+lastsize)
{
Logger::println(" added %s", var->toChars());
lastoffset = offset;
lastsize = size;
defVars.push_back(var);
}
else
{
Logger::println(" skipped %s at offset %u, current pos is %lu", var->toChars(), var->offset, lastoffset+lastsize);
}
}
// reset offsets, we're going from beginning again
lastoffset = offsetbegin;
lastsize = 0;
// go through the default vars and build the default constant initializer
// adding zeros along the way to live up to alignment expectations
size_t nvars = defVars.size();
for (size_t i=0; i<nvars; i++)
{
VarDeclaration* var = defVars[i];
Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset);
// get offset and size
size_t offset = var->offset;
size_t size = var->type->size();
// is there space in between last last offset and this one?
// if so, fill it with zeros
if (offset > lastoffset+lastsize)
{
size_t pos = lastoffset + lastsize;
addZeros(inits, pos, offset);
}
// add the field
// and build its constant initializer lazily
if (!var->ir.irField->constInit)
var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init);
inits.push_back(var->ir.irField->constInit);
lastoffset = offset;
lastsize = var->type->size();
}
// if it's a class, and it implements interfaces, add the vtables - as found in the target class!
IrStruct* irstruct = target->ir.irStruct;
size_t nvtbls = cd->vtblInterfaces->dim;
for(size_t i=0; i<nvtbls; i++)
{
BaseClass* bc = (BaseClass*)cd->vtblInterfaces->data[i];
IrStruct::InterfaceMap::iterator iter = irstruct->interfaceMap.find(bc->base);
assert(iter != irstruct->interfaceMap.end());
IrInterface* iri = iter->second;
if (iri->vtbl)
inits.push_back(iri->vtbl);
else // abstract impl
inits.push_back(getNullPtr(getVoidPtrType()));
lastoffset += lastsize;
lastsize = PTRSIZE;
}
// return next offset
return lastoffset + lastsize;
}
//////////////////////////////////////////////////////////////////////////////
// build the vtable initializer for class cd
static void init_class_vtbl_initializer(ClassDeclaration* cd)
{
// generate vtable initializer
std::vector<LLConstant*> sinits(cd->vtbl.dim, NULL);
IrStruct* irstruct = cd->ir.irStruct;
assert(cd->vtbl.dim > 1);
// first entry always classinfo
assert(irstruct->classInfo);
sinits[0] = DtoBitCast(irstruct->classInfo, DtoType(ClassDeclaration::classinfo->type));
// add virtual functions
for (int k=1; k < cd->vtbl.dim; k++)
{
Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k];
assert(dsym);
// Logger::println("vtbl[%d] = %s", k, dsym->toChars());
FuncDeclaration* fd = dsym->isFuncDeclaration();
assert(fd);
// if function is abstract,
// or class is abstract, and func has no body,
// emit a null vtbl entry
if (fd->isAbstract() || (cd->isAbstract() && !fd->fbody))
{
sinits[k] = getNullPtr(getVoidPtrType());
}
else
{
DtoForceDeclareDsymbol(fd);
assert(fd->ir.irFunc->func);
sinits[k] = fd->ir.irFunc->func;
}
// if (Logger::enabled())
// Logger::cout() << "vtbl[" << k << "] = " << *sinits[k] << std::endl;
}
irstruct->constVtbl = LLConstantStruct::get(sinits);
// refine type
llvm::cast<llvm::OpaqueType>(irstruct->vtblInitTy.get())->refineAbstractTypeTo(irstruct->constVtbl->getType());
// if (Logger::enabled())
// Logger::cout() << "vtbl initializer: " << *irstruct->constVtbl << std::endl;
}
//////////////////////////////////////////////////////////////////////////////
static void init_class_interface_vtbl_initializers(ClassDeclaration* cd)
{
IrStruct* irstruct = cd->ir.irStruct;
// don't do anything if list is empty
if (irstruct->interfaceVec.empty())
return;
std::vector<LLConstant*> inits;
std::vector<LLConstant*> infoInits(3);
// go through each interface
size_t ninter = irstruct->interfaceVec.size();
for (size_t i=0; i<ninter; i++)
{
IrInterface* iri = irstruct->interfaceVec[i];
Logger::println("interface %s", iri->decl->toChars());
// build vtable intializer for this interface implementation
Array& arr = iri->vtblDecls;
size_t narr = arr.dim;
if (narr > 0)
{
inits.resize(narr, NULL);
// first is always the interface info
assert(iri->info);
inits[0] = iri->info;
// build vtable
for (size_t j=1; j < narr; j++)
{
Dsymbol* dsym = (Dsymbol*)arr.data[j];
if (!dsym)
{
inits[j] = getNullPtr(getVoidPtrType());
continue;
}
//Logger::println("ivtbl[%d] = %s", j, dsym->toChars());
// must all be functions
FuncDeclaration* fd = dsym->isFuncDeclaration();
assert(fd);
if (fd->isAbstract())
inits[j] = getNullPtr(getVoidPtrType());
else
{
DtoForceDeclareDsymbol(fd);
assert(fd->ir.irFunc->func);
inits[j] = fd->ir.irFunc->func;
}
//if (Logger::enabled())
// Logger::cout() << "ivtbl[" << j << "] = " << *inits[j] << std::endl;
}
// build the constant
iri->vtblInit = LLConstantStruct::get(inits);
}
// build the interface info for ClassInfo
// generate interface info initializer
DtoForceDeclareDsymbol(iri->decl);
// classinfo
IrStruct* iris = iri->decl->ir.irStruct;
assert(iris);
assert(iris->classInfo);
infoInits[0] = DtoBitCast(iris->classInfo, DtoType(ClassDeclaration::classinfo->type));
// vtbl
LLConstant* c;
if (iri->vtbl)
c = llvm::ConstantExpr::getBitCast(iri->vtbl, getPtrToType(getVoidPtrType()));
else
c = getNullPtr(getPtrToType(getVoidPtrType()));
infoInits[1] = DtoConstSlice(DtoConstSize_t(narr), c);
// offset
size_t ioff;
if (iri->index == 0)
ioff = 0;
else
ioff = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(iri->index);
Logger::println("DMD interface offset: %d, LLVM interface offset: %lu", iri->base->offset, ioff);
assert(iri->base->offset == ioff);
infoInits[2] = DtoConstUint(ioff);
// create interface info initializer constant
iri->infoInit = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(infoInits));
}
}
//////////////////////////////////////////////////////////////////////////////
static void DtoConstInitInterface(InterfaceDeclaration* cd)
{
if (cd->ir.initialized) return;
cd->ir.initialized = true;
Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
init_class_interface_vtbl_initializers(cd);
}
//////////////////////////////////////////////////////////////////////////////
void DtoConstInitClass(ClassDeclaration* cd)
{
if (InterfaceDeclaration* it = cd->isInterfaceDeclaration())
{
DtoConstInitInterface(it);
return;
}
if (cd->ir.initialized) return;
cd->ir.initialized = true;
Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
assert(!cd->isInterfaceDeclaration());
// make sure the baseclass is const initialized
if (cd->baseClass)
DtoForceConstInitDsymbol(cd->baseClass);
// get IrStruct
IrStruct* irstruct = cd->ir.irStruct;
gIR->structs.push_back(irstruct);
// get types
TypeClass* tc = (TypeClass*)cd->type;
const llvm::StructType* structtype = isaStruct(tc->ir.type->get());
assert(structtype);
const llvm::ArrayType* vtbltype = isaArray(irstruct->vtblTy.get());
assert(vtbltype);
// build initializer list
std::vector<LLConstant*> inits;
inits.reserve(irstruct->varDecls.size());
// vtable is always first
assert(irstruct->vtbl != 0);
inits.push_back(irstruct->vtbl);
// then comes monitor
inits.push_back(LLConstant::getNullValue(getVoidPtrType()));
// recursively do data and interface vtables
init_class_initializer(inits, cd, cd, 2 * PTRSIZE);
// build vtable initializer
init_class_vtbl_initializer(cd);
// build interface vtables
init_class_interface_vtbl_initializers(cd);
// build constant from inits
assert(!irstruct->constInit);
irstruct->constInit = LLConstantStruct::get(inits); // classes are never packed
// refine __initZ global type to the one of the initializer
llvm::cast<llvm::OpaqueType>(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType());
// if (Logger::enabled())
// {
// Logger::cout() << "class " << cd->toChars() << std::endl;
// Logger::cout() << "type " << *cd->type->ir.type->get() << std::endl;
// Logger::cout() << "initializer " << *irstruct->constInit << std::endl;
// }
gIR->structs.pop_back();
}
//////////////////////////////////////////////////////////////////////////////////////////
static void DefineInterfaceInfos(IrStruct* irstruct)
{
// always do interface info array when possible
std::vector<LLConstant*> infoInits;
size_t n = irstruct->interfaceVec.size();
infoInits.reserve(n);
for (size_t i=0; i < n; i++)
{
IrInterface* iri = irstruct->interfaceVec[i];
assert(iri->infoInit);
infoInits.push_back(iri->infoInit);
}
// set initializer
if (!infoInits.empty())
{
const LLArrayType* arrty = LLArrayType::get(infoInits[0]->getType(), infoInits.size());
LLConstant* arrInit = llvm::ConstantArray::get(arrty, infoInits);
irstruct->interfaceInfos->setInitializer(arrInit);
}
else
{
assert(irstruct->interfaceInfos == NULL);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
static void DtoDefineInterface(InterfaceDeclaration* cd)
{
if (cd->ir.defined) return;
cd->ir.defined = true;
Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
// defined interface infos
DefineInterfaceInfos(cd->ir.irStruct);
// define the classinfo
if (mustDefineSymbol(cd))
{
DtoDefineClassInfo(cd);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// FIXME: clean this up
void DtoDefineClass(ClassDeclaration* cd)
{
if (InterfaceDeclaration* id = cd->isInterfaceDeclaration())
{
DtoDefineInterface(id);
return;
}
if (cd->ir.defined) return;
cd->ir.defined = true;
Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
// get the struct (class) type
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
IrStruct* irstruct = cd->ir.irStruct;
assert(mustDefineSymbol(cd));
// sanity check
assert(irstruct->init);
assert(irstruct->constInit);
assert(irstruct->vtbl);
assert(irstruct->constVtbl);
// if (Logger::enabled())
// {
// Logger::cout() << "initZ: " << *irstruct->init << std::endl;
// Logger::cout() << "cinitZ: " << *irstruct->constInit << std::endl;
// Logger::cout() << "vtblZ: " << *irstruct->vtbl << std::endl;
// Logger::cout() << "cvtblZ: " << *irstruct->constVtbl << std::endl;
// }
// set initializers
irstruct->init->setInitializer(irstruct->constInit);
irstruct->vtbl->setInitializer(irstruct->constVtbl);
// initialize interface vtables
size_t n = irstruct->interfaceVec.size();
for (size_t i=0; i<n; i++)
{
IrInterface* iri = irstruct->interfaceVec[i];
Logger::println("interface %s", iri->base->base->toChars());
assert(iri->vtblInit);
// refine the init type
llvm::cast<llvm::OpaqueType>(iri->vtblInitTy.get())->refineAbstractTypeTo(iri->vtblInit->getType());
// apply initializer
assert(iri->vtbl);
iri->vtbl->setInitializer(iri->vtblInit);
}
DefineInterfaceInfos(irstruct);
// generate classinfo
DtoDefineClassInfo(cd);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp)
{
// resolve type
DtoForceDeclareDsymbol(tc->sym);
// allocate
LLValue* mem;
if (newexp->onstack)
{
mem = DtoAlloca(DtoType(tc)->getContainedType(0), ".newclass_alloca");
}
// custom allocator
else if (newexp->allocator)
{
DtoForceDeclareDsymbol(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");
}
// default allocator
else
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocclass");
LLConstant* ci = DtoBitCast(tc->sym->ir.irStruct->classInfo, DtoType(ClassDeclaration::classinfo->type));
mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc")->get();
mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc");
}
// init
DtoInitClass(tc, mem);
// init inner-class outer reference
if (newexp->thisexp)
{
Logger::println("Resolving outer class");
LOG_SCOPE;
DValue* thisval = newexp->thisexp->toElem(gIR);
size_t idx = tc->sym->vthis->ir.irField->index;
LLValue* src = thisval->getRVal();
LLValue* dst = DtoGEPi(mem,0,idx,"tmp");
if (Logger::enabled())
Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
DtoStore(src, dst);
}
// set the context for nested classes
else if (tc->sym->isNested() && tc->sym->vthis)
{
Logger::println("Resolving nested context");
LOG_SCOPE;
// get context
LLValue* nest = DtoNestedContext(loc, tc->sym);
// store into right location
size_t idx = tc->sym->vthis->ir.irField->index;
LLValue* gep = DtoGEPi(mem,0,idx,"tmp");
DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep);
}
// call constructor
if (newexp->member)
{
assert(newexp->arguments != NULL);
DtoForceDeclareDsymbol(newexp->member);
DFuncValue dfn(newexp->member, newexp->member->ir.irFunc->func, mem);
return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments);
}
// return default constructed class
return new DImValue(tc, mem);
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoInitClass(TypeClass* tc, LLValue* dst)
{
DtoForceConstInitDsymbol(tc->sym);
size_t presz = 2*getTypePaddedSize(DtoSize_t());
uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz;
// set vtable field seperately, this might give better optimization
assert(tc->sym->ir.irStruct->vtbl);
LLValue* tmp = DtoGEPi(dst,0,0,"vtbl");
LLValue* val = DtoBitCast(tc->sym->ir.irStruct->vtbl, tmp->getType()->getContainedType(0));
DtoStore(val, tmp);
// monitor always defaults to zero
tmp = DtoGEPi(dst,0,1,"monitor");
val = llvm::Constant::getNullValue(tmp->getType()->getContainedType(0));
DtoStore(val, tmp);
// done?
if (n == 0)
return;
// copy the rest from the static initializer
assert(tc->sym->ir.irStruct->init);
LLValue* dstarr = DtoGEPi(dst,0,2,"tmp");
LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->init,0,2,"tmp");
DtoMemCpy(dstarr, srcarr, DtoConstSize_t(n));
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoFinalizeClass(LLValue* inst)
{
// get runtime function
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_callfinalizer");
// build args
LLSmallVector<LLValue*,1> arg;
arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp"));
// call
gIR->CreateCallOrInvoke(fn, arg.begin(), arg.end(), "");
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoCastClass(DValue* val, Type* _to)
{
Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars());
LOG_SCOPE;
Type* to = _to->toBasetype();
// class -> pointer
if (to->ty == Tpointer) {
Logger::println("to pointer");
const LLType* tolltype = DtoType(_to);
LLValue* rval = DtoBitCast(val->getRVal(), tolltype);
return new DImValue(_to, rval);
}
// class -> bool
else if (to->ty == Tbool) {
Logger::println("to bool");
LLValue* llval = val->getRVal();
LLValue* zero = LLConstant::getNullValue(llval->getType());
return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero, "tmp"));
}
// must be class/interface
assert(to->ty == Tclass);
TypeClass* tc = (TypeClass*)to;
// from type
Type* from = val->getType()->toBasetype();
TypeClass* fc = (TypeClass*)from;
// x -> interface
if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) {
Logger::println("to interface");
// interface -> interface
if (fc->sym->isInterfaceDeclaration()) {
Logger::println("from interface");
return DtoDynamicCastInterface(val, _to);
}
// class -> interface - static cast
else if (it->isBaseOf(fc->sym,NULL)) {
Logger::println("static down cast");
// get the from class
ClassDeclaration* cd = fc->sym->isClassDeclaration();
DtoResolveClass(cd); // add this
IrStruct* irstruct = cd->ir.irStruct;
// find interface impl
IrStruct::InterfaceMapIter iriter = irstruct->interfaceMap.find(it);
assert(iriter != irstruct->interfaceMap.end());
IrInterface* iri = iriter->second;
// offset pointer
LLValue* v = val->getRVal();
v = DtoGEPi(v, 0, iri->index);
if (Logger::enabled())
{
Logger::cout() << "V = " << *v << std::endl;
Logger::cout() << "T = " << *DtoType(_to) << std::endl;
}
v = DtoBitCast(v, DtoType(_to));
// return r-value
return new DImValue(_to, v);
}
// class -> interface
else {
Logger::println("from object");
return DtoDynamicCastObject(val, _to);
}
}
// x -> class
else {
Logger::println("to class");
int poffset;
// interface -> class
if (fc->sym->isInterfaceDeclaration()) {
Logger::println("interface cast");
return DtoDynamicCastInterface(val, _to);
}
// class -> class - static down cast
else if (tc->sym->isBaseOf(fc->sym,NULL)) {
Logger::println("static down cast");
const LLType* tolltype = DtoType(_to);
LLValue* rval = DtoBitCast(val->getRVal(), tolltype);
return new DImValue(_to, rval);
}
// class -> class - dynamic up cast
else {
Logger::println("dynamic up cast");
return DtoDynamicCastObject(val, _to);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoDynamicCastObject(DValue* val, Type* _to)
{
// call:
// Object _d_dynamic_cast(Object o, ClassInfo c)
DtoForceDeclareDsymbol(ClassDeclaration::object);
DtoForceDeclareDsymbol(ClassDeclaration::classinfo);
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast");
const llvm::FunctionType* funcTy = func->getFunctionType();
std::vector<LLValue*> args;
// Object o
LLValue* obj = val->getRVal();
obj = DtoBitCast(obj, funcTy->getParamType(0));
assert(funcTy->getParamType(0) == obj->getType());
// ClassInfo c
TypeClass* to = (TypeClass*)_to->toBasetype();
DtoForceDeclareDsymbol(to->sym);
assert(to->sym->ir.irStruct->classInfo);
LLValue* cinfo = to->sym->ir.irStruct->classInfo;
// unfortunately this is needed as the implementation of object differs somehow from the declaration
// this could happen in user code as well :/
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
assert(funcTy->getParamType(1) == cinfo->getType());
// call it
LLValue* ret = gIR->CreateCallOrInvoke2(func, obj, cinfo, "tmp")->get();
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
return new DImValue(_to, ret);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoCastInterfaceToObject(DValue* val, Type* to)
{
// call:
// Object _d_toObject(void* p)
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject");
const llvm::FunctionType* funcTy = func->getFunctionType();
// void* p
LLValue* tmp = val->getRVal();
tmp = DtoBitCast(tmp, funcTy->getParamType(0));
// call it
LLValue* ret = gIR->CreateCallOrInvoke(func, tmp, "tmp")->get();
// cast return value
if (to != NULL)
ret = DtoBitCast(ret, DtoType(to));
else
to = ClassDeclaration::object->type;
return new DImValue(to, ret);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoDynamicCastInterface(DValue* val, Type* _to)
{
// call:
// Object _d_interface_cast(void* p, ClassInfo c)
DtoForceDeclareDsymbol(ClassDeclaration::object);
DtoForceDeclareDsymbol(ClassDeclaration::classinfo);
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_interface_cast");
const llvm::FunctionType* funcTy = func->getFunctionType();
std::vector<LLValue*> args;
// void* p
LLValue* ptr = val->getRVal();
ptr = DtoBitCast(ptr, funcTy->getParamType(0));
// ClassInfo c
TypeClass* to = (TypeClass*)_to->toBasetype();
DtoForceDeclareDsymbol(to->sym);
assert(to->sym->ir.irStruct->classInfo);
LLValue* cinfo = to->sym->ir.irStruct->classInfo;
// unfortunately this is needed as the implementation of object differs somehow from the declaration
// this could happen in user code as well :/
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
// call it
LLValue* ret = gIR->CreateCallOrInvoke2(func, ptr, cinfo, "tmp")->get();
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
return new DImValue(_to, ret);
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd)
{
Logger::println("indexing class field %s:", vd->toPrettyChars());
LOG_SCOPE;
if (Logger::enabled())
Logger::cout() << "src: " << *src << '\n';
// make sure class is resolved
DtoResolveClass(cd);
// vd must be a field
IrField* field = vd->ir.irField;
assert(field);
// get the start pointer
const LLType* st = DtoType(cd->type);
// cast to the struct type
src = DtoBitCast(src, st);
// gep to the index
if (Logger::enabled())
{
Logger::cout() << "src2: " << *src << '\n';
Logger::cout() << "index: " << field->index << '\n';
Logger::cout() << "srctype: " << *src->getType() << '\n';
}
LLValue* val = DtoGEPi(src, 0, field->index);
// do we need to offset further? (union area)
if (field->unionOffset)
{
// cast to void*
val = DtoBitCast(val, getVoidPtrType());
// offset
val = DtoGEPi1(val, field->unionOffset);
}
// cast it to the right type
val = DtoBitCast(val, getPtrToType(DtoType(vd->type)));
if (Logger::enabled())
Logger::cout() << "value: " << *val << '\n';
return val;
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl)
{
// sanity checks
assert(fdecl->isVirtual());
assert(!fdecl->isFinal());
assert(fdecl->vtblIndex > 0); // 0 is always ClassInfo/Interface*
assert(inst->getType()->toBasetype()->ty == Tclass);
// get instance
LLValue* vthis = inst->getRVal();
if (Logger::enabled())
Logger::cout() << "vthis: " << *vthis << '\n';
LLValue* funcval = vthis;
// get the vtbl for objects
if (!fdecl->isMember()->isInterfaceDeclaration())
funcval = DtoGEPi(funcval, 0, 0, "tmp");
// load vtbl ptr
funcval = DtoLoad(funcval);
// index vtbl
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toChars());
// load funcptr
funcval = DtoLoad(funcval);
if (Logger::enabled())
Logger::cout() << "funcval: " << *funcval << '\n';
// cast to final funcptr type
funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type)));
if (Logger::enabled())
Logger::cout() << "funcval casted: " << *funcval << '\n';
return funcval;
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoDeclareClassInfo(ClassDeclaration* cd)
{
IrStruct* irstruct = cd->ir.irStruct;
if (irstruct->classInfoDeclared) return;
irstruct->classInfoDeclared = true;
Logger::println("DtoDeclareClassInfo(%s)", cd->toChars());
LOG_SCOPE;
// resovle ClassInfo
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
DtoResolveClass(cinfo);
// do the mangle
std::string gname("_D");
gname.append(cd->mangle());
if (!cd->isInterfaceDeclaration())
gname.append("7__ClassZ");
else
gname.append("11__InterfaceZ");
// create global
irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, DtoLinkage(cd), NULL, gname, gIR->module);
}
//////////////////////////////////////////////////////////////////////////////////////////
#if GENERATE_OFFTI
// build a single element for the OffsetInfo[] of ClassInfo
static LLConstant* build_offti_entry(ClassDeclaration* cd, VarDeclaration* vd)
{
std::vector<LLConstant*> inits(2);
// size_t offset;
//
assert(vd->ir.irField);
// grab the offset from llvm and the formal class type
size_t offset = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(vd->ir.irField->index);
// offset nested struct/union fields
offset += vd->ir.irField->unionOffset;
// assert that it matches DMD
Logger::println("offsets: %lu vs %u", offset, vd->offset);
assert(offset == vd->offset);
inits[0] = DtoConstSize_t(offset);
// TypeInfo ti;
inits[1] = DtoTypeInfoOf(vd->type, true);
// done
return llvm::ConstantStruct::get(inits);
}
static LLConstant* build_offti_array(ClassDeclaration* cd, const LLType* arrayT)
{
IrStruct* irstruct = cd->ir.irStruct;
size_t nvars = irstruct->varDecls.size();
std::vector<LLConstant*> arrayInits(nvars);
for (size_t i=0; i<nvars; i++)
{
arrayInits[i] = build_offti_entry(cd, irstruct->varDecls[i]);
}
LLConstant* size = DtoConstSize_t(nvars);
LLConstant* ptr;
if (nvars == 0)
return LLConstant::getNullValue( arrayT );
// array type
const llvm::ArrayType* arrTy = llvm::ArrayType::get(arrayInits[0]->getType(), nvars);
LLConstant* arrInit = llvm::ConstantArray::get(arrTy, arrayInits);
// mangle
std::string name(cd->type->vtinfo->toChars());
name.append("__OffsetTypeInfos");
// create symbol
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,DtoInternalLinkage(cd),arrInit,name,gIR->module);
ptr = DtoBitCast(gvar, getPtrToType(arrTy->getElementType()));
return DtoConstSlice(size, ptr);
}
#endif // GENERATE_OFFTI
static LLConstant* build_class_dtor(ClassDeclaration* cd)
{
FuncDeclaration* dtor = cd->dtor;
// if no destructor emit a null
if (!dtor)
return getNullPtr(getVoidPtrType());
DtoForceDeclareDsymbol(dtor);
return llvm::ConstantExpr::getBitCast(dtor->ir.irFunc->func, getPtrToType(LLType::Int8Ty));
}
static unsigned build_classinfo_flags(ClassDeclaration* cd)
{
// adapted from original dmd code
unsigned flags = 0;
//flags |= isCOMclass(); // IUnknown
bool hasOffTi = false;
if (cd->ctor) flags |= 8;
for (ClassDeclaration *cd2 = cd; cd2; cd2 = cd2->baseClass)
{
if (cd2->members)
{
for (size_t i = 0; i < cd2->members->dim; i++)
{
Dsymbol *sm = (Dsymbol *)cd2->members->data[i];
if (sm->isVarDeclaration() && !sm->isVarDeclaration()->isDataseg()) // is this enough?
hasOffTi = true;
//printf("sm = %s %s\n", sm->kind(), sm->toChars());
if (sm->hasPointers())
goto L2;
}
}
}
flags |= 2; // no pointers
L2:
if (hasOffTi)
flags |= 4;
return flags;
}
void DtoDefineClassInfo(ClassDeclaration* cd)
{
// The layout is:
// {
// void **vptr;
// monitor_t monitor;
// byte[] initializer; // static initialization data
// char[] name; // class name
// void *[] vtbl;
// Interface[] interfaces;
// ClassInfo *base; // base class
// void *destructor;
// void *invariant; // class invariant
// uint flags;
// void *deallocator;
// OffsetTypeInfo[] offTi;
// void *defaultConstructor;
// }
IrStruct* ir = cd->ir.irStruct;
if (ir->classInfoDefined) return;
ir->classInfoDefined = true;
Logger::println("DtoDefineClassInfo(%s)", cd->toChars());
LOG_SCOPE;
assert(cd->type->ty == Tclass);
assert(ir->classInfo);
TypeClass* cdty = (TypeClass*)cd->type;
if (!cd->isInterfaceDeclaration())
{
assert(ir->init);
assert(ir->constInit);
assert(ir->vtbl);
assert(ir->constVtbl);
}
// holds the list of initializers for llvm
std::vector<LLConstant*> inits;
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
DtoForceConstInitDsymbol(cinfo);
LLConstant* c;
const LLType* voidPtr = getVoidPtrType();
const LLType* voidPtrPtr = getPtrToType(voidPtr);
// own vtable
c = cinfo->ir.irStruct->vtbl;
assert(c);
inits.push_back(c);
// monitor
c = LLConstant::getNullValue(voidPtr);
inits.push_back(c);
// byte[] init
if (cd->isInterfaceDeclaration())
c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(voidPtr));
else
{
c = DtoBitCast(ir->init, voidPtr);
//Logger::cout() << *ir->constInit->getType() << std::endl;
size_t initsz = getTypePaddedSize(ir->init->getType()->getContainedType(0));
c = DtoConstSlice(DtoConstSize_t(initsz), c);
}
inits.push_back(c);
// class name
// from dmd
char *name = cd->ident->toChars();
size_t namelen = strlen(name);
if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
{
name = cd->toPrettyChars();
namelen = strlen(name);
}
c = DtoConstString(name);
inits.push_back(c);
// vtbl array
if (cd->isInterfaceDeclaration())
c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(getPtrToType(voidPtr)));
else {
c = DtoBitCast(ir->vtbl, voidPtrPtr);
c = DtoConstSlice(DtoConstSize_t(cd->vtbl.dim), c);
}
inits.push_back(c);
// interfaces array
VarDeclaration* intersVar = (VarDeclaration*)cinfo->fields.data[3];
const LLType* intersTy = DtoType(intersVar->type);
if (!ir->interfaceInfos)
c = LLConstant::getNullValue(intersTy);
else {
const LLType* t = intersTy->getContainedType(1); // .ptr
// cast to Interface*
c = DtoBitCast(ir->interfaceInfos, t);
size_t isz = ir->interfaceVec.size();
size_t iisz = ir->classInfoInterfaces.size();
assert(iisz <= isz);
// offset - we only want the 'iisz' last ones
LLConstant* idx = DtoConstUint(isz - iisz);
c = llvm::ConstantExpr::getGetElementPtr(c, &idx, 1);
// make array
c = DtoConstSlice(DtoConstSize_t(iisz), c);
}
inits.push_back(c);
// base classinfo
// interfaces never get a base , just the interfaces[]
if (cd->baseClass && !cd->isInterfaceDeclaration()) {
DtoDeclareClassInfo(cd->baseClass);
c = cd->baseClass->ir.irStruct->classInfo;
assert(c);
inits.push_back(c);
}
else {
// null
c = LLConstant::getNullValue(DtoType(cinfo->type));
inits.push_back(c);
}
// destructor
if (cd->isInterfaceDeclaration())
c = LLConstant::getNullValue(voidPtr);
else
c = build_class_dtor(cd);
inits.push_back(c);
// invariant
VarDeclaration* invVar = (VarDeclaration*)cinfo->fields.data[6];
const LLType* invTy = DtoType(invVar->type);
if (cd->inv)
{
DtoForceDeclareDsymbol(cd->inv);
c = cd->inv->ir.irFunc->func;
c = DtoBitCast(c, invTy);
}
else
c = LLConstant::getNullValue(invTy);
inits.push_back(c);
// uint flags
if (cd->isInterfaceDeclaration())
c = DtoConstUint(0);
else {
unsigned flags = build_classinfo_flags(cd);
c = DtoConstUint(flags);
}
inits.push_back(c);
// deallocator
if (cd->aggDelete)
{
DtoForceDeclareDsymbol(cd->aggDelete);
c = cd->aggDelete->ir.irFunc->func;
c = DtoBitCast(c, voidPtr);
}
else
c = LLConstant::getNullValue(voidPtr);
inits.push_back(c);
// offset typeinfo
VarDeclaration* offTiVar = (VarDeclaration*)cinfo->fields.data[9];
const LLType* offTiTy = DtoType(offTiVar->type);
#if GENERATE_OFFTI
if (cd->isInterfaceDeclaration())
c = LLConstant::getNullValue(offTiTy);
else
c = build_offti_array(cd, offTiTy);
#else // GENERATE_OFFTI
c = LLConstant::getNullValue(offTiTy);
#endif // GENERATE_OFFTI
inits.push_back(c);
// default constructor
if (cd->defaultCtor)
{
DtoForceDeclareDsymbol(cd->defaultCtor);
c = isaConstant(cd->defaultCtor->ir.irFunc->func);
c = DtoBitCast(c, voidPtr);
}
else
c = LLConstant::getNullValue(voidPtr);
inits.push_back(c);
#if DMDV2
// xgetMembers
VarDeclaration* xgetVar = (VarDeclaration*)cinfo->fields.data[11];
const LLType* xgetTy = DtoType(xgetVar->type);
// FIXME: fill it out!
inits.push_back( LLConstant::getNullValue(xgetTy) );
#endif
/*size_t n = inits.size();
for (size_t i=0; i<n; ++i)
{
Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n';
}*/
// build the initializer
LLConstant* finalinit = llvm::ConstantStruct::get(inits);
//Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n';
ir->constClassInfo = finalinit;
// refine the type
llvm::cast<llvm::OpaqueType>(ir->classInfoOpaque.get())->refineAbstractTypeTo(finalinit->getType());
// apply initializer
ir->classInfo->setInitializer(finalinit);
}