Mercurial > projects > ldc
diff gen/classes.cpp @ 133:44a95ac7368a trunk
[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!
author | lindquist |
---|---|
date | Mon, 14 Jan 2008 05:11:54 +0100 |
parents | 1700239cab2e |
children | 0e28624814e8 |
line wrap: on
line diff
--- a/gen/classes.cpp Fri Jan 11 17:57:40 2008 +0100 +++ b/gen/classes.cpp Mon Jan 14 05:11:54 2008 +0100 @@ -56,7 +56,21 @@ 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 @@ } } - 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 @@ 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 @@ 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 @@ } // 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ } // 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ } */ - // 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 @@ assert(_init); cd->llvmConstInit = _init; - // generate vtable initializer - std::vector<llvm::Constant*> sinits; + // abstract classes have no static vtable + if (!cd->isAbstract()) + { + // generate vtable initializer + std::vector<llvm::Constant*> sinits; - for (int k=0; k < cd->vtbl.dim; k++) - { - Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; - assert(dsym); - //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; + for (int k=0; k < cd->vtbl.dim; k++) + { + Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; + assert(dsym); + //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; - 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); + 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); } - 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()); + 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); + + // 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)); - idx++; - } + // 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 @@ 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 @@ 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 @@ ////////////////////////////////////////////////////////////////////////////////////////// +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 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 @@ 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* 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 @@ 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 @@ 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 @@ 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* 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 @@ 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 @@ // 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 @@ 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 @@ { // 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ } // destructor - if (cd->isInterfaceDeclaration()) { + if (cd->isInterfaceDeclaration() || cd->isAbstract()) { c = cinfo->llvmConstInit->getOperand(7); } else { @@ -1226,7 +1420,7 @@ inits.push_back(c); // uint flags - if (cd->isInterfaceDeclaration()) { + if (cd->isInterfaceDeclaration() || cd->isAbstract()) { c = cinfo->llvmConstInit->getOperand(9); } else { @@ -1241,7 +1435,7 @@ inits.push_back(c); // offset typeinfo - if (cd->isInterfaceDeclaration()) { + if (cd->isInterfaceDeclaration() || cd->isAbstract()) { c = cinfo->llvmConstInit->getOperand(11); } else { @@ -1250,7 +1444,7 @@ 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();