[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...

In particular, assertions has been fixed to include file/line info, and much more!
This commit is contained in:
Tomas Lindquist Olsen
2008-01-14 05:11:54 +01:00
parent b15b3484c8
commit 4505b9b006
58 changed files with 1986 additions and 754 deletions

View File

@@ -56,7 +56,21 @@ void DtoResolveClass(ClassDeclaration* cd)
if (cd->llvmResolved) return;
cd->llvmResolved = true;
// first resolve the base class
Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
// get the TypeClass
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
// make sure the IRStruct is created
IRStruct* irstruct = cd->llvmIRStruct;
if (!irstruct) {
irstruct = new IRStruct(ts);
cd->llvmIRStruct = irstruct;
}
// resolve the base class
if (cd->baseClass) {
DtoResolveClass(cd->baseClass);
}
@@ -72,28 +86,18 @@ void DtoResolveClass(ClassDeclaration* cd)
}
}
Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
assert(!cd->llvmIRStruct);
IRStruct* irstruct = new IRStruct(ts);
cd->llvmIRStruct = irstruct;
gIR->structs.push_back(irstruct);
gIR->classes.push_back(cd);
// add vtable
ts->llvmVtblType = new llvm::PATypeHolder(llvm::OpaqueType::get());
const llvm::Type* vtabty = llvm::PointerType::get(ts->llvmVtblType->get());
const llvm::Type* vtabty = getPtrToType(ts->llvmVtblType->get());
std::vector<const llvm::Type*> fieldtypes;
fieldtypes.push_back(vtabty);
// add monitor
fieldtypes.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
fieldtypes.push_back(getPtrToType(llvm::Type::Int8Ty));
// add interface vtables
if (cd->vtblInterfaces)
@@ -103,7 +107,7 @@ void DtoResolveClass(ClassDeclaration* cd)
ClassDeclaration *id = b->base;
assert(id->type->ty == Tclass);
TypeClass* itc = (TypeClass*)id->type;
const llvm::Type* ivtblTy = llvm::PointerType::get(itc->llvmVtblType->get());
const llvm::Type* ivtblTy = getPtrToType(itc->llvmVtblType->get());
fieldtypes.push_back(ivtblTy);
// add this interface to the map
@@ -142,12 +146,12 @@ void DtoResolveClass(ClassDeclaration* cd)
lastoffset = i->first;
fieldtype = i->second.type;
fieldinit = i->second.var;
prevsize = gTargetData->getTypeSize(fieldtype);
prevsize = getABITypeSize(fieldtype);
i->second.var->llvmFieldIndex = idx;
}
// colliding offset?
else if (lastoffset == i->first) {
size_t s = gTargetData->getTypeSize(i->second.type);
size_t s = getABITypeSize(i->second.type);
if (s > prevsize) {
fieldpad += s - prevsize;
prevsize = s;
@@ -157,7 +161,7 @@ void DtoResolveClass(ClassDeclaration* cd)
}
// intersecting offset?
else if (i->first < (lastoffset + prevsize)) {
size_t s = gTargetData->getTypeSize(i->second.type);
size_t s = getABITypeSize(i->second.type);
assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size
cd->llvmHasUnions = true;
i->second.var->llvmFieldIndex = idx;
@@ -180,7 +184,7 @@ void DtoResolveClass(ClassDeclaration* cd)
lastoffset = i->first;
fieldtype = i->second.type;
fieldinit = i->second.var;
prevsize = gTargetData->getTypeSize(fieldtype);
prevsize = getABITypeSize(fieldtype);
i->second.var->llvmFieldIndex = idx;
fieldpad = 0;
}
@@ -212,6 +216,7 @@ void DtoResolveClass(ClassDeclaration* cd)
ts->llvmType = new llvm::PATypeHolder(structtype);
else
*ts->llvmType = structtype;
spa = *ts->llvmType;
// name the type
gIR->module->addTypeName(cd->mangle(), ts->llvmType->get());
@@ -221,11 +226,11 @@ void DtoResolveClass(ClassDeclaration* cd)
// ClassInfo classinfo
ClassDeclaration* cinfod = ClassDeclaration::classinfo;
DtoResolveClass(cinfod);
infoTypes.push_back(llvm::PointerType::get(cinfod->type->llvmType->get()));
infoTypes.push_back(getPtrToType(cinfod->type->llvmType->get()));
// void*[] vtbl
std::vector<const llvm::Type*> infoVtbltypes;
infoVtbltypes.push_back(DtoSize_t());
const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
const llvm::Type* byteptrptrty = getPtrToType(getPtrToType(llvm::Type::Int8Ty));
infoVtbltypes.push_back(byteptrptrty);
infoTypes.push_back(llvm::StructType::get(infoVtbltypes));
// int offset
@@ -247,9 +252,9 @@ void DtoResolveClass(ClassDeclaration* cd)
DtoResolveFunction(fd);
//assert(fd->type->ty == Tfunction);
//TypeFunction* tf = (TypeFunction*)fd->type;
//const llvm::Type* fpty = llvm::PointerType::get(tf->llvmType->get());
//const llvm::Type* fpty = getPtrToType(tf->llvmType->get());
const llvm::FunctionType* vfty = DtoBaseFunctionType(fd);
const llvm::Type* vfpty = llvm::PointerType::get(vfty);
const llvm::Type* vfpty = getPtrToType(vfty);
sinits_ty.push_back(vfpty);
}
else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) {
@@ -266,7 +271,7 @@ void DtoResolveClass(ClassDeclaration* cd)
// this is the ClassInfo class, the type is this type
cinfoty = ts->llvmType->get();
}
const llvm::Type* cty = llvm::PointerType::get(cinfoty);
const llvm::Type* cty = getPtrToType(cinfoty);
sinits_ty.push_back(cty);
}
else
@@ -314,8 +319,9 @@ void DtoDeclareClass(ClassDeclaration* cd)
}
// interface vtables are emitted by the class implementing them
// also interfaces have no static initializer
if (!cd->isInterfaceDeclaration()) {
// also, interfaces have no static initializer
// also, abstract classes have no vtable
if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) {
// vtable
std::string varname("_D");
varname.append(cd->mangle());
@@ -331,11 +337,11 @@ void DtoDeclareClass(ClassDeclaration* cd)
// ClassInfo classinfo
ClassDeclaration* cd2 = ClassDeclaration::classinfo;
DtoResolveClass(cd2);
types.push_back(llvm::PointerType::get(cd2->type->llvmType->get()));
types.push_back(getPtrToType(cd2->type->llvmType->get()));
// void*[] vtbl
std::vector<const llvm::Type*> vtbltypes;
vtbltypes.push_back(DtoSize_t());
const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
const llvm::Type* byteptrptrty = getPtrToType(getPtrToType(llvm::Type::Int8Ty));
vtbltypes.push_back(byteptrptrty);
types.push_back(llvm::StructType::get(vtbltypes));
// int offset
@@ -418,6 +424,12 @@ void DtoConstInitClass(ClassDeclaration* cd)
gIR->structs.push_back(irstruct);
gIR->classes.push_back(cd);
// get the struct (class) type
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
const llvm::StructType* structtype = isaStruct(ts->llvmType->get());
const llvm::StructType* vtbltype = isaStruct(ts->llvmVtblType->get());
// make sure each offset knows its default initializer
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i)
{
@@ -431,11 +443,24 @@ void DtoConstInitClass(ClassDeclaration* cd)
std::vector<llvm::Constant*> fieldinits;
// first field is always the vtable
assert(cd->llvmVtbl != 0);
fieldinits.push_back(cd->llvmVtbl);
if (cd->isAbstract())
{
fieldinits.push_back(
llvm::ConstantPointerNull::get(
getPtrToType(
ts->llvmVtblType->get()
)
)
);
}
else
{
assert(cd->llvmVtbl != 0);
fieldinits.push_back(cd->llvmVtbl);
}
// then comes monitor
fieldinits.push_back(llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)));
fieldinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty)));
size_t dataoffset = 2;
@@ -443,9 +468,16 @@ void DtoConstInitClass(ClassDeclaration* cd)
for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
{
IRInterface* iri = i->second;
assert(iri->vtbl);
fieldinits.push_back(iri->vtbl);
++dataoffset;
if (cd->isAbstract())
{
fieldinits.push_back(llvm::Constant::getNullValue(iri->vtblTy));
}
else
{
assert(iri->vtbl);
fieldinits.push_back(iri->vtbl);
++dataoffset;
}
}
/*
@@ -456,12 +488,6 @@ void DtoConstInitClass(ClassDeclaration* cd)
}
*/
// get the struct (class) type
assert(cd->type->ty == Tclass);
TypeClass* ts = (TypeClass*)cd->type;
const llvm::StructType* structtype = isaStruct(ts->llvmType->get());
const llvm::StructType* vtbltype = isaStruct(ts->llvmVtblType->get());
// go through the field inits and build the default initializer
size_t nfi = irstruct->defaultFields.size();
for (size_t i=0; i<nfi; ++i) {
@@ -495,111 +521,115 @@ void DtoConstInitClass(ClassDeclaration* cd)
assert(_init);
cd->llvmConstInit = _init;
// generate vtable initializer
std::vector<llvm::Constant*> sinits;
for (int k=0; k < cd->vtbl.dim; k++)
// abstract classes have no static vtable
if (!cd->isAbstract())
{
Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k];
assert(dsym);
//Logger::cout() << "vtblsym: " << dsym->toChars() << '\n';
// generate vtable initializer
std::vector<llvm::Constant*> sinits;
if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue);
llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
// cast if necessary (overridden method)
if (c->getType() != vtbltype->getElementType(k))
c = llvm::ConstantExpr::getBitCast(c, vtbltype->getElementType(k));
sinits.push_back(c);
}
else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) {
assert(cd->llvmClass);
llvm::Constant* c = cd->llvmClass;
sinits.push_back(c);
}
else
assert(0);
}
for (int k=0; k < cd->vtbl.dim; k++)
{
Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k];
assert(dsym);
//Logger::cout() << "vtblsym: " << dsym->toChars() << '\n';
const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get());
if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue);
llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
// cast if necessary (overridden method)
if (c->getType() != vtbltype->getElementType(k))
c = llvm::ConstantExpr::getBitCast(c, vtbltype->getElementType(k));
sinits.push_back(c);
}
else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) {
assert(cd->llvmClass);
llvm::Constant* c = cd->llvmClass;
sinits.push_back(c);
}
else
assert(0);
}
const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get());
#if 0
for (size_t i=0; i< sinits.size(); ++i)
{
Logger::cout() << "field[" << i << "] = " << *svtbl_ty->getElementType(i) << '\n';
Logger::cout() << "init [" << i << "] = " << *sinits[i]->getType() << '\n';
assert(svtbl_ty->getElementType(i) == sinits[i]->getType());
}
#endif
llvm::Constant* cvtblInit = llvm::ConstantStruct::get(svtbl_ty, sinits);
cd->llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(cvtblInit);
// create interface vtable const initalizers
int idx = 2;
int idxScale = PTRSIZE;
for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
{
ClassDeclaration* id = i->first;
assert(id->type->ty == Tclass);
TypeClass* its = (TypeClass*)id->type;
IRInterface* iri = i->second;
BaseClass* b = iri->base;
const llvm::StructType* ivtbl_ty = isaStruct(its->llvmVtblType->get());
// generate interface info initializer
std::vector<llvm::Constant*> infoInits;
// classinfo
assert(id->llvmClass);
llvm::Constant* c = id->llvmClass;
infoInits.push_back(c);
// vtbl
const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
c = llvm::ConstantExpr::getBitCast(iri->vtbl, byteptrptrty);
c = DtoConstSlice(DtoConstSize_t(b->vtbl.dim), c);
infoInits.push_back(c);
// offset
infoInits.push_back(DtoConstInt(idx*idxScale));
// create interface info initializer constant
iri->infoInit = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(iri->infoTy, infoInits));
// generate vtable initializer
std::vector<llvm::Constant*> iinits;
// add interface info
iinits.push_back(iri->info);
for (int k=1; k < b->vtbl.dim; k++)
for (size_t i=0; i< sinits.size(); ++i)
{
Logger::println("interface vtbl const init nr. %d", k);
Dsymbol* dsym = (Dsymbol*)b->vtbl.data[k];
FuncDeclaration* fd = dsym->isFuncDeclaration();
assert(fd);
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue);
llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
// we have to bitcast, as the type created in ResolveClass expects a different this type
c = llvm::ConstantExpr::getBitCast(c, iri->vtblTy->getContainedType(k));
iinits.push_back(c);
}
#if 1
for (size_t x=0; x< iinits.size(); ++x)
{
Logger::cout() << "field[" << x << "] = " << *ivtbl_ty->getElementType(x) << "\n\n";
Logger::cout() << "init [" << x << "] = " << *iinits[x] << "\n\n";
assert(ivtbl_ty->getElementType(x) == iinits[x]->getType());
Logger::cout() << "field[" << i << "] = " << *svtbl_ty->getElementType(i) << '\n';
Logger::cout() << "init [" << i << "] = " << *sinits[i]->getType() << '\n';
assert(svtbl_ty->getElementType(i) == sinits[i]->getType());
}
#endif
llvm::Constant* civtblInit = llvm::ConstantStruct::get(ivtbl_ty, iinits);
iri->vtblInit = llvm::cast<llvm::ConstantStruct>(civtblInit);
llvm::Constant* cvtblInit = llvm::ConstantStruct::get(svtbl_ty, sinits);
cd->llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(cvtblInit);
idx++;
}
// create interface vtable const initalizers
int idx = 2;
int idxScale = PTRSIZE;
for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
{
ClassDeclaration* id = i->first;
assert(id->type->ty == Tclass);
TypeClass* its = (TypeClass*)id->type;
IRInterface* iri = i->second;
BaseClass* b = iri->base;
const llvm::StructType* ivtbl_ty = isaStruct(its->llvmVtblType->get());
// generate interface info initializer
std::vector<llvm::Constant*> infoInits;
// classinfo
assert(id->llvmClass);
llvm::Constant* c = id->llvmClass;
infoInits.push_back(c);
// vtbl
const llvm::Type* byteptrptrty = getPtrToType(getPtrToType(llvm::Type::Int8Ty));
c = llvm::ConstantExpr::getBitCast(iri->vtbl, byteptrptrty);
c = DtoConstSlice(DtoConstSize_t(b->vtbl.dim), c);
infoInits.push_back(c);
// offset
infoInits.push_back(DtoConstInt(idx*idxScale));
// create interface info initializer constant
iri->infoInit = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(iri->infoTy, infoInits));
// generate vtable initializer
std::vector<llvm::Constant*> iinits;
// add interface info
iinits.push_back(iri->info);
for (int k=1; k < b->vtbl.dim; k++)
{
Logger::println("interface vtbl const init nr. %d", k);
Dsymbol* dsym = (Dsymbol*)b->vtbl.data[k];
FuncDeclaration* fd = dsym->isFuncDeclaration();
assert(fd);
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue);
llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
// we have to bitcast, as the type created in ResolveClass expects a different this type
c = llvm::ConstantExpr::getBitCast(c, iri->vtblTy->getContainedType(k));
iinits.push_back(c);
}
#if 1
for (size_t x=0; x< iinits.size(); ++x)
{
Logger::cout() << "field[" << x << "] = " << *ivtbl_ty->getElementType(x) << "\n\n";
Logger::cout() << "init [" << x << "] = " << *iinits[x] << "\n\n";
assert(ivtbl_ty->getElementType(x) == iinits[x]->getType());
}
#endif
llvm::Constant* civtblInit = llvm::ConstantStruct::get(ivtbl_ty, iinits);
iri->vtblInit = llvm::cast<llvm::ConstantStruct>(civtblInit);
idx++;
}
} // !abstract
gIR->classes.pop_back();
gIR->structs.pop_back();
@@ -621,7 +651,9 @@ void DtoDefineClass(ClassDeclaration* cd)
if (cd->getModule() == gIR->dmodule) {
// interfaces don't have initializers
if (!cd->isInterfaceDeclaration()) {
// neither do abstract classes
if (!cd->isInterfaceDeclaration() && !cd->isAbstract())
{
cd->llvmInit->setInitializer(cd->llvmConstInit);
cd->llvmVtbl->setInitializer(cd->llvmConstVtbl);
@@ -635,7 +667,8 @@ void DtoDefineClass(ClassDeclaration* cd)
infoInits.push_back(iri->infoInit);
}
// initialize interface info array
if (!infoInits.empty()) {
if (!infoInits.empty())
{
llvm::Constant* arrInit = llvm::ConstantArray::get(irstruct->interfaceInfosTy, infoInits);
irstruct->interfaceInfos->setInitializer(arrInit);
}
@@ -648,6 +681,141 @@ void DtoDefineClass(ClassDeclaration* cd)
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoNewClass(TypeClass* tc, NewExp* newexp)
{
// resolve type
DtoForceDeclareDsymbol(tc->sym);
// allocate
llvm::Value* mem;
if (newexp->onstack)
{
mem = new llvm::AllocaInst(DtoType(tc)->getContainedType(0), "newclass_alloca", gIR->topallocapoint());
}
else
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_newclass");
std::vector<llvm::Value*> args;
args.push_back(tc->sym->llvmClass);
mem = gIR->ir->CreateCall(fn, args.begin(), args.end(), "newclass_gc_alloc");
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 = 2;
idx += tc->sym->llvmIRStruct->interfaces.size();
llvm::Value* dst = thisval->getRVal();
llvm::Value* src = DtoGEPi(mem,0,idx,"tmp");
Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
DtoStore(dst, src);
}
// set the context for nested classes
else if (tc->sym->isNested())
{
Logger::println("Resolving nested context");
LOG_SCOPE;
size_t idx = 2;
idx += tc->sym->llvmIRStruct->interfaces.size();
llvm::Value* nest = gIR->func()->decl->llvmNested;
if (!nest)
nest = gIR->func()->decl->llvmThisVar;
assert(nest);
llvm::Value* gep = DtoGEPi(mem,0,idx,"tmp");
nest = DtoBitCast(nest, gep->getType()->getContainedType(0));
DtoStore(nest, gep);
}
// call constructor
if (newexp->arguments)
return DtoCallClassCtor(tc, newexp->member, newexp->arguments, mem);
// return default constructed class
return new DImValue(tc, mem, false);
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoInitClass(TypeClass* tc, llvm::Value* dst)
{
size_t presz = 2*getABITypeSize(DtoSize_t());
uint64_t n = getABITypeSize(tc->llvmType->get()) - presz;
// set vtable field seperately, this might give better optimization
assert(tc->sym->llvmVtbl);
DtoStore(tc->sym->llvmVtbl, DtoGEPi(dst,0,0,"vtbl"));
// monitor always defaults to zero
llvm::Value* tmp = DtoGEPi(dst,0,1,"monitor");
DtoStore(llvm::Constant::getNullValue(tmp->getType()->getContainedType(0)), tmp);
// done?
if (n == 0)
return;
// copy the rest from the static initializer
assert(tc->sym->llvmInit);
assert(dst->getType() == tc->sym->llvmInit->getType());
const llvm::Type* arrty = getPtrToType(llvm::Type::Int8Ty);
llvm::Value* dstarr = DtoGEPi(dst,0,2,"tmp");
dstarr = DtoBitCast(dstarr, arrty);
llvm::Value* srcarr = DtoGEPi(tc->sym->llvmInit,0,2,"tmp");
srcarr = DtoBitCast(srcarr, arrty);
llvm::Function* fn = LLVM_DeclareMemCpy32();
std::vector<llvm::Value*> llargs;
llargs.resize(4);
llargs[0] = dstarr;
llargs[1] = srcarr;
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoCallClassCtor(TypeClass* type, CtorDeclaration* ctor, Array* arguments, llvm::Value* mem)
{
Logger::println("Calling constructor");
LOG_SCOPE;
assert(ctor);
DtoForceDeclareDsymbol(ctor);
llvm::Function* fn = llvm::cast<llvm::Function>(ctor->llvmValue);
TypeFunction* tf = (TypeFunction*)DtoDType(ctor->type);
std::vector<llvm::Value*> ctorargs;
ctorargs.push_back(mem);
for (size_t i=0; i<arguments->dim; ++i)
{
Expression* ex = (Expression*)arguments->data[i];
Argument* fnarg = Argument::getNth(tf->parameters, i);
DValue* argval = DtoArgument(fnarg, ex);
llvm::Value* a = argval->getRVal();
const llvm::Type* aty = fn->getFunctionType()->getParamType(i+1);
if (a->getType() != aty)
a = DtoBitCast(a, aty);
ctorargs.push_back(a);
}
llvm::CallInst* call = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", gIR->scopebb());
call->setCallingConv(DtoCallingConv(LINKd));
return new DImValue(type, call, false);
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
{
Array* arr = &tc->sym->dtors;
@@ -661,46 +829,6 @@ void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
//////////////////////////////////////////////////////////////////////////////////////////
void DtoInitClass(TypeClass* tc, llvm::Value* dst)
{
assert(gIR);
assert(tc->llvmType);
uint64_t size_t_size = gTargetData->getTypeSize(DtoSize_t());
uint64_t n = gTargetData->getTypeSize(tc->llvmType->get()) - size_t_size;
// set vtable field
llvm::Value* vtblvar = DtoGEPi(dst,0,0,"tmp",gIR->scopebb());
assert(tc->sym->llvmVtbl);
new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb());
// copy the static initializer
if (n > 0) {
assert(tc->sym->llvmInit);
assert(dst->getType() == tc->sym->llvmInit->getType());
llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
dstarr = DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb());
llvm::Value* srcarr = new llvm::BitCastInst(tc->sym->llvmInit,arrty,"tmp",gIR->scopebb());
srcarr = DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb());
llvm::Function* fn = LLVM_DeclareMemCpy32();
std::vector<llvm::Value*> llargs;
llargs.resize(4);
llargs[0] = dstarr;
llargs[1] = srcarr;
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
}
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoCastClass(DValue* val, Type* _to)
{
Type* to = DtoDType(_to);
@@ -717,8 +845,12 @@ DValue* DtoCastClass(DValue* val, Type* _to)
TypeClass* fc = (TypeClass*)from;
if (tc->sym->isInterfaceDeclaration()) {
assert(!fc->sym->isInterfaceDeclaration());
return DtoDynamicCastObject(val, _to);
if (fc->sym->isInterfaceDeclaration()) {
return DtoDynamicCastInterface(val, _to);
}
else {
return DtoDynamicCastObject(val, _to);
}
}
else {
int poffset;
@@ -805,6 +937,45 @@ DValue* DtoCastInterfaceToObject(DValue* val, Type* to)
//////////////////////////////////////////////////////////////////////////////////////////
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<llvm::Value*> args;
// void* p
llvm::Value* tmp = val->getRVal();
tmp = DtoBitCast(tmp, funcTy->getParamType(0));
args.push_back(tmp);
// ClassInfo c
TypeClass* to = (TypeClass*)DtoDType(_to);
DtoForceDeclareDsymbol(to->sym);
assert(to->sym->llvmClass);
tmp = to->sym->llvmClass;
// unfortunately this is needed as the implementation of object differs somehow from the declaration
// this could happen in user code as well :/
tmp = DtoBitCast(tmp, funcTy->getParamType(1));
args.push_back(tmp);
// call it
llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp");
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
return new DImValue(_to, ret);
}
//////////////////////////////////////////////////////////////////////////////////////////
static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx)
{
// start at the bottom of the inheritance chain
@@ -851,7 +1022,7 @@ llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsi
if (idxs.empty())
idxs.push_back(0);
const llvm::Type* llt = llvm::PointerType::get(DtoType(t));
const llvm::Type* llt = getPtrToType(DtoType(t));
const llvm::Type* st = DtoType(cd->type);
if (ptr->getType() != st) {
assert(cd->llvmHasUnions);
@@ -895,7 +1066,7 @@ llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsi
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {
const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type));
const llvm::Type* sty = getPtrToType(DtoType(vd->type));
if (ptr->getType() != sty) {
ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp");
std::vector<unsigned> tmp;
@@ -910,7 +1081,7 @@ llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsi
assert(0);
size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0));
size_t llt_sz = getABITypeSize(llt->getContainedType(0));
assert(os % llt_sz == 0);
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb());
@@ -918,6 +1089,29 @@ llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsi
//////////////////////////////////////////////////////////////////////////////////////////
llvm::Value* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl)
{
assert(fdecl->isVirtual());//fdecl->isAbstract() || (!fdecl->isFinal() && fdecl->isVirtual()));
assert(fdecl->vtblIndex > 0);
assert(DtoDType(inst->getType())->ty == Tclass);
llvm::Value* vthis = inst->getRVal();
//Logger::cout() << "vthis: " << *vthis << '\n';
llvm::Value* funcval;
funcval = DtoGEPi(vthis, 0, 0, "tmp");
funcval = DtoLoad(funcval);
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toPrettyChars());
funcval = DtoLoad(funcval);
//assert(funcval->getType() == DtoType(fdecl->type));
//cc = DtoCallingConv(fdecl->linkage);
return funcval;
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoDeclareClassInfo(ClassDeclaration* cd)
{
if (cd->llvmClassDeclared) return;
@@ -961,7 +1155,7 @@ static llvm::Constant* build_offti_entry(VarDeclaration* vd)
DtoForceDeclareDsymbol(vd->type->vtinfo);
llvm::Constant* c = isaConstant(vd->type->vtinfo->llvmValue);
const llvm::Type* tiTy = llvm::PointerType::get(Type::typeinfo->type->llvmType->get());
const llvm::Type* tiTy = getPtrToType(Type::typeinfo->type->llvmType->get());
//Logger::cout() << "tiTy = " << *tiTy << '\n';
types.push_back(tiTy);
@@ -1002,7 +1196,7 @@ static llvm::Constant* build_offti_array(ClassDeclaration* cd, llvm::Constant* i
// OffsetTypeInfo type
std::vector<const llvm::Type*> elemtypes;
elemtypes.push_back(DtoSize_t());
const llvm::Type* tiTy = llvm::PointerType::get(Type::typeinfo->type->llvmType->get());
const llvm::Type* tiTy = getPtrToType(Type::typeinfo->type->llvmType->get());
elemtypes.push_back(tiTy);
const llvm::StructType* sTy = llvm::StructType::get(elemtypes);
@@ -1013,7 +1207,7 @@ static llvm::Constant* build_offti_array(ClassDeclaration* cd, llvm::Constant* i
std::string name(cd->type->vtinfo->toChars());
name.append("__OffsetTypeInfos");
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,llvm::GlobalValue::InternalLinkage,arrInit,name,gIR->module);
ptr = llvm::ConstantExpr::getBitCast(gvar, llvm::PointerType::get(sTy));
ptr = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(sTy));
}
else {
ptr = llvm::ConstantPointerNull::get(isaPointer(initTy->getElementType(1)));
@@ -1026,18 +1220,18 @@ static llvm::Constant* build_class_dtor(ClassDeclaration* cd)
{
// construct the function
std::vector<const llvm::Type*> paramTypes;
paramTypes.push_back(llvm::PointerType::get(cd->type->llvmType->get()));
paramTypes.push_back(getPtrToType(cd->type->llvmType->get()));
const llvm::FunctionType* fnTy = llvm::FunctionType::get(llvm::Type::VoidTy, paramTypes, false);
if (cd->dtors.dim == 0) {
return llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty));
return llvm::ConstantPointerNull::get(getPtrToType(llvm::Type::Int8Ty));
}
else if (cd->dtors.dim == 1) {
DtorDeclaration *d = (DtorDeclaration *)cd->dtors.data[0];
DtoForceDeclareDsymbol(d);
assert(d->llvmValue);
return llvm::ConstantExpr::getBitCast(isaConstant(d->llvmValue), llvm::PointerType::get(llvm::Type::Int8Ty));
return llvm::ConstantExpr::getBitCast(isaConstant(d->llvmValue), getPtrToType(llvm::Type::Int8Ty));
}
std::string gname("_D");
@@ -1060,7 +1254,7 @@ static llvm::Constant* build_class_dtor(ClassDeclaration* cd)
}
builder.CreateRetVoid();
return llvm::ConstantExpr::getBitCast(func, llvm::PointerType::get(llvm::Type::Int8Ty));
return llvm::ConstantExpr::getBitCast(func, getPtrToType(llvm::Type::Int8Ty));
}
static uint build_classinfo_flags(ClassDeclaration* cd)
@@ -1121,7 +1315,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
assert(cd->llvmClass);
TypeClass* cdty = (TypeClass*)cd->type;
if (!cd->isInterfaceDeclaration()) {
if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) {
assert(cd->llvmInit);
assert(cd->llvmConstInit);
assert(cd->llvmVtbl);
@@ -1147,14 +1341,14 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
inits.push_back(c);
// byte[] init
const llvm::Type* byteptrty = llvm::PointerType::get(llvm::Type::Int8Ty);
if (cd->isInterfaceDeclaration()) {
const llvm::Type* byteptrty = getPtrToType(llvm::Type::Int8Ty);
if (cd->isInterfaceDeclaration() || cd->isAbstract()) {
c = cinfo->llvmConstInit->getOperand(2);
}
else {
c = llvm::ConstantExpr::getBitCast(cd->llvmInit, byteptrty);
assert(!cd->llvmConstInit->getType()->isAbstract());
size_t initsz = gTargetData->getTypeSize(cd->llvmConstInit->getType());
size_t initsz = getABITypeSize(cd->llvmConstInit->getType());
c = DtoConstSlice(DtoConstSize_t(initsz), c);
}
inits.push_back(c);
@@ -1172,11 +1366,11 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
inits.push_back(c);
// vtbl array
if (cd->isInterfaceDeclaration()) {
if (cd->isInterfaceDeclaration() || cd->isAbstract()) {
c = cinfo->llvmConstInit->getOperand(4);
}
else {
const llvm::Type* byteptrptrty = llvm::PointerType::get(byteptrty);
const llvm::Type* byteptrptrty = getPtrToType(byteptrty);
assert(!cd->llvmVtbl->getType()->isAbstract());
c = llvm::ConstantExpr::getBitCast(cd->llvmVtbl, byteptrptrty);
assert(!cd->llvmConstVtbl->getType()->isAbstract());
@@ -1187,7 +1381,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
// interfaces array
IRStruct* irstruct = cd->llvmIRStruct;
if (cd->isInterfaceDeclaration() || !irstruct->interfaceInfos) {
if (cd->isInterfaceDeclaration() || !irstruct->interfaceInfos || cd->isAbstract()) {
c = cinfo->llvmConstInit->getOperand(5);
}
else {
@@ -1199,7 +1393,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
inits.push_back(c);
// base classinfo
if (cd->baseClass && !cd->isInterfaceDeclaration()) {
if (cd->baseClass && !cd->isInterfaceDeclaration() && !cd->isAbstract()) {
DtoDeclareClassInfo(cd->baseClass);
c = cd->baseClass->llvmClass;
assert(c);
@@ -1212,7 +1406,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
}
// destructor
if (cd->isInterfaceDeclaration()) {
if (cd->isInterfaceDeclaration() || cd->isAbstract()) {
c = cinfo->llvmConstInit->getOperand(7);
}
else {
@@ -1226,7 +1420,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
inits.push_back(c);
// uint flags
if (cd->isInterfaceDeclaration()) {
if (cd->isInterfaceDeclaration() || cd->isAbstract()) {
c = cinfo->llvmConstInit->getOperand(9);
}
else {
@@ -1241,7 +1435,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
inits.push_back(c);
// offset typeinfo
if (cd->isInterfaceDeclaration()) {
if (cd->isInterfaceDeclaration() || cd->isAbstract()) {
c = cinfo->llvmConstInit->getOperand(11);
}
else {
@@ -1250,7 +1444,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
inits.push_back(c);
// default constructor
if (cd->defaultCtor && !cd->isInterfaceDeclaration()) {
if (cd->defaultCtor && !cd->isInterfaceDeclaration() && !cd->isAbstract()) {
DtoForceDeclareDsymbol(cd->defaultCtor);
c = isaConstant(cd->defaultCtor->llvmValue);
const llvm::Type* toTy = cinfo->llvmConstInit->getOperand(12)->getType();