Mercurial > projects > ldc
diff gen/classes.cpp @ 100:5071469303d4 trunk
[svn r104] TONS OF FIXES.
Split up declaration, constant initializer gen and definition for globals, structs, classes and functions.
Improved ClassInfo support (not complete), not in vtable yet.
Fixed a bunch of forward reference problems.
Much more. Major commit! :)
author | lindquist |
---|---|
date | Fri, 16 Nov 2007 08:21:47 +0100 |
parents | |
children | 027b8d8b71ec |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/classes.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -0,0 +1,431 @@ +#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/arrays.h" +#include "gen/logger.h" +#include "gen/classes.h" + +////////////////////////////////////////////////////////////////////////////////////////// + +static void LLVM_AddBaseClassData(BaseClasses* bcs) +{ + // add base class data members first + for (int j=0; j<bcs->dim; j++) + { + BaseClass* bc = (BaseClass*)(bcs->data[j]); + assert(bc); + Logger::println("Adding base class members of %s", bc->base->toChars()); + LOG_SCOPE; + + bc->base->toObjFile(); + + LLVM_AddBaseClassData(&bc->base->baseclasses); + for (int k=0; k < bc->base->members->dim; k++) { + Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); + if (dsym->isVarDeclaration()) + { + dsym->toObjFile(); + } + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoDeclareClass(ClassDeclaration* cd) +{ + if (cd->llvmTouched) return; + cd->llvmTouched = true; + + Logger::println("DtoDeclareClass(%s)\n", cd->toPrettyChars()); + 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 + llvm::PATypeHolder pa = llvm::OpaqueType::get(); + const llvm::Type* vtabty = llvm::PointerType::get(pa); + + std::vector<const llvm::Type*> fieldtypes; + fieldtypes.push_back(vtabty); + + // base classes first + LLVM_AddBaseClassData(&cd->baseclasses); + + // then add own members + for (int k=0; k < cd->members->dim; k++) { + Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); + dsym->toObjFile(); + } + + // add field types + for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { + fieldtypes.push_back(i->second.type); + } + + const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); + // refine abstract types for stuff like: class C {C next;} + assert(irstruct->recty != 0); + { + llvm::PATypeHolder& spa = irstruct->recty; + llvm::cast<llvm::OpaqueType>(spa.get())->refineAbstractTypeTo(structtype); + structtype = isaStruct(spa.get()); + } + + // create the type + ts->llvmType = new llvm::PATypeHolder(structtype); + + bool needs_definition = false; + if (cd->parent->isModule()) { + gIR->module->addTypeName(cd->mangle(), ts->llvmType->get()); + needs_definition = (cd->getModule() == gIR->dmodule); + } + else { + assert(0 && "class parent is not a module"); + } + + // generate vtable + llvm::GlobalVariable* svtblVar = 0; + std::vector<llvm::Constant*> sinits; + std::vector<const llvm::Type*> sinits_ty; + sinits.reserve(cd->vtbl.dim); + sinits_ty.reserve(cd->vtbl.dim); + + 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()) { + fd->toObjFile(); + assert(fd->llvmValue); + llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue); + sinits.push_back(c); + sinits_ty.push_back(c->getType()); + } + else if (ClassDeclaration* cd = dsym->isClassDeclaration()) { + const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty); + llvm::Constant* c = llvm::Constant::getNullValue(cty); + sinits.push_back(c); + sinits_ty.push_back(cty); + } + else + assert(0); + } + + const llvm::StructType* svtbl_ty = 0; + if (!sinits.empty()) + { + llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; + + std::string varname("_D"); + varname.append(cd->mangle()); + varname.append("6__vtblZ"); + + std::string styname(cd->mangle()); + styname.append("__vtblTy"); + + svtbl_ty = llvm::StructType::get(sinits_ty); + gIR->module->addTypeName(styname, svtbl_ty); + svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); + + cd->llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits)); + if (needs_definition) + svtblVar->setInitializer(cd->llvmConstVtbl); + cd->llvmVtbl = svtblVar; + } + + // refine for final vtable type + llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty); + + std::string initname("_D"); + initname.append(cd->mangle()); + initname.append("6__initZ"); + llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; + llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module); + ts->llvmInit = initvar; + + gIR->classes.pop_back(); + gIR->structs.pop_back(); + + gIR->constInitQueue.push_back(cd); + if (needs_definition) + gIR->defineQueue.push_back(cd); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoConstInitClass(ClassDeclaration* cd) +{ + IRStruct* irstruct = cd->llvmIRStruct; + if (irstruct->constinited) return; + irstruct->constinited = true; + + Logger::println("DtoConstInitClass(%s)\n", cd->toPrettyChars()); + LOG_SCOPE; + + gIR->structs.push_back(irstruct); + gIR->classes.push_back(cd); + + // make sure each offset knows its default initializer + for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) + { + IRStruct::Offset* so = &i->second; + llvm::Constant* finit = DtoConstFieldInitializer(so->var->type, so->var->init); + so->init = finit; + so->var->llvmConstInit = finit; + } + + // fill out fieldtypes/inits + std::vector<llvm::Constant*> fieldinits; + + // first field is always the vtable + assert(cd->llvmVtbl != 0); + fieldinits.push_back(cd->llvmVtbl); + + // rest + for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { + fieldinits.push_back(i->second.init); + } + + // get the struct (class) type + assert(cd->type->ty == Tclass); + TypeClass* ts = (TypeClass*)cd->type; + const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); + + // generate initializer + Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; + Logger::println("%u %u fields", structtype->getNumElements(), fieldinits.size()); + llvm::Constant* _init = llvm::ConstantStruct::get(structtype, fieldinits); + assert(_init); + cd->llvmInitZ = _init; + + gIR->classes.pop_back(); + gIR->structs.pop_back(); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoDefineClass(ClassDeclaration* cd) +{ + IRStruct* irstruct = cd->llvmIRStruct; + if (irstruct->defined) return; + irstruct->defined = true; + + Logger::println("DtoDefineClass(%s)\n", cd->toPrettyChars()); + LOG_SCOPE; + + // get the struct (class) type + assert(cd->type->ty == Tclass); + TypeClass* ts = (TypeClass*)cd->type; + + bool def = false; + if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) { + ts->llvmInit->setInitializer(cd->llvmInitZ); + def = true; + } + + // generate classinfo + DtoDeclareClassInfo(cd); + if (def) DtoDefineClassInfo(cd); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance) +{ + Array* arr = &tc->sym->dtors; + for (size_t i=0; i<arr->dim; i++) + { + FuncDeclaration* fd = (FuncDeclaration*)arr->data[i]; + assert(fd->llvmValue); + new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb()); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +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->llvmInit); + assert(dst->getType() == tc->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->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()); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoDeclareClassInfo(ClassDeclaration* cd) +{ + if (cd->llvmClass) + return; + + Logger::println("CLASS INFO DECLARATION: %s", cd->toChars()); + LOG_SCOPE; + + ClassDeclaration* cinfo = ClassDeclaration::classinfo; + cinfo->toObjFile(); + + const llvm::Type* st = cinfo->type->llvmType->get(); + + std::string gname("_D"); + gname.append(cd->mangle()); + gname.append("7__ClassZ"); + + cd->llvmClass = new llvm::GlobalVariable(st, true, llvm::GlobalValue::ExternalLinkage, NULL, gname, gIR->module); +} + +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; +// } + + if (cd->llvmClassZ) + return; + + Logger::println("CLASS INFO DEFINITION: %s", cd->toChars()); + LOG_SCOPE; + assert(cd->llvmClass); + + // holds the list of initializers for llvm + std::vector<llvm::Constant*> inits; + + ClassDeclaration* cinfo = ClassDeclaration::classinfo; + DtoConstInitClass(cinfo); + assert(cinfo->llvmInitZ); + + llvm::Constant* c; + + // own vtable + c = cinfo->llvmInitZ->getOperand(0); + assert(c); + inits.push_back(c); + + // monitor + // TODO no monitors yet + + // initializer + c = cinfo->llvmInitZ->getOperand(1); + 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 + c = cinfo->llvmInitZ->getOperand(3); + inits.push_back(c); + + // interfaces array + c = cinfo->llvmInitZ->getOperand(4); + inits.push_back(c); + + // base classinfo + c = cinfo->llvmInitZ->getOperand(5); + inits.push_back(c); + + // destructor + c = cinfo->llvmInitZ->getOperand(6); + inits.push_back(c); + + // invariant + c = cinfo->llvmInitZ->getOperand(7); + inits.push_back(c); + + // flags + c = cinfo->llvmInitZ->getOperand(8); + inits.push_back(c); + + // allocator + c = cinfo->llvmInitZ->getOperand(9); + inits.push_back(c); + + // offset typeinfo + c = cinfo->llvmInitZ->getOperand(10); + inits.push_back(c); + + // default constructor + c = cinfo->llvmInitZ->getOperand(11); + inits.push_back(c); + + /*size_t n = inits.size(); + for (size_t i=0; i<n; ++i) + { + Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; + }*/ + + // build the initializer + const llvm::StructType* st = isaStruct(cinfo->llvmInitZ->getType()); + llvm::Constant* finalinit = llvm::ConstantStruct::get(st, inits); + //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; + + cd->llvmClassZ = finalinit; + cd->llvmClass->setInitializer(finalinit); +}