# HG changeset patch # User Tomas Lindquist Olsen # Date 1227990343 -3600 # Node ID 340acf1535d05181ed231200fb5dd8b2bddce961 # Parent 6e7a4c3b64d2c937acb4e90a16709de25e9a3dd3 Removed KDevelop3 project files, CMake can generate them just fine! Fixed function literals in static initializers. Changed alignment of delegates from 2*PTRSIZE to just PTRSIZE. Changed errors to go to stderr instead of stdout. Fairly major rewriting of struct/union/class handling, STILL A BIT BUGGY !!! diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/aggregate.h --- a/dmd/aggregate.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/aggregate.h Sat Nov 29 21:25:43 2008 +0100 @@ -45,7 +45,6 @@ class ConstantStruct; class GlobalVariable; } -struct DUnion; struct AggregateDeclaration : ScopeDsymbol { @@ -258,9 +257,6 @@ Symbol *vtblsym; - // llvm - void offsetToIndex(Type* t, unsigned os, std::vector& result); - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } }; diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/attrib.c --- a/dmd/attrib.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/attrib.c Sat Nov 29 21:25:43 2008 +0100 @@ -616,7 +616,6 @@ sc->flags = 0; aad.structalign = sc->structalign; aad.parent = ad; - for (unsigned i = 0; i < decl->dim; i++) { Dsymbol *s = (Dsymbol *)decl->data[i]; @@ -672,6 +671,9 @@ { VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; + // LDC + v->offset2 = sc->offset; + v->offset += sc->offset; // LDC diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/attrib.h --- a/dmd/attrib.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/attrib.h Sat Nov 29 21:25:43 2008 +0100 @@ -50,7 +50,7 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); AttribDeclaration *isAttribDeclaration() { return this; } - void toObjFile(int multiobj); // compile to .obj file + virtual void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); }; @@ -107,6 +107,9 @@ void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); + + // LDC + void toObjFile(int multiobj); // compile to .obj file }; struct PragmaDeclaration : AttribDeclaration diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/declaration.c --- a/dmd/declaration.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/declaration.c Sat Nov 29 21:25:43 2008 +0100 @@ -624,6 +624,7 @@ // LDC anonDecl = NULL; + offset2 = 0; } Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/declaration.h --- a/dmd/declaration.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/declaration.h Sat Nov 29 21:25:43 2008 +0100 @@ -273,6 +273,7 @@ // LDC AnonDeclaration* anonDecl; + unsigned offset2; }; /**************************************************************/ diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/expression.h --- a/dmd/expression.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/expression.h Sat Nov 29 21:25:43 2008 +0100 @@ -628,6 +628,9 @@ int inlineCost(InlineCostState *ics); //Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); + + // LDC + virtual llvm::Constant *toConstElem(IRState *irs); }; // Declaration of a symbol diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/mars.c --- a/dmd/mars.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/mars.c Sat Nov 29 21:25:43 2008 +0100 @@ -1196,9 +1196,9 @@ m->inlineScan(); } } +#endif if (global.errors) fatal(); -#endif // Generate output files for (i = 0; i < modules.dim; i++) diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/mars.h --- a/dmd/mars.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/mars.h Sat Nov 29 21:25:43 2008 +0100 @@ -345,7 +345,7 @@ void halt(); /*** Where to send error messages ***/ -#if IN_GCC +#if IN_GCC || IN_LLVM #define stdmsg stderr #else #define stdmsg stdout diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/mtype.c --- a/dmd/mtype.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/mtype.c Sat Nov 29 21:25:43 2008 +0100 @@ -3186,6 +3186,14 @@ return PTRSIZE * 2; } +// LDC added, no reason to align to 2*PTRSIZE +unsigned TypeDelegate::alignsize() +{ + // A Delegate consists of two ptr values, so align it on pointer size + // boundary + return PTRSIZE; +} + void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd/mtype.h --- a/dmd/mtype.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd/mtype.h Sat Nov 29 21:25:43 2008 +0100 @@ -451,6 +451,7 @@ Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); + unsigned alignsize(); // added in LDC void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *defaultInit(Loc loc); int isZeroInit(); diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/aggregate.h --- a/dmd2/aggregate.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/aggregate.h Sat Nov 29 21:25:43 2008 +0100 @@ -45,7 +45,6 @@ class ConstantStruct; class GlobalVariable; } -struct DUnion; struct AggregateDeclaration : ScopeDsymbol { @@ -264,9 +263,6 @@ Symbol *vtblsym; - // llvm - void offsetToIndex(Type* t, unsigned os, std::vector& result); - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } }; diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/attrib.c --- a/dmd2/attrib.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/attrib.c Sat Nov 29 21:25:43 2008 +0100 @@ -629,7 +629,6 @@ sc->flags = 0; aad.structalign = sc->structalign; aad.parent = ad; - for (unsigned i = 0; i < decl->dim; i++) { Dsymbol *s = (Dsymbol *)decl->data[i]; @@ -685,6 +684,9 @@ { VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; + // LDC + v->offset2 = sc->offset; + v->offset += sc->offset; // LDC diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/attrib.h --- a/dmd2/attrib.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/attrib.h Sat Nov 29 21:25:43 2008 +0100 @@ -50,7 +50,7 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); AttribDeclaration *isAttribDeclaration() { return this; } - void toObjFile(int multiobj); // compile to .obj file + virtual void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); }; diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/declaration.c --- a/dmd2/declaration.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/declaration.c Sat Nov 29 21:25:43 2008 +0100 @@ -618,6 +618,7 @@ // LDC anonDecl = NULL; + offset2 = 0; } Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/declaration.h --- a/dmd2/declaration.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/declaration.h Sat Nov 29 21:25:43 2008 +0100 @@ -279,6 +279,7 @@ // LDC AnonDeclaration* anonDecl; + unsigned offset2; }; /**************************************************************/ diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/expression.h --- a/dmd2/expression.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/expression.h Sat Nov 29 21:25:43 2008 +0100 @@ -653,6 +653,9 @@ int inlineCost(InlineCostState *ics); //Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); + + // LDC + virtual llvm::Constant *toConstElem(IRState *irs); }; // Declaration of a symbol diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/mars.c --- a/dmd2/mars.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/mars.c Sat Nov 29 21:25:43 2008 +0100 @@ -1220,9 +1220,9 @@ m->inlineScan(); } } +#endif if (global.errors) fatal(); -#endif // Generate output files for (i = 0; i < modules.dim; i++) diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/mars.h --- a/dmd2/mars.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/mars.h Sat Nov 29 21:25:43 2008 +0100 @@ -350,7 +350,7 @@ void halt(); /*** Where to send error messages ***/ -#if IN_GCC +#if IN_GCC || IN_LLVM #define stdmsg stderr #else #define stdmsg stdout diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/mtype.c --- a/dmd2/mtype.c Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/mtype.c Sat Nov 29 21:25:43 2008 +0100 @@ -3694,6 +3694,14 @@ return PTRSIZE * 2; } +// LDC added, no reason to align to 2*PTRSIZE +unsigned TypeDelegate::alignsize() +{ + // A Delegate consists of two ptr values, so align it on pointer size + // boundary + return PTRSIZE; +} + void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) diff -r 6e7a4c3b64d2 -r 340acf1535d0 dmd2/mtype.h --- a/dmd2/mtype.h Sat Nov 29 12:28:10 2008 +0100 +++ b/dmd2/mtype.h Sat Nov 29 21:25:43 2008 +0100 @@ -516,6 +516,7 @@ Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); + unsigned alignsize(); // added in LDC void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *defaultInit(Loc loc); int isZeroInit(); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/arrays.cpp --- a/gen/arrays.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/arrays.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -208,6 +208,9 @@ } ////////////////////////////////////////////////////////////////////////////////////////// + +// FIXME: this looks like it could use a cleanup + LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) { Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars()); @@ -241,6 +244,9 @@ Type* arrnext = arrinittype->nextOf(); const LLType* elemty = DtoType(arrinittype->nextOf()); + // true if there is a mismatch with one of the initializers + bool mismatch = false; + assert(arrinit->index.dim == arrinit->value.dim); for (unsigned i=0,j=0; i < tdim; ++i) { @@ -292,23 +298,51 @@ v = DtoConstInitializer(arrinit->loc, t->nextOf(), init); assert(v); + // global arrays of unions might have type mismatch for each element + // if there is any mismatch at all, we need to use a struct instead :/ + if (v->getType() != elemty) + mismatch = true; + inits[i] = v; if (Logger::enabled()) Logger::cout() << "llval: " << *v << '\n'; } Logger::println("building constant array"); + + LLConstant* constarr; const LLArrayType* arrty = LLArrayType::get(elemty,tdim); - LLConstant* constarr = LLConstantArray::get(arrty, inits); + + if (mismatch) + { + constarr = LLConstantStruct::get(inits); + } + else + { + constarr = LLConstantArray::get(arrty, inits); + } + +#if 0 + if (Logger::enabled()) + { + Logger::cout() << "array type: " << *arrty << '\n'; + size_t n = inits.size(); + for (size_t i=0; imodule); + LLGlobalVariable* gvar = new LLGlobalVariable(constarr->getType(),true,LLGlobalValue::InternalLinkage,constarr,".constarray",gIR->module); LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; + LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); + gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(elemty)); + return DtoConstSlice(DtoConstSize_t(tdim),gep); } @@ -795,24 +829,6 @@ } ////////////////////////////////////////////////////////////////////////////////////////// -LLConstant* DtoConstStaticArray(const LLType* t, LLConstant* c) -{ - const LLArrayType* at = isaArray(t); - assert(at); - - if (isaArray(at->getElementType())) - { - c = DtoConstStaticArray(at->getElementType(), c); - } - else { - assert(at->getElementType() == c->getType()); - } - std::vector initvals; - initvals.resize(at->getNumElements(), c); - return llvm::ConstantArray::get(at, initvals); -} - -////////////////////////////////////////////////////////////////////////////////////////// LLValue* DtoArrayLen(DValue* v) { Logger::println("DtoArrayLen"); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/arrays.h --- a/gen/arrays.h Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/arrays.h Sat Nov 29 21:25:43 2008 +0100 @@ -9,7 +9,6 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* si); LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr); -LLConstant* DtoConstStaticArray(const LLType* t, LLConstant* c); void DtoArrayCopySlices(DSliceValue* dst, DSliceValue* src); void DtoArrayCopyToSlice(DSliceValue* dst, DValue* src); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/classes.cpp --- a/gen/classes.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/classes.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -21,76 +21,163 @@ ////////////////////////////////////////////////////////////////////////////////////////// -static void LLVM_AddBaseClassInterfaces(ClassDeclaration* target, BaseClasses* bcs) +// 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) { - // add base class data members first - for (int j=0; jdim; j++) - { - BaseClass* bc = (BaseClass*)(bcs->data[j]); + 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); - // base *classes* might add more interfaces? - DtoResolveClass(bc->base); - LLVM_AddBaseClassInterfaces(target, &bc->base->baseclasses); + // 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; + } - // resolve interfaces while we're at it - if (bc->base->isInterfaceDeclaration()) + 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); + + // assign this iri to all base interfaces of this one + for (unsigned j = 0; j < b->baseInterfaces_dim; j++) + { + BaseClass *bc = &b->baseInterfaces[j]; + // add to map + if (irstruct->interfaceMap.find(bc->base) == irstruct->interfaceMap.end()) { - // don't add twice - if (target->ir.irStruct->interfaceMap.find(bc->base) == target->ir.irStruct->interfaceMap.end()) - { - Logger::println("adding interface '%s'", bc->base->toPrettyChars()); - IrInterface* iri = new IrInterface(bc); + irstruct->interfaceMap.insert(std::make_pair(bc->base, iri)); + } + } + + // build the interface vtable + b->fillVtbl(target, &b->vtbl, 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; - // add to map - target->ir.irStruct->interfaceMap.insert(std::make_pair(bc->base, iri)); - // add to ordered list - target->ir.irStruct->interfaceVec.push_back(iri); + // recurse into baseClasses + if (cd->baseClass) + { + add_class_data(target, cd->baseClass); + //offset = baseClass->structsize; + } - // Fill in vtbl[] - if (!target->isAbstract()) { - bc->fillVtbl(target, &bc->vtbl, 0); - } - } + // 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 LLVM_AddBaseClassData(IrStruct* irstruct, BaseClasses* bcs) +static void DtoResolveInterface(InterfaceDeclaration* cd) { - // add base class data members first - for (int j=0; jdim; j++) - { - BaseClass* bc = (BaseClass*)(bcs->data[j]); + if (cd->ir.resolved) return; + cd->ir.resolved = true; + + Logger::println("DtoResolveInterface(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); + LOG_SCOPE; - // interfaces never add data fields - if (bc->base->isInterfaceDeclaration()) - continue; + // get the TypeClass + assert(cd->type->ty == Tclass); + TypeClass* ts = (TypeClass*)cd->type; - // recursively add baseclass data - LLVM_AddBaseClassData(irstruct, &bc->base->baseclasses); + // create the IrStruct, we need somewhere to store the classInfo + assert(!cd->ir.irStruct); + IrStruct* irstruct = new IrStruct(cd); + cd->ir.irStruct = irstruct; - Array* arr = &bc->base->fields; - if (arr->dim == 0) - continue; - - Logger::println("Adding base class members of %s", bc->base->toChars()); + // handle base interfaces + if (cd->baseclasses.dim) + { + Logger::println("num baseclasses: %u", cd->baseclasses.dim); LOG_SCOPE; - for (int k=0; k < arr->dim; k++) { - VarDeclaration* v = (VarDeclaration*)(arr->data[k]); - Logger::println("Adding field: %s %s", v->type->toChars(), v->toChars()); - // init fields, used to happen in VarDeclaration::toObjFile - irstruct->addField(v); + for (int i=0; ibaseclasses.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); } } + + // 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; @@ -103,11 +190,20 @@ assert(cd->type->ty == Tclass); TypeClass* ts = (TypeClass*)cd->type; - // make sure the IrStruct is created - IrStruct* irstruct = cd->ir.irStruct; - if (!irstruct) { - irstruct = new IrStruct(ts); - cd->ir.irStruct = irstruct; + // 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 @@ -115,247 +211,45 @@ DtoResolveClass(cd->baseClass); } - // resolve interface vtables - /*if (cd->vtblInterfaces) { - Logger::println("Vtbl interfaces for '%s'", cd->toPrettyChars()); - LOG_SCOPE; - for (int i=0; i < cd->vtblInterfaces->dim; i++) { - BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; - ClassDeclaration *id = b->base; - Logger::println("Vtbl interface: '%s'", id->toPrettyChars()); - DtoResolveClass(id); - // Fill in vtbl[] - b->fillVtbl(cd, &b->vtbl, 1); - } - }*/ - // push state gIR->structs.push_back(irstruct); - gIR->classes.push_back(cd); - - // vector holding the field types - std::vector fieldtypes; // add vtable - ts->ir.vtblType = new llvm::PATypeHolder(llvm::OpaqueType::get()); - const LLType* vtabty = getPtrToType(ts->ir.vtblType->get()); - fieldtypes.push_back(vtabty); + irstruct->types.push_back(getPtrToType(irstruct->vtblTy.get())); + irstruct->index++; // add monitor - fieldtypes.push_back(getVoidPtrType()); - - // add base class data fields first - LLVM_AddBaseClassData(irstruct, &cd->baseclasses); - - // add own fields - Array* fields = &cd->fields; - for (int k=0; k < fields->dim; k++) - { - VarDeclaration* v = (VarDeclaration*)fields->data[k]; - Logger::println("Adding field: %s %s", v->type->toChars(), v->toChars()); - // init fields, used to happen in VarDeclaration::toObjFile - irstruct->addField(v); - } - - // then add other members of us, if any - if(cd->members) { - for (int k=0; k < cd->members->dim; k++) { - Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); - dsym->toObjFile(0); // TODO: multiobj - } - } - - // resolve class data fields (possibly unions) - Logger::println("doing class fields"); + irstruct->types.push_back(getVoidPtrType()); + irstruct->index++; - if (irstruct->offsets.empty()) - { - Logger::println("has no fields"); - } - else - { - Logger::println("has fields"); - unsigned prevsize = (unsigned)-1; - unsigned lastoffset = (unsigned)-1; - const LLType* fieldtype = NULL; - VarDeclaration* fieldinit = NULL; - size_t fieldpad = 0; - int idx = 0; - for (IrStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { - // first iteration - if (lastoffset == (unsigned)-1) { - lastoffset = i->first; - fieldtype = i->second.type; - fieldinit = i->second.var; - prevsize = getABITypeSize(fieldtype); - i->second.var->ir.irField->index = idx; - } - // colliding offset? - else if (lastoffset == i->first) { - size_t s = getABITypeSize(i->second.type); - if (s > prevsize) { - fieldpad += s - prevsize; - prevsize = s; - } - cd->ir.irStruct->hasUnions = true; - i->second.var->ir.irField->index = idx; - } - // intersecting offset? - else if (i->first < (lastoffset + prevsize)) { - size_t s = getABITypeSize(i->second.type); - assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size - cd->ir.irStruct->hasUnions = true; - i->second.var->ir.irField->index = idx; - i->second.var->ir.irField->indexOffset = (i->first - lastoffset) / s; - } - // fresh offset - else { - // commit the field - fieldtypes.push_back(fieldtype); - irstruct->defaultFields.push_back(fieldinit); - if (fieldpad) { - fieldtypes.push_back(llvm::ArrayType::get(LLType::Int8Ty, fieldpad)); - irstruct->defaultFields.push_back(NULL); - idx++; - } + // add class data fields and interface vtables recursively + add_class_data(cd, cd); - idx++; - - // start new - lastoffset = i->first; - fieldtype = i->second.type; - fieldinit = i->second.var; - prevsize = getABITypeSize(fieldtype); - i->second.var->ir.irField->index = idx; - fieldpad = 0; - } - } - fieldtypes.push_back(fieldtype); - irstruct->defaultFields.push_back(fieldinit); - if (fieldpad) { - fieldtypes.push_back(llvm::ArrayType::get(LLType::Int8Ty, fieldpad)); - irstruct->defaultFields.push_back(NULL); - } - } - - // populate interface map - { - Logger::println("Adding interfaces to '%s'", cd->toPrettyChars()); - LOG_SCOPE; - LLVM_AddBaseClassInterfaces(cd, &cd->baseclasses); - Logger::println("%d interfaces added", cd->ir.irStruct->interfaceVec.size()); - assert(cd->ir.irStruct->interfaceVec.size() == cd->ir.irStruct->interfaceMap.size()); - } - - // add interface vtables at the end - int interIdx = (int)fieldtypes.size(); - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - ClassDeclaration* id = iri->decl; - - // set vtbl type - TypeClass* itc = (TypeClass*)id->type; - const LLType* ivtblTy = itc->ir.vtblType->get(); - assert(ivtblTy); - if (Logger::enabled()) - Logger::cout() << "interface vtbl type: " << *ivtblTy << '\n'; - fieldtypes.push_back(getPtrToType(ivtblTy)); - - // fix the interface vtable type - assert(iri->vtblTy == NULL); - iri->vtblTy = new llvm::PATypeHolder(ivtblTy); - - // set index - iri->index = interIdx++; - } - Logger::println("%d interface vtables added", cd->ir.irStruct->interfaceVec.size()); - assert(cd->ir.irStruct->interfaceVec.size() == cd->ir.irStruct->interfaceMap.size()); + // check if errors occured while building interface vtables + if (global.errors) + fatal(); // create type - const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); + assert(irstruct->index == irstruct->types.size()); + const LLType* structtype = irstruct->build(); // refine abstract types for stuff like: class C {C next;} - assert(irstruct->recty != 0); - llvm::PATypeHolder& spa = irstruct->recty; - llvm::cast(spa.get())->refineAbstractTypeTo(structtype); - structtype = isaStruct(spa.get()); - - // make it official - if (!ts->ir.type) - ts->ir.type = new llvm::PATypeHolder(structtype); - else - *ts->ir.type = structtype; - spa = *ts->ir.type; + llvm::PATypeHolder* spa = ts->ir.type; + llvm::cast(spa->get())->refineAbstractTypeTo(structtype); + structtype = isaStruct(spa->get()); // name the type gIR->module->addTypeName(cd->mangle(), ts->ir.type->get()); - // create vtable type - llvm::GlobalVariable* svtblVar = 0; -#if OPAQUE_VTBLS - // void*[vtbl.dim] - const llvm::ArrayType* svtbl_ty - = llvm::ArrayType::get(getVoidPtrType(), cd->vtbl.dim); - -#else - std::vector sinits_ty; - - for (int k=0; k < cd->vtbl.dim; k++) - { - Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; - assert(dsym); - //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; + // refine vtable type - if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { - DtoResolveFunction(fd); - //assert(fd->type->ty == Tfunction); - //TypeFunction* tf = (TypeFunction*)fd->type; - //const LLType* fpty = getPtrToType(tf->ir.type->get()); - const llvm::FunctionType* vfty = DtoBaseFunctionType(fd); - const LLType* vfpty = getPtrToType(vfty); - sinits_ty.push_back(vfpty); - } - else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) { - Logger::println("*** ClassDeclaration in vtable: %s", cd2->toChars()); - const LLType* cinfoty; - if (cd->isInterfaceDeclaration()) { - cinfoty = DtoInterfaceInfoType(); - } - else if (cd != ClassDeclaration::classinfo) { - cinfoty = ClassDeclaration::classinfo->type->ir.type->get(); - } - else { - // this is the ClassInfo class, the type is this type - cinfoty = ts->ir.type->get(); - } - const LLType* cty = getPtrToType(cinfoty); - sinits_ty.push_back(cty); - } - else - assert(0); - } - - // get type - assert(!sinits_ty.empty()); - const llvm::StructType* svtbl_ty = llvm::StructType::get(sinits_ty); -#endif - - // refine for final vtable type - llvm::cast(ts->ir.vtblType->get())->refineAbstractTypeTo(svtbl_ty); - -#if !OPAQUE_VTBLS - // name vtbl type - std::string styname(cd->mangle()); - styname.append("__vtblType"); - gIR->module->addTypeName(styname, svtbl_ty); -#endif + // void*[vtbl.dim] + llvm::cast(irstruct->vtblTy.get())->refineAbstractTypeTo(LLArrayType::get(getVoidPtrType(), cd->vtbl.dim)); // log - //Logger::cout() << "final class type: " << *ts->ir.type->get() << '\n'; + Logger::cout() << "final class type: " << *ts->ir.type->get() << '\n'; // pop state - gIR->classes.pop_back(); gIR->structs.pop_back(); // queue declare @@ -364,12 +258,79 @@ ////////////////////////////////////////////////////////////////////////////////////////// -void DtoDeclareClass(ClassDeclaration* cd) +static void DtoDeclareInterface(InterfaceDeclaration* cd) { if (cd->ir.declared) return; cd->ir.declared = true; - Logger::println("DtoDeclareClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); + 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 (cd->getModule() == gIR->dmodule || DtoIsTemplateInstance(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()); @@ -381,7 +342,6 @@ IrStruct* irstruct = cd->ir.irStruct; gIR->structs.push_back(irstruct); - gIR->classes.push_back(cd); bool needs_definition = false; if (cd->getModule() == gIR->dmodule || DtoIsTemplateInstance(cd)) { @@ -390,82 +350,344 @@ llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(cd); - // interfaces have no static initializer - // same goes for abstract classes - if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) { - // vtable - std::string varname("_D"); - varname.append(cd->mangle()); - varname.append("6__vtblZ"); - cd->ir.irStruct->vtbl = new llvm::GlobalVariable(ts->ir.vtblType->get(), true, _linkage, 0, varname, gIR->module); - } + // 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 (!cd->ir.irStruct->interfaceVec.empty()) { + 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, cd->ir.irStruct->interfaceVec.size()); + const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size()); // declare global - irstruct->interfaceInfosTy = arrTy; irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, _linkage, NULL, nam, gIR->module); } - // interfaces have no static initializer - // same goes for abstract classes - if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) { - // interface vtables - unsigned idx = 0; - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - ClassDeclaration* id = iri->decl; + // 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"); + std::string nam("_D"); + nam.append(cd->mangle()); + nam.append("11__interface"); + nam.append(id->mangle()); + nam.append("6__vtblZ"); - assert(iri->vtblTy); - iri->vtbl = new llvm::GlobalVariable(iri->vtblTy->get(), true, _linkage, 0, nam, gIR->module); - LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; - iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); - idx++; - } + iri->vtbl = new llvm::GlobalVariable(iri->vtblInitTy.get(), true, _linkage, 0, nam, gIR->module); - // init - std::string initname("_D"); - initname.append(cd->mangle()); - initname.append("6__initZ"); - - llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->ir.type->get(), true, _linkage, NULL, initname, gIR->module); - cd->ir.irStruct->init = initvar; + // always create interfaceinfos + LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; + iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); + idx++; } - gIR->classes.pop_back(); + // 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); - // typeinfo + // do typeinfo ? if (needs_definition) DtoTypeInfoOf(cd->type, false); } ////////////////////////////////////////////////////////////////////////////////////////// -void DtoConstInitClass(ClassDeclaration* cd) +void addZeros(std::vector& inits, size_t pos, size_t offset); // irstruct.cpp + +////////////////////////////////////////////////////////////////////////////// + +// assigns constant initializers to fields introduced by cd +static void init_field_inits(ClassDeclaration* cd) +{ + size_t n = cd->fields.dim; + for (size_t i=0; ifields.data[i]; + IrField* f = v->ir.irField; + assert(!f->constInit); + f->constInit = DtoConstFieldInitializer(v->loc, v->type, v->init); + } +} + +////////////////////////////////////////////////////////////////////////////// + +// adds data fields and interface vtables to the constant initializer of class cd +static size_t init_class_initializer(std::vector& 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", cd->toChars(), target->toChars()); + LOG_SCOPE; + + // add default fields + VarDeclaration** fields = (VarDeclaration**)cd->fields.data; + size_t nfields = cd->fields.dim; + + std::vector defVars; + defVars.reserve(nfields); + + size_t lastoffset = offsetbegin; // vtbl,monitor + size_t lastsize = 0; + + // find fields that contribute to default + for (size_t i=0; ioffset; + size_t size = var->type->size(); + if (offset >= lastoffset+lastsize) + { + Logger::println(" added"); + lastoffset = offset; + lastsize = size; + defVars.push_back(var); + } + } + + // 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; itype->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 + assert(var->ir.irField->constInit); + 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 + IrStruct* irstruct = cd->ir.irStruct; + + size_t nvtbls = cd->vtblInterfaces->dim; + for(size_t i=0; ivtblInterfaces->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 += PTRSIZE; + 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 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 (fd->isAbstract()) + { + 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(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 inits; + std::vector infoInits(3); + + // go through each interface + size_t ninter = irstruct->interfaceVec.size(); + for (size_t i=0; iinterfaceVec[i]; + Logger::println("interface %s", iri->decl->toChars()); + + // build vtable intializer for this interface implementation + Array& arr = iri->base->vtbl; + 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::get(infoInits)); + } +} + +////////////////////////////////////////////////////////////////////////////// + +static void DtoConstInitInterface(InterfaceDeclaration* cd) { if (cd->ir.initialized) return; cd->ir.initialized = true; @@ -473,281 +695,141 @@ Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; - IrStruct* irstruct = cd->ir.irStruct; - 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->ir.type->get()); -#if OPAQUE_VTBLS - const llvm::ArrayType* vtbltype = isaArray(ts->ir.vtblType->get()); -#else - const llvm::StructType* vtbltype = isaStruct(ts->ir.vtblType->get()); -#endif + init_class_interface_vtbl_initializers(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; - LLConstant* finit = DtoConstFieldInitializer(so->var->loc, so->var->type, so->var->init); - so->init = finit; - so->var->ir.irField->constInit = finit; - } +////////////////////////////////////////////////////////////////////////////// - // fill out fieldtypes/inits - std::vector fieldinits; - - // first field is always the vtable - if (cd->isAbstract() || cd->isInterfaceDeclaration()) - { - const LLType* ptrTy = getPtrToType(ts->ir.vtblType->get()); - fieldinits.push_back(llvm::Constant::getNullValue(ptrTy)); - } - else +void DtoConstInitClass(ClassDeclaration* cd) +{ + if (InterfaceDeclaration* it = cd->isInterfaceDeclaration()) { - assert(cd->ir.irStruct->vtbl != 0); - fieldinits.push_back(cd->ir.irStruct->vtbl); - } - - // then comes monitor - fieldinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); - - // go through the field inits and build the default initializer - size_t nfi = irstruct->defaultFields.size(); - for (size_t i=0; idefaultFields[i]) { - c = irstruct->defaultFields[i]->ir.irField->constInit; - assert(c); - } - else { - const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i+2)); - assert(arrty); - std::vector vals(arrty->getNumElements(), llvm::ConstantInt::get(LLType::Int8Ty, 0, false)); - c = llvm::ConstantArray::get(arrty, vals); - } - fieldinits.push_back(c); - } - - // last comes interface vtables - const llvm::StructType* infoTy = DtoInterfaceInfoType(); - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - iri->infoTy = infoTy; - - if (cd->isAbstract() || cd->isInterfaceDeclaration()) - { - fieldinits.push_back(llvm::Constant::getNullValue(structtype->getElementType(iri->index))); - } - else - { - assert(iri->vtbl); - fieldinits.push_back(iri->vtbl); - } + DtoConstInitInterface(it); + return; } - // generate initializer -#if 0 - //Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; - assert(fieldinits.size() == structtype->getNumElements()); - for(size_t i=0; igetNumElements(); ++i) { - Logger::cout() << "s#" << i << " = " << *structtype->getElementType(i) << '\n'; - Logger::cout() << "i#" << i << " = " << *fieldinits[i] << '\n'; - assert(fieldinits[i]->getType() == structtype->getElementType(i)); - } -#endif + if (cd->ir.initialized) return; + cd->ir.initialized = true; -#if 0 - for(size_t i=0; itoPrettyChars(), cd->loc.toChars()); + LOG_SCOPE; - LLConstant* _init = llvm::ConstantStruct::get(structtype, fieldinits); - assert(_init); - cd->ir.irStruct->constInit = _init; - - // abstract classes have no static vtable - // neither do interfaces (on their own, the implementing class supplies the vtable) - if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) - { - // generate vtable initializer - std::vector sinits; + assert(!cd->isInterfaceDeclaration()); - 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 OPAQUE_VTBLS - const LLType* targetTy = getVoidPtrType(); - #else - const LLType* targetTy = vtbltype->getElementType(k); - #endif + // make sure the baseclass is const initialized + if (cd->baseClass) + DtoForceConstInitDsymbol(cd->baseClass); - LLConstant* c = NULL; - // virtual method - if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { - DtoForceDeclareDsymbol(fd); - assert(fd->ir.irFunc->func); - c = llvm::cast(fd->ir.irFunc->func); - } - // classinfo - else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) { - assert(cd->ir.irStruct->classInfo); - c = cd->ir.irStruct->classInfo; - } - assert(c != NULL); + // get IrStruct + IrStruct* irstruct = cd->ir.irStruct; + gIR->structs.push_back(irstruct); - // cast if necessary (overridden method) - if (c->getType() != targetTy) - c = llvm::ConstantExpr::getBitCast(c, targetTy); - sinits.push_back(c); - } - #if OPAQUE_VTBLS - const llvm::ArrayType* svtbl_ty = isaArray(ts->ir.vtblType->get()); - cd->ir.irStruct->constVtbl = llvm::ConstantArray::get(svtbl_ty, sinits); - #else - const llvm::StructType* svtbl_ty = isaStruct(ts->ir.vtblType->get()); - LLConstant* cvtblInit = llvm::ConstantStruct::get(svtbl_ty, sinits); - cd->ir.irStruct->constVtbl = llvm::cast(cvtblInit); - #endif + // 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); - // create interface vtable const initalizers - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - BaseClass* b = iri->base; - - ClassDeclaration* id = iri->decl; - assert(id->type->ty == Tclass); - TypeClass* its = (TypeClass*)id->type; - - #if OPAQUE_VTBLS - const llvm::ArrayType* ivtbl_ty = isaArray(its->ir.vtblType->get()); - #else - const llvm::StructType* ivtbl_ty = isaStruct(its->ir.vtblType->get()); - #endif - - // generate interface info initializer - std::vector infoInits; - - // classinfo - assert(id->ir.irStruct->classInfo); - LLConstant* c = id->ir.irStruct->classInfo; - infoInits.push_back(c); + // make sure each field knows its default initializer + init_field_inits(cd); - // vtbl - const LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::Int8Ty)); - c = llvm::ConstantExpr::getBitCast(iri->vtbl, byteptrptrty); - c = DtoConstSlice(DtoConstSize_t(b->vtbl.dim), c); - infoInits.push_back(c); - - // offset - assert(iri->index >= 0); - size_t ioff = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(iri->index); - infoInits.push_back(DtoConstUint(ioff)); - - // create interface info initializer constant - iri->infoInit = llvm::cast(llvm::ConstantStruct::get(iri->infoTy, infoInits)); - - // generate vtable initializer - std::vector iinits; + // build initializer list + std::vector inits; + inits.reserve(irstruct->varDecls.size()); - // add interface info - #if OPAQUE_VTBLS - const LLType* targetTy = getVoidPtrType(); - iinits.push_back(llvm::ConstantExpr::getBitCast(iri->info, targetTy)); - #else - iinits.push_back(iri->info); - #endif - - 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]; + // vtable is always first + assert(irstruct->vtbl != 0); + inits.push_back(irstruct->vtbl); - // error on unimplemented functions, error was already generated earlier - if(!dsym) - fatal(); + // then comes monitor + inits.push_back(LLConstant::getNullValue(getVoidPtrType())); - FuncDeclaration* fd = dsym->isFuncDeclaration(); - assert(fd); - DtoForceDeclareDsymbol(fd); - assert(fd->ir.irFunc->func); - LLConstant* c = llvm::cast(fd->ir.irFunc->func); - - #if !OPAQUE_VTBLS - const LLType* targetTy = iri->vtblTy->getContainedType(k); - #endif + // recursively do data and interface vtables + init_class_initializer(inits, cd, cd, 2 * PTRSIZE); - // we have to bitcast, as the type created in ResolveClass expects a different this type - c = llvm::ConstantExpr::getBitCast(c, targetTy); - iinits.push_back(c); -// if (Logger::enabled()) -// Logger::cout() << "c: " << *c << '\n'; - } + // build vtable initializer + init_class_vtbl_initializer(cd); + + // build interface vtables + init_class_interface_vtbl_initializers(cd); - #if OPAQUE_VTBLS -// if (Logger::enabled()) -// Logger::cout() << "n: " << iinits.size() << " ivtbl_ty: " << *ivtbl_ty << '\n'; - LLConstant* civtblInit = llvm::ConstantArray::get(ivtbl_ty, iinits); - iri->vtblInit = llvm::cast(civtblInit); - #else - LLConstant* civtblInit = llvm::ConstantStruct::get(ivtbl_ty, iinits); - iri->vtblInit = llvm::cast(civtblInit); - #endif - } - } - // we always generate interfaceinfos as best we can - else + // build constant from inits + irstruct->constInit = LLConstantStruct::get(inits); // classes are never packed + + // refine __initZ global type to the one of the initializer + llvm::cast(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType()); + + if (Logger::enabled()) { - // TODO: this is duplicated code from right above... I'm just too lazy to generalise it right now :/ - // create interface vtable const initalizers - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - BaseClass* b = iri->base; - - ClassDeclaration* id = iri->decl; - assert(id->type->ty == Tclass); - TypeClass* its = (TypeClass*)id->type; - - // generate interface info initializer - std::vector infoInits; - - // classinfo - assert(id->ir.irStruct->classInfo); - LLConstant* c = id->ir.irStruct->classInfo; - infoInits.push_back(c); - - // vtbl - const LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::Int8Ty)); - c = DtoConstSlice(DtoConstSize_t(0), getNullPtr(byteptrptrty)); - infoInits.push_back(c); - - // offset - assert(iri->index >= 0); - size_t ioff = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(iri->index); - infoInits.push_back(DtoConstUint(ioff)); - - // create interface info initializer constant - iri->infoInit = llvm::cast(llvm::ConstantStruct::get(iri->infoTy, infoInits)); - } + 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->classes.pop_back(); gIR->structs.pop_back(); } ////////////////////////////////////////////////////////////////////////////////////////// +static void DefineInterfaceInfos(IrStruct* irstruct) +{ + // always do interface info array when possible + std::vector infoInits; + infoInits.reserve(irstruct->interfaceVec.size()); + + for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) + { + IrInterface* iri = *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 (cd->getModule() == gIR->dmodule || DtoIsTemplateInstance(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; @@ -758,46 +840,48 @@ assert(cd->type->ty == Tclass); TypeClass* ts = (TypeClass*)cd->type; - if (cd->getModule() == gIR->dmodule || DtoIsTemplateInstance(cd)) { + IrStruct* irstruct = cd->ir.irStruct; - // interfaces don't have static initializer/vtable - // neither do abstract classes - if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) - { - cd->ir.irStruct->init->setInitializer(cd->ir.irStruct->constInit); - cd->ir.irStruct->vtbl->setInitializer(cd->ir.irStruct->constVtbl); + assert(cd->getModule() == gIR->dmodule || DtoIsTemplateInstance(cd)); - // initialize interface vtables - IrStruct* irstruct = cd->ir.irStruct; - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - iri->vtbl->setInitializer(iri->vtblInit); - } - } + // 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; + } - // always do interface info array when possible - IrStruct* irstruct = cd->ir.irStruct; - std::vector infoInits; - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - infoInits.push_back(iri->infoInit); - } - // set initializer - if (!infoInits.empty()) - { - LLConstant* arrInit = llvm::ConstantArray::get(irstruct->interfaceInfosTy, infoInits); - irstruct->interfaceInfos->setInitializer(arrInit); - } - else - { - assert(irstruct->interfaceInfos == NULL); - } + // 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; iinterfaceVec[i]; + Logger::println("interface %s", iri->base->base->toChars()); + assert(iri->vtblInit); - // generate classinfo - DtoDefineClassInfo(cd); + // refine the init type + llvm::cast(iri->vtblInitTy.get())->refineAbstractTypeTo(iri->vtblInit->getType()); + + // apply initializer + assert(iri->vtbl); + iri->vtbl->setInitializer(iri->vtblInit); } + + DefineInterfaceInfos(irstruct); + + // generate classinfo + DtoDefineClassInfo(cd); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -825,7 +909,8 @@ else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocclass"); - mem = gIR->CreateCallOrInvoke(fn, tc->sym->ir.irStruct->classInfo, ".newclass_gc_alloc")->get(); + 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"); } @@ -838,7 +923,7 @@ Logger::println("Resolving outer class"); LOG_SCOPE; DValue* thisval = newexp->thisexp->toElem(gIR); - size_t idx = 2 + tc->sym->vthis->ir.irField->index; + size_t idx = tc->sym->vthis->ir.irField->index; LLValue* src = thisval->getRVal(); LLValue* dst = DtoGEPi(mem,0,idx,"tmp"); if (Logger::enabled()) @@ -855,7 +940,7 @@ LLValue* nest = DtoNestedContext(loc, tc->sym); // store into right location - size_t idx = 2 + tc->sym->vthis->ir.irField->index; + size_t idx = tc->sym->vthis->ir.irField->index; LLValue* gep = DtoGEPi(mem,0,idx,"tmp"); DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep); } @@ -877,16 +962,21 @@ void DtoInitClass(TypeClass* tc, LLValue* dst) { + DtoForceConstInitDsymbol(tc->sym); + size_t presz = 2*getABITypeSize(DtoSize_t()); uint64_t n = getABITypeSize(tc->ir.type->get()) - presz; // set vtable field seperately, this might give better optimization assert(tc->sym->ir.irStruct->vtbl); - DtoStore(tc->sym->ir.irStruct->vtbl, DtoGEPi(dst,0,0,"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 - LLValue* tmp = DtoGEPi(dst,0,1,"monitor"); - DtoStore(llvm::Constant::getNullValue(tmp->getType()->getContainedType(0)), tmp); + tmp = DtoGEPi(dst,0,1,"monitor"); + val = llvm::Constant::getNullValue(tmp->getType()->getContainedType(0)); + DtoStore(val, tmp); // done? if (n == 0) @@ -894,7 +984,6 @@ // copy the rest from the static initializer assert(tc->sym->ir.irStruct->init); - assert(dst->getType() == tc->sym->ir.irStruct->init->getType()); LLValue* dstarr = DtoGEPi(dst,0,2,"tmp"); LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->init,0,2,"tmp"); @@ -923,12 +1012,15 @@ 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(); @@ -936,36 +1028,67 @@ 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; - if (tc->sym->isInterfaceDeclaration()) { + // 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(); + 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 DtoCastInterfaceToObject(val, _to); } - else if (!tc->sym->isInterfaceDeclaration() && tc->sym->isBaseOf(fc->sym,NULL)) { + // 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); @@ -1100,19 +1223,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector& result) -{ - unsigned idx = 0; - unsigned r = LLVM_ClassOffsetToIndex(this, os, idx); - assert(r != (unsigned)-1 && "Offset not found in any aggregate field"); - // vtable is 0, monitor is 1 - r += 2; - // the final index was not pushed - result.push_back(r); -} - -////////////////////////////////////////////////////////////////////////////////////////// - LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) { Logger::println("indexing class field %s:", vd->toPrettyChars()); @@ -1125,17 +1235,31 @@ IrField* field = vd->ir.irField; assert(field); - unsigned idx = field->index + 2; // vtbl & monitor - unsigned off = field->indexOffset; - + // get the start pointer const LLType* st = DtoType(cd->type); + // cast to the struct type src = DtoBitCast(src, st); - LLValue* val = DtoGEPi(src, 0,idx); - val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); + // 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); - if (off) - val = DtoGEPi1(val, off); + // 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'; @@ -1155,8 +1279,9 @@ if (Logger::enabled()) Logger::cout() << "vthis: " << *vthis << '\n'; - LLValue* funcval; - funcval = DtoGEPi(vthis, 0, 0, "tmp"); + LLValue* funcval = vthis; + if (!fdecl->isMember2()->isInterfaceDeclaration()) + funcval = DtoGEPi(funcval, 0, 0, "tmp"); funcval = DtoLoad(funcval); funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toPrettyChars()); funcval = DtoLoad(funcval); @@ -1164,11 +1289,9 @@ if (Logger::enabled()) Logger::cout() << "funcval: " << *funcval << '\n'; -#if OPAQUE_VTBLS funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); if (Logger::enabled()) Logger::cout() << "funcval casted: " << *funcval << '\n'; -#endif return funcval; } @@ -1177,8 +1300,10 @@ void DtoDeclareClassInfo(ClassDeclaration* cd) { - if (cd->ir.irStruct->classDeclared) return; - cd->ir.irStruct->classDeclared = true; + IrStruct* irstruct = cd->ir.irStruct; + + if (irstruct->classInfoDeclared) return; + irstruct->classInfoDeclared = true; Logger::println("DtoDeclareClassInfo(%s)", cd->toChars()); LOG_SCOPE; @@ -1193,9 +1318,7 @@ else gname.append("11__InterfaceZ"); - const LLType* st = cinfo->type->ir.type->get(); - - cd->ir.irStruct->classInfo = new llvm::GlobalVariable(st, false, DtoLinkage(cd), NULL, gname, gIR->module); + irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, DtoLinkage(cd), NULL, gname, gIR->module); } static LLConstant* build_offti_entry(ClassDeclaration* cd, VarDeclaration* vd) @@ -1206,8 +1329,8 @@ types.push_back(DtoSize_t()); assert(vd->ir.irField); - assert(vd->ir.irField->index >= 0); - size_t offset = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(vd->ir.irField->index+2); + size_t offset = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(vd->ir.irField->index); + offset += vd->ir.irField->unionOffset; inits.push_back(DtoConstSize_t(offset)); LLConstant* c = DtoTypeInfoOf(vd->type, true); @@ -1227,24 +1350,15 @@ assert(initTy); std::vector arrayInits; - for (ClassDeclaration *cd2 = cd; cd2; cd2 = cd2->baseClass) - { - if (cd2->members) + + VarDeclaration** fields = &cd->ir.irStruct->varDecls[0]; + size_t nvars = cd->ir.irStruct->varDecls.size(); + + for (size_t i=0; imembers->dim; i++) - { - Dsymbol *sm = (Dsymbol *)cd2->members->data[i]; - if (VarDeclaration* vd = sm->isVarDeclaration()) // is this enough? - { - if (!vd->isDataseg()) // static members dont have an offset! - { - LLConstant* c = build_offti_entry(cd, vd); - assert(c); - arrayInits.push_back(c); - } - } - } - } + LLConstant* c = build_offti_entry(cd, fields[i]); + assert(c); + arrayInits.push_back(c); } size_t ninits = arrayInits.size(); @@ -1336,21 +1450,23 @@ // void *defaultConstructor; // } - if (cd->ir.irStruct->classDefined) return; - cd->ir.irStruct->classDefined = true; + 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(cd->ir.irStruct->classInfo); + assert(ir->classInfo); TypeClass* cdty = (TypeClass*)cd->type; if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) { - assert(cd->ir.irStruct->init); - assert(cd->ir.irStruct->constInit); - assert(cd->ir.irStruct->vtbl); - assert(cd->ir.irStruct->constVtbl); + assert(ir->init); + assert(ir->constInit); + assert(ir->vtbl); + assert(ir->constVtbl); } // holds the list of initializers for llvm @@ -1381,8 +1497,9 @@ c = defc->getOperand(2); } else { - c = llvm::ConstantExpr::getBitCast(cd->ir.irStruct->init, byteptrty); - size_t initsz = getABITypeSize(cd->ir.irStruct->constInit->getType()); + c = llvm::ConstantExpr::getBitCast(ir->init, byteptrty); + //Logger::cout() << *ir->constInit->getType() << std::endl; + size_t initsz = getABITypeSize(ir->constInit->getType()); c = DtoConstSlice(DtoConstSize_t(initsz), c); } inits.push_back(c); @@ -1405,27 +1522,23 @@ } else { const LLType* byteptrptrty = getPtrToType(byteptrty); - assert(!cd->ir.irStruct->vtbl->getType()->isAbstract()); c = llvm::ConstantExpr::getBitCast(cd->ir.irStruct->vtbl, byteptrptrty); - assert(!cd->ir.irStruct->constVtbl->getType()->isAbstract()); - size_t vtblsz = 0; - llvm::ConstantArray* constVtblArray = llvm::dyn_cast(cd->ir.irStruct->constVtbl); - if(constVtblArray) { - vtblsz = constVtblArray->getType()->getNumElements(); - } + + assert(ir->constVtbl); + size_t vtblsz = ir->constVtbl->getNumOperands(); c = DtoConstSlice(DtoConstSize_t(vtblsz), c); } inits.push_back(c); // interfaces array IrStruct* irstruct = cd->ir.irStruct; - if (cd->isInterfaceDeclaration() || !irstruct->interfaceInfos || cd->isAbstract()) { + if (!irstruct->interfaceInfos) { c = defc->getOperand(5); } else { const LLType* t = defc->getOperand(5)->getType()->getContainedType(1); c = llvm::ConstantExpr::getBitCast(irstruct->interfaceInfos, t); - size_t iisz = irstruct->interfaceInfosTy->getNumElements(); + size_t iisz = irstruct->interfaceVec.size(); c = DtoConstSlice(DtoConstSize_t(iisz), c); } inits.push_back(c); @@ -1521,10 +1634,13 @@ }*/ // build the initializer - const llvm::StructType* st = isaStruct(defc->getType()); - LLConstant* finalinit = llvm::ConstantStruct::get(st, inits); + LLConstant* finalinit = llvm::ConstantStruct::get(inits); //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; + ir->constClassInfo = finalinit; - cd->ir.irStruct->constClassInfo = finalinit; - cd->ir.irStruct->classInfo->setInitializer(finalinit); + // refine the type + llvm::cast(ir->classInfoOpaque.get())->refineAbstractTypeTo(finalinit->getType()); + + // apply initializer + ir->classInfo->setInitializer(finalinit); } diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/functions.cpp --- a/gen/functions.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/functions.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -97,16 +97,8 @@ } if (dVararg) { - ClassDeclaration* ti = Type::typeinfo; - ti->toObjFile(0); // TODO: multiobj - DtoForceConstInitDsymbol(ti); - assert(ti->ir.irStruct->constInit); - std::vector types; - types.push_back(DtoSize_t()); - types.push_back(getPtrToType(getPtrToType(ti->ir.irStruct->constInit->getType()))); - const LLType* t1 = llvm::StructType::get(types); - paramvec.push_back(t1); - paramvec.push_back(getPtrToType(LLType::Int8Ty)); + paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments + paramvec.push_back(getVoidPtrType()); // _argptr } // number of formal params @@ -286,7 +278,7 @@ Logger::println("isMember = this is: %s", ad->type->toChars()); thisty = DtoType(ad->type); //Logger::cout() << "this llvm type: " << *thisty << '\n'; - if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->recty.get())) + if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->type->ir.type->get())) thisty = getPtrToType(thisty); } else { @@ -547,35 +539,36 @@ } // we never reference parameters of function prototypes + std::string str; if (!declareOnly) { // name parameters llvm::Function::arg_iterator iarg = func->arg_begin(); if (f->retInPtr) { - iarg->setName(".sretarg"); + iarg->setName(".sret_arg"); fdecl->ir.irFunc->retArg = iarg; ++iarg; } if (f->usesThis) { - iarg->setName("this"); + iarg->setName(".this_arg"); fdecl->ir.irFunc->thisArg = iarg; assert(fdecl->ir.irFunc->thisArg); ++iarg; } else if (f->usesNest) { - iarg->setName(".nest"); + iarg->setName(".nest_arg"); fdecl->ir.irFunc->nestArg = iarg; assert(fdecl->ir.irFunc->nestArg); ++iarg; } if (f->linkage == LINKd && f->varargs == 1) { - iarg->setName("_arguments"); + iarg->setName("._arguments"); fdecl->ir.irFunc->_arguments = iarg; ++iarg; - iarg->setName("_argptr"); + iarg->setName("._argptr"); fdecl->ir.irFunc->_argptr = iarg; ++iarg; } @@ -597,7 +590,10 @@ assert(!argvd->ir.irLocal); argvd->ir.irLocal = new IrLocal(argvd); argvd->ir.irLocal->value = iarg; - iarg->setName(argvd->ident->toChars()); + + str = argvd->ident->toChars(); + str.append("_arg"); + iarg->setName(str); k++; } @@ -671,8 +667,7 @@ if (fd->isMain()) gIR->emitMain = true; - std::string entryname("entry_"); - entryname.append(fd->toPrettyChars()); + std::string entryname("entry"); llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(entryname,func); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endentry",func); @@ -710,7 +705,7 @@ LLValue* thisvar = irfunction->thisArg; assert(thisvar); - LLValue* thismem = DtoAlloca(thisvar->getType(), ".this"); + LLValue* thismem = DtoAlloca(thisvar->getType(), "this"); DtoStore(thisvar, thismem); irfunction->thisArg = thismem; @@ -760,7 +755,7 @@ if (!refout && (!DtoIsPassedByRef(vd->type) || lazy)) { LLValue* a = irloc->value; - LLValue* v = DtoAlloca(a->getType(), "."+a->getName()); + LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars()); DtoStore(a,v); irloc->value = v; } @@ -822,7 +817,7 @@ ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); assert(cd); assert(cd->vthis); - src = DtoLoad(DtoGEPi(thisval, 0,2+cd->vthis->ir.irField->index, ".vthis")); + src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); } DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE)); } diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/irstate.h --- a/gen/irstate.h Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/irstate.h Sat Nov 29 21:25:43 2008 +0100 @@ -23,6 +23,7 @@ struct Module; struct TypeStruct; struct BaseClass; +struct AnonDeclaration; struct EnclosingHandler; struct IrModule; @@ -147,10 +148,6 @@ StructVector structs; IrStruct* topstruct(); - // classes TODO move into IRClass - typedef std::vector ClassDeclVec; - ClassDeclVec classes; - // D main function bool emitMain; llvm::Function* mainFunc; diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/llvmhelpers.cpp --- a/gen/llvmhelpers.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/llvmhelpers.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -338,7 +338,7 @@ { ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration(); LLValue* val = DtoLoad(irfunc->thisArg); - ctx = DtoLoad(DtoGEPi(val, 0,2+cd->vthis->ir.irField->index, ".vthis")); + ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); } else ctx = irfunc->nestArg; @@ -374,7 +374,7 @@ if (!cd || !cd->vthis) return getNullPtr(getVoidPtrType()); LLValue* val = DtoLoad(irfunc->thisArg); - return DtoLoad(DtoGEPi(val, 0,2+cd->vthis->ir.irField->index, ".vthis")); + return DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis")); } else { @@ -964,73 +964,68 @@ if (vd->ir.initialized) return; vd->ir.initialized = gIR->dmodule; - Logger::println("* DtoConstInitGlobal(%s)", vd->toChars()); + Logger::println("DtoConstInitGlobal(%s) @ %s", vd->toChars(), vd->locToChars()); LOG_SCOPE; - bool emitRTstaticInit = false; + // if the variable is a function local static variable with a runtime initializer + // we must do lazy initialization, which involves a boolean flag to make sure it happens only once + // FIXME: I don't think it's thread safe ... + + bool doLazyInit = false; + Dsymbol* par = vd->toParent2(); - LLConstant* _init = 0; - if (vd->parent && vd->parent->isFuncDeclaration() && vd->init && vd->init->isExpInitializer()) { - _init = DtoConstInitializer(vd->loc, vd->type, NULL); - emitRTstaticInit = true; - } - else { - _init = DtoConstInitializer(vd->loc, vd->type, vd->init); + if (par && par->isFuncDeclaration() && vd->init) + { + if (ExpInitializer* einit = vd->init->isExpInitializer()) + { + if (!einit->exp->isConst()) + { + // mark as needing lazy now + doLazyInit = true; + } + } } - const LLType* _type = DtoType(vd->type); - Type* t = vd->type->toBasetype(); - - //Logger::cout() << "initializer: " << *_init << '\n'; - if (_type != _init->getType()) { - if (Logger::enabled()) - Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n"; + // if we do lazy init, we start out with an undefined initializer + LLConstant* initVal; + if (doLazyInit) + { + initVal = llvm::UndefValue::get(DtoType(vd->type)); + } + // otherwise we build it + else + { + initVal = DtoConstInitializer(vd->loc, vd->type, vd->init); + } - // zero initalizer - if (_init->isNullValue()) - _init = llvm::Constant::getNullValue(_type); - // pointer to global constant (struct.init) - else if (llvm::isa(_init)) - { - assert(_init->getType()->getContainedType(0) == _type); - llvm::GlobalVariable* gv = llvm::cast(_init); - assert(t->ty == Tstruct); - TypeStruct* ts = (TypeStruct*)t; - assert(ts->sym->ir.irStruct->constInit); - _init = ts->sym->ir.irStruct->constInit; - } - // array single value init - else if (isaArray(_type)) - { - _init = DtoConstStaticArray(_type, _init); - } - else { - if (Logger::enabled()) - Logger::cout() << "Unexpected initializer type: " << *_type << '\n'; - //assert(0); - } - } + // set the initializer if appropriate + IrGlobal* glob = vd->ir.irGlobal; + llvm::GlobalVariable* gvar = llvm::cast(glob->value); + + // refine the global's opaque type to the type of the initializer + llvm::cast(glob->type.get())->refineAbstractTypeTo(initVal->getType()); + + glob->constInit = initVal; bool istempl = false; if ((vd->storage_class & STCcomdat) || (vd->parent && DtoIsTemplateInstance(vd->parent))) { istempl = true; } - if (_init && _init->getType() != _type) - _type = _init->getType(); - llvm::cast(vd->ir.irGlobal->type.get())->refineAbstractTypeTo(_type); - _type = vd->ir.irGlobal->type.get(); + // assign the initializer + llvm::GlobalVariable* globalvar = llvm::cast(glob->value); - llvm::GlobalVariable* gvar = llvm::cast(vd->ir.irGlobal->value); if (!(vd->storage_class & STCextern) && (vd->getModule() == gIR->dmodule || istempl)) { if (Logger::enabled()) { Logger::println("setting initializer"); Logger::cout() << "global: " << *gvar << '\n'; - Logger::cout() << "init: " << *_init << '\n'; + Logger::cout() << "init: " << *initVal << '\n'; } - gvar->setInitializer(_init); + + gvar->setInitializer(initVal); + // do debug info if (global.params.symdebug) { @@ -1040,8 +1035,8 @@ } } - if (emitRTstaticInit) - DtoLazyStaticInit(istempl, gvar, vd->init, t); + if (doLazyInit) + DtoLazyStaticInit(istempl, gvar, vd->init, vd->type); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1396,18 +1391,18 @@ // INITIALIZER HELPERS ////////////////////////////////////////////////////////////////////////////////////////*/ -LLConstant* DtoConstInitializer(Loc& loc, Type* type, Initializer* init) +LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) { LLConstant* _init = 0; // may return zero if (!init) { Logger::println("const default initializer for %s", type->toChars()); - _init = DtoDefaultInit(loc, type); + _init = DtoConstExpInit(loc, type, type->defaultInit()); } else if (ExpInitializer* ex = init->isExpInitializer()) { Logger::println("const expression initializer"); - _init = ex->exp->toConstElem(gIR); + _init = DtoConstExpInit(loc, type, ex->exp);; } else if (StructInitializer* si = init->isStructInitializer()) { @@ -1433,7 +1428,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -LLConstant* DtoConstFieldInitializer(Loc& loc, Type* t, Initializer* init) +LLConstant* DtoConstFieldInitializer(Loc loc, Type* t, Initializer* init) { Logger::println("DtoConstFieldInitializer"); LOG_SCOPE; @@ -1530,20 +1525,33 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) { - Logger::println("building type %s to expression (%s) of type %s", base->toChars(), exp->toChars(), exp->type->toChars()); + Logger::println("building type %s from expression (%s) of type %s", base->toChars(), exp->toChars(), exp->type->toChars()); const LLType* dstTy = DtoType(base); if (Logger::enabled()) Logger::cout() << "final llvm type requested: " << *dstTy << '\n'; - + LLConstant* val = exp->toConstElem(gIR); - + Type* expbase = exp->type->toBasetype(); - Type* t = base; - + Logger::println("expbase: %s", expbase->toChars()); + Type* t = base->toBasetype(); + LLSmallVector dims; + // handle zero initializers + if (expbase->isintegral() && exp->isConst()) + { + if (!exp->toInteger()) + return LLConstant::getNullValue(dstTy); + } + else if (exp->op == TOKnull) + { + return LLConstant::getNullValue(dstTy); + } + while(1) { + Logger::println("t: %s", t->toChars()); if (t->equals(expbase)) break; assert(t->ty == Tsarray); @@ -1552,7 +1560,7 @@ assert(t->nextOf()); t = t->nextOf()->toBasetype(); } - + size_t i = dims.size(); assert(i); @@ -1564,17 +1572,15 @@ inits.insert(inits.end(), dims[i], val); val = LLConstantArray::get(arrty, inits); } - + return val; } -LLConstant* DtoDefaultInit(Loc& loc, Type* type) +LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) { - Expression* exp = type->defaultInit(); - Type* expbase = exp->type->toBasetype(); Type* base = type->toBasetype(); - + // if not the same basetypes, we won't get the same llvm types either if (!expbase->equals(base)) { @@ -1584,7 +1590,6 @@ error(loc, "static arrays of voids have no default initializer"); fatal(); } - Logger::println("type is a static array, building constant array initializer to single value"); return expand_to_sarray(base, exp); } @@ -1594,9 +1599,8 @@ fatal(); } assert(0); - } - + return exp->toConstElem(gIR); } @@ -1615,6 +1619,7 @@ ++p; } // create a noop with the code as the result name! + // FIXME: this is const folded and eliminated immediately ... :/ gIR->ir->CreateAnd(DtoConstSize_t(0),DtoConstSize_t(0),s.c_str()); } diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/llvmhelpers.h --- a/gen/llvmhelpers.h Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/llvmhelpers.h Sat Nov 29 21:25:43 2008 +0100 @@ -86,8 +86,9 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var); // initializer helpers -LLConstant* DtoConstInitializer(Loc& loc, Type* type, Initializer* init); -LLConstant* DtoConstFieldInitializer(Loc& loc, Type* type, Initializer* init); +LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init); +LLConstant* DtoConstFieldInitializer(Loc loc, Type* type, Initializer* init); +LLConstant* DtoConstExpInit(Loc loc, Type* t, Expression* exp); DValue* DtoInitializer(LLValue* target, Initializer* init); // annotation generator @@ -108,9 +109,6 @@ // target stuff void findDefaultTarget(); -/// get the default initializer of the type -LLConstant* DtoDefaultInit(Loc& loc, Type* t); - // fixup an overloaded intrinsic name string void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/runtime.cpp --- a/gen/runtime.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/runtime.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -134,8 +134,10 @@ static void LLVM_D_BuildRuntimeModule() { + Logger::println("building module"); M = new llvm::Module("ldc internal runtime"); + Logger::println("building basic types"); const LLType* voidTy = LLType::VoidTy; const LLType* boolTy = LLType::Int1Ty; const LLType* byteTy = LLType::Int8Ty; @@ -144,6 +146,7 @@ const LLType* longTy = LLType::Int64Ty; const LLType* sizeTy = DtoSize_t(); + Logger::println("building float types"); const LLType* floatTy = LLType::FloatTy; const LLType* doubleTy = LLType::DoubleTy; const LLType* realTy; @@ -156,15 +159,22 @@ const LLType* cdoubleTy = llvm::StructType::get(doubleTy, doubleTy, NULL); const LLType* crealTy = llvm::StructType::get(realTy, realTy, NULL); + Logger::println("building aggr types"); const LLType* voidPtrTy = rt_ptr(byteTy); const LLType* stringTy = rt_array(byteTy); const LLType* wstringTy = rt_array(shortTy); const LLType* dstringTy = rt_array(intTy); - const LLType* objectTy = rt_ptr(ClassDeclaration::object->type->ir.type->get()); - const LLType* classInfoTy = rt_ptr(ClassDeclaration::classinfo->type->ir.type->get()); - const LLType* typeInfoTy = rt_ptr(Type::typeinfo->type->ir.type->get()); + + Logger::println("building class types"); + const LLType* objectTy = DtoType(ClassDeclaration::object->type); + const LLType* classInfoTy = DtoType(ClassDeclaration::classinfo->type); + const LLType* typeInfoTy = DtoType(Type::typeinfo->type); + + Logger::println("building aa type"); const LLType* aaTy = rt_ptr(llvm::OpaqueType::get()); + Logger::println("building functions"); + ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/statements.cpp --- a/gen/statements.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/statements.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -897,7 +897,7 @@ DtoDwarfStopPoint(loc.linnum); // DMD doesn't fold stuff like continue/break, and since this isn't really a loop - // we have to keep track of each statement and jump to next the next/end on continue/break + // we have to keep track of each statement and jump to the next/end on continue/break llvm::BasicBlock* oldend = gIR->scopeend(); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/structs.cpp --- a/gen/structs.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/structs.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -18,36 +18,279 @@ #include "ir/irstruct.h" ////////////////////////////////////////////////////////////////////////////////////////// +void addZeros(std::vector& inits, unsigned pos, unsigned offset); // defined in irstruct.cpp + +// pair of var and its init +typedef std::pair VarInitPair; + +// comparison func for qsort +static int varinit_offset_cmp_func(const void* p1, const void* p2) +{ + VarDeclaration* v1 = ((VarInitPair*)p1)->first; + VarDeclaration* v2 = ((VarInitPair*)p2)->first; + if (v1->offset < v2->offset) + return -1; + else if (v1->offset > v2->offset) + return 1; + else + return 0; +} + +/* +this uses a simple algorithm to build the correct constant + +(1) first sort the explicit initializers by offset... well, DMD doesn't :) + +(2) if there is NO space before the next explicit initializeer, goto (9) +(3) find the next default initializer that fits before it, if NOT found goto (7) +(4) insert zero padding up to the next default initializer +(5) insert the next default initializer +(6) goto (2) + +(7) insert zero padding up to the next explicit initializer + +(9) insert the next explicit initializer +(10) goto (2) + +(11) done + +(next can be the end too) + +*/ + +// return the next default initializer to use or null +static VarDeclaration* nextDefault(IrStruct* irstruct, size_t& idx, size_t pos, size_t offset) +{ + IrStruct::VarDeclVector& defaults = irstruct->defVars; + size_t ndefaults = defaults.size(); + + // for each valid index + while(idx < ndefaults) + { + VarDeclaration* v = defaults[idx]; + + // skip defaults before pos + if (v->offset < pos) + { + idx++; + continue; + } + + // this var default fits + if (v->offset >= pos && v->offset + v->type->size() <= offset) + return v; + + // not usable + break; + } + + // not usable + return NULL; +} + LLConstant* DtoConstStructInitializer(StructInitializer* si) { Logger::println("DtoConstStructInitializer: %s", si->toChars()); LOG_SCOPE; + // get TypeStruct assert(si->ad); TypeStruct* ts = (TypeStruct*)si->ad->type; - DtoResolveDsymbol(si->ad); + // force constant initialization of the symbol + DtoForceConstInitDsymbol(si->ad); + // get formal type const llvm::StructType* structtype = isaStruct(ts->ir.type->get()); + // log it if (Logger::enabled()) Logger::cout() << "llvm struct type: " << *structtype << '\n'; + // sanity check + assert(si->value.dim > 0); assert(si->value.dim == si->vars.dim); - std::vector inits; - for (int i = 0; i < si->value.dim; ++i) + // vector of final initializer constants + std::vector inits; + + // get the ir struct + IrStruct* irstruct = si->ad->ir.irStruct; + + // get default fields + IrStruct::VarDeclVector& defaults = irstruct->defVars; + size_t ndefaults = defaults.size(); + + // make sure si->vars is sorted by offset + std::vector vars; + size_t nvars = si->vars.dim; + vars.resize(nvars); + + // fill pair vector + for (size_t i = 0; i < nvars; i++) { + VarDeclaration* var = (VarDeclaration*)si->vars.data[i]; Initializer* ini = (Initializer*)si->value.data[i]; + assert(var); assert(ini); - VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; - assert(vd); - LLConstant* v = DtoConstInitializer(vd->loc, vd->type, ini); - inits.push_back(DUnionIdx(vd->ir.irField->index, vd->ir.irField->indexOffset, v)); + vars[i] = std::make_pair(var, ini); + } + // sort it + qsort(&vars[0], nvars, sizeof(VarInitPair), &varinit_offset_cmp_func); + + // check integrity + // and do error checking, since the frontend does verify static struct initializers + size_t lastoffset = 0; + size_t lastsize = 0; + bool overlap = false; + for (size_t i=0; i < nvars; i++) + { + // next explicit init var + VarDeclaration* var = vars[i].first; + Logger::println("var = %s : +%u", var->toChars(), var->offset); + + // I would have thought this to be a frontend check + for (size_t j=i+1; joffset >= var->offset && var2->offset < var->offset + var->type->size()) + { + fprintf(stdmsg, "Error: %s: initializer '%s' overlaps with '%s'\n", si->loc.toChars(), var->toChars(), var2->toChars()); + overlap = true; + } + } + + // update offsets + lastoffset = var->offset; + lastsize = var->type->size(); + } + + // error handling, report all overlaps before aborting + if (overlap) + { + error("%s: overlapping union initializers", si->loc.toChars()); } - DtoConstInitStruct((StructDeclaration*)si->ad); - return si->ad->ir.irStruct->dunion->getConst(inits); + // go through each explicit initalizer, falling back to defaults or zeros when necessary + lastoffset = 0; + lastsize = 0; + + size_t j=0; // defaults + + for (size_t i=0; i < nvars; i++) + { + // get var and init + VarDeclaration* var = vars[i].first; + Initializer* ini = vars[i].second; + + size_t offset = var->offset; + size_t size = var->type->size(); + + // if there is space before the next explicit initializer +Lpadding: + size_t pos = lastoffset+lastsize; + if (offset > pos) + { + // find the the next default initializer that fits in this space + VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, offset); + + // found + if (nextdef) + { + // need zeros before the default + if (nextdef->offset > pos) + { + Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos); + addZeros(inits, pos, nextdef->offset); + } + + // do the default + Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset); + LLConstant* c = nextdef->ir.irField->constInit; + inits.push_back(c); + + // update offsets + lastoffset = nextdef->offset; + lastsize = nextdef->type->size(); + + // check if more defaults would fit + goto Lpadding; + } + // not found, pad with zeros + else + { + Logger::println("inserting %lu byte padding at %lu", offset - pos, pos); + addZeros(inits, pos, offset); + // offsets are updated by the explicit initializer + } + } + + // insert next explicit + Logger::println("adding explicit field: %s : +%lu", var->toChars(), offset); + LOG_SCOPE; + LLConstant* c = DtoConstInitializer(var->loc, var->type, ini); + inits.push_back(c); + + lastoffset = offset; + lastsize = size; + } + + // there might still be padding after the last one, make sure that is defaulted/zeroed as well + size_t structsize = getABITypeSize(structtype); + + // if there is space before the next explicit initializer + // FIXME: this should be handled in the loop above as well +Lpadding2: + size_t pos = lastoffset+lastsize; + if (structsize > pos) + { + // find the the next default initializer that fits in this space + VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, structsize); + + // found + if (nextdef) + { + // need zeros before the default + if (nextdef->offset > pos) + { + Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos); + addZeros(inits, pos, nextdef->offset); + } + + // do the default + Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset); + LLConstant* c = nextdef->ir.irField->constInit; + inits.push_back(c); + + // update offsets + lastoffset = nextdef->offset; + lastsize = nextdef->type->size(); + + // check if more defaults would fit + goto Lpadding2; + } + // not found, pad with zeros + else + { + Logger::println("inserting %lu byte padding at %lu", structsize - pos, pos); + addZeros(inits, pos, structsize); + lastoffset = pos; + lastsize = structsize - pos; + } + } + + assert(lastoffset+lastsize == structsize); + + // make the constant struct + LLConstant* c = LLConstantStruct::get(inits, si->ad->ir.irStruct->packed); + if (Logger::enabled()) + { + Logger::cout() << "constant struct initializer: " << *c << '\n'; + } + assert(getABITypeSize(c->getType()) == structsize); + return c; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -61,17 +304,26 @@ IrField* field = vd->ir.irField; assert(field); - unsigned idx = field->index; - unsigned off = field->indexOffset; + // get the start pointer + const LLType* st = getPtrToType(DtoType(sd->type)); - const LLType* st = getPtrToType(DtoType(sd->type)); + // cast to the formal struct type src = DtoBitCast(src, st); - LLValue* val = DtoGEPi(src, 0,idx); - val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); + // gep to the index + LLValue* val = DtoGEPi(src, 0, field->index); - if (off) - val = DtoGEPi1(val, off); + // 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'; @@ -79,46 +331,46 @@ return val; } -////////////////////////////////////////////////////////////////////////////////////////// - void DtoResolveStruct(StructDeclaration* sd) { + // don't do anything if already been here if (sd->ir.resolved) return; + // make sure above works :P sd->ir.resolved = true; - Logger::println("DtoResolveStruct(%s): %s", sd->toChars(), sd->loc.toChars()); + // log what we're doing + Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->locToChars()); LOG_SCOPE; - TypeStruct* ts = (TypeStruct*)sd->type->toBasetype(); + // get the DMD TypeStruct + TypeStruct* ts = (TypeStruct*)sd->type; - // this struct is a forward declaration + // create the IrStruct + IrStruct* irstruct = new IrStruct(sd); + sd->ir.irStruct = irstruct; + + // create the type + ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get()); + + // handle forward declaration structs (opaques) // didn't even know D had those ... if (sd->sizeok != 1) { - sd->ir.irStruct = new IrStruct(ts); - ts->ir.type = new llvm::PATypeHolder(llvm::OpaqueType::get()); + // nothing more to do return; } - bool ispacked = (ts->alignsize() == 1); - - // create the IrStruct - IrStruct* irstruct = new IrStruct(ts); - sd->ir.irStruct = irstruct; + // make this struct current gIR->structs.push_back(irstruct); - // add fields - Array* fields = &sd->fields; - for (int k=0; k < fields->dim; k++) - { - VarDeclaration* v = (VarDeclaration*)fields->data[k]; - Logger::println("Adding field: %s %s", v->type->toChars(), v->toChars()); - // init fields, used to happen in VarDeclaration::toObjFile - irstruct->addField(v); - } + // get some info + bool ispacked = (ts->alignsize() == 1); + bool isunion = sd->isUnionDeclaration(); + // set irstruct info irstruct->packed = ispacked; + // defined in this module? bool thisModule = false; if (sd->getModule() == gIR->dmodule) thisModule = true; @@ -127,21 +379,29 @@ Array* arr = sd->members; for (int k=0; k < arr->dim; k++) { Dsymbol* s = (Dsymbol*)arr->data[k]; - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - if (thisModule || (fd->prot() != PROTprivate)) { - fd->toObjFile(0); // TODO: multiobj - } - } - else if (s->isAttribDeclaration() || - s->isVarDeclaration() || - s->isTemplateMixin()) { - s->toObjFile(0); // TODO: multiobj - } - else { - Logger::println("Ignoring dsymbol '%s' in this->members of kind '%s'", s->toPrettyChars(), s->kind()); - } + s->toObjFile(0); } + const LLType* ST = irstruct->build(); + +#if 0 + std::cout << sd->kind() << ' ' << sd->toPrettyChars() << " type: " << *ST << '\n'; + + // add fields + for (int k=0; k < fields->dim; k++) + { + VarDeclaration* v = (VarDeclaration*)fields->data[k]; + printf(" field: %s %s\n", v->type->toChars(), v->toChars()); + printf(" index: %u offset: %u\n", v->ir.irField->index, v->ir.irField->unionOffset); + } + + unsigned llvmSize = (unsigned)getABITypeSize(ST); + unsigned dmdSize = (unsigned)sd->type->size(); + printf(" llvm size: %u dmd size: %u\n", llvmSize, dmdSize); + assert(llvmSize == dmdSize); + +#endif + /*for (int k=0; k < sd->members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]); dsym->toObjFile(); @@ -149,98 +409,13 @@ Logger::println("doing struct fields"); - const llvm::StructType* structtype = 0; - std::vector fieldtypes; + // refine abstract types for stuff like: struct S{S* next;} + llvm::cast(ts->ir.type->get())->refineAbstractTypeTo(ST); + ST = ts->ir.type->get(); - if (irstruct->offsets.empty()) - { - Logger::println("has no fields"); - fieldtypes.push_back(LLType::Int8Ty); - structtype = llvm::StructType::get(fieldtypes, ispacked); - } - else - { - Logger::println("has fields"); - unsigned prevsize = (unsigned)-1; - unsigned lastoffset = (unsigned)-1; - const LLType* fieldtype = NULL; - VarDeclaration* fieldinit = NULL; - size_t fieldpad = 0; - int idx = 0; - for (IrStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { - // first iteration - if (lastoffset == (unsigned)-1) { - lastoffset = i->first; - assert(lastoffset == 0); - fieldtype = i->second.type; - fieldinit = i->second.var; - prevsize = fieldinit->type->size(); - i->second.var->ir.irField->index = idx; - } - // colliding offset? - else if (lastoffset == i->first) { - size_t s = i->second.var->type->size(); - if (s > prevsize) { - fieldpad += s - prevsize; - prevsize = s; - } - sd->ir.irStruct->hasUnions = true; - i->second.var->ir.irField->index = idx; - } - // intersecting offset? - else if (i->first < (lastoffset + prevsize)) { - size_t s = i->second.var->type->size(); - assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size - sd->ir.irStruct->hasUnions = true; - i->second.var->ir.irField->index = idx; - i->second.var->ir.irField->indexOffset = (i->first - lastoffset) / s; - } - // fresh offset - else { - // commit the field - fieldtypes.push_back(fieldtype); - irstruct->defaultFields.push_back(fieldinit); - if (fieldpad) { - fieldtypes.push_back(llvm::ArrayType::get(LLType::Int8Ty, fieldpad)); - irstruct->defaultFields.push_back(NULL); - idx++; - } - - idx++; - - // start new - lastoffset = i->first; - fieldtype = i->second.type; - fieldinit = i->second.var; - prevsize = fieldinit->type->size(); - i->second.var->ir.irField->index = idx; - fieldpad = 0; - } - } - fieldtypes.push_back(fieldtype); - irstruct->defaultFields.push_back(fieldinit); - if (fieldpad) { - fieldtypes.push_back(llvm::ArrayType::get(LLType::Int8Ty, fieldpad)); - irstruct->defaultFields.push_back(NULL); - } - - Logger::println("creating struct type"); - structtype = llvm::StructType::get(fieldtypes, ispacked); - } - - // refine abstract types for stuff like: struct S{S* next;} - if (irstruct->recty != 0) - { - llvm::PATypeHolder& pa = irstruct->recty; - llvm::cast(pa.get())->refineAbstractTypeTo(structtype); - structtype = isaStruct(pa.get()); - } - - assert(ts->ir.type == 0); - ts->ir.type = new llvm::PATypeHolder(structtype); - + // name type if (sd->parent->isModule()) { - gIR->module->addTypeName(sd->mangle(),structtype); + gIR->module->addTypeName(sd->mangle(),ST); } gIR->structs.pop_back(); @@ -265,7 +440,7 @@ initname.append("6__initZ"); llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(sd); - llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->ir.type->get(), true, _linkage, NULL, initname, gIR->module); + llvm::GlobalVariable* initvar = new llvm::GlobalVariable(sd->ir.irStruct->initOpaque.get(), true, _linkage, NULL, initname, gIR->module); sd->ir.irStruct->init = initvar; gIR->constInitList.push_back(sd); @@ -286,59 +461,33 @@ IrStruct* irstruct = sd->ir.irStruct; gIR->structs.push_back(irstruct); - // 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; - LLConstant* finit = DtoConstFieldInitializer(so->var->loc, so->var->type, so->var->init); - so->init = finit; - so->var->ir.irField->constInit = finit; - } - const llvm::StructType* structtype = isaStruct(sd->type->ir.type->get()); - // go through the field inits and build the default initializer - std::vector fieldinits_ll; - size_t nfi = irstruct->defaultFields.size(); - for (size_t i=0; idefaultFields[i] != NULL) { - c = irstruct->defaultFields[i]->ir.irField->constInit; - assert(c); - } - else { - const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i)); - std::vector vals(arrty->getNumElements(), llvm::ConstantInt::get(LLType::Int8Ty, 0, false)); - c = llvm::ConstantArray::get(arrty, vals); - } - fieldinits_ll.push_back(c); + // make sure each offset knows its default initializer + Array* fields = &sd->fields; + for (int k=0; k < fields->dim; k++) + { + VarDeclaration* v = (VarDeclaration*)fields->data[k]; + LLConstant* finit = DtoConstFieldInitializer(v->loc, v->type, v->init); + v->ir.irField->constInit = finit; } - // generate the union mapper - sd->ir.irStruct->dunion = new DUnion(); // uses gIR->topstruct() - // always generate the constant initalizer - if (!sd->zeroInit) { + if (sd->zeroInit) + { + Logger::println("Zero initialized"); + irstruct->constInit = llvm::ConstantAggregateZero::get(structtype); + } + else + { Logger::println("Not zero initialized"); - #if 0 - //assert(tk == gIR->gIR->topstruct()().size()); - #ifndef LLVMD_NO_LOGGER - Logger::cout() << "struct type: " << *structtype << '\n'; - for (size_t k=0; kgetType() << '\n'; - Logger::cout() << "Value:" << '\n'; - Logger::cout() << *fieldinits_ll[k] << '\n'; - } - Logger::cout() << "Initializer printed" << '\n'; - #endif - #endif - sd->ir.irStruct->constInit = llvm::ConstantStruct::get(structtype,fieldinits_ll); + + LLConstant* c = irstruct->buildDefaultConstInit(); + irstruct->constInit = c; } - else { - Logger::println("Zero initialized"); - sd->ir.irStruct->constInit = llvm::ConstantAggregateZero::get(structtype); - } + + // refine __initZ global type to the one of the initializer + llvm::cast(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType()); gIR->structs.pop_back(); @@ -385,163 +534,3 @@ LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz)); return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); } - -////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////// D UNION HELPER CLASS //////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -DUnion::DUnion() -{ - DUnionField* f = NULL; - IrStruct* topstruct = gIR->topstruct(); - bool unions = false; - for (IrStruct::OffsetMap::iterator i=topstruct->offsets.begin(); i!=topstruct->offsets.end(); ++i) - { - unsigned o = i->first; - IrStruct::Offset* so = &i->second; - const LLType* ft = so->init->getType(); - size_t sz = getABITypeSize(ft); - if (f == NULL) { // new field - fields.push_back(DUnionField()); - f = &fields.back(); - f->size = sz; - f->offset = o; - f->init = so->init; - f->initsize = sz; - f->types.push_back(ft); - } - else if (o == f->offset) { // same offset - if (sz > f->size) - f->size = sz; - f->types.push_back(ft); - unions = true; - } - else if (o < f->offset+f->size) { - assert((o+sz) <= (f->offset+f->size)); - unions = true; - } - else { - fields.push_back(DUnionField()); - f = &fields.back(); - f->size = sz; - f->offset = o; - f->init = so->init; - f->initsize = sz; - f->types.push_back(ft); - } - } - - ispacked = topstruct->packed; - - /*{ - LOG_SCOPE; - Logger::println("******** DUnion BEGIN"); - size_t n = fields.size(); - for (size_t i=0; i& out) -{ - assert(nbytes > 0); - std::vector i(nbytes, llvm::ConstantInt::get(LLType::Int8Ty, 0, false)); - out.push_back(llvm::ConstantArray::get(llvm::ArrayType::get(LLType::Int8Ty, nbytes), i)); -} - -LLConstant* DUnion::getConst(std::vector& in) -{ - std::sort(in.begin(), in.end()); - std::vector out; - - size_t nin = in.size(); - size_t nfields = fields.size(); - - size_t fi = 0; - size_t last = 0; - size_t ii = 0; - size_t os = 0; - - for(;;) - { - if (fi == nfields) break; - - bool nextSame = (ii+1 < nin) && (in[ii+1].idx == fi); - - if (ii < nin && fi == in[ii].idx) - { - size_t s = getABITypeSize(in[ii].c->getType()); - if (in[ii].idx == last) - { - size_t nos = in[ii].idxos * s; - if (nos && nos-os) { - assert(nos >= os); - push_nulls(nos-os, out); - } - os = nos + s; - } - else - { - os = s; - } - out.push_back(in[ii].c); - ii++; - if (!nextSame) - { - if (os < fields[fi].size) - push_nulls(fields[fi].size - os, out); - os = 0; - last = fi++; - } - continue; - } - - // default initialize if necessary - if (ii == nin || fi < in[ii].idx) - { - DUnionField& f = fields[fi]; - out.push_back(f.init); - if (f.initsize < f.size) - push_nulls(f.size - f.initsize, out); - last = fi++; - os = 0; - continue; - } - } - - std::vector tys; - size_t nout = out.size(); - for (size_t i=0; igetType()); - - const llvm::StructType* st = llvm::StructType::get(tys, ispacked); - return llvm::ConstantStruct::get(st, out); -} - - - - - - - - - - - - - - - - - - - - - diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/structs.h --- a/gen/structs.h Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/structs.h Sat Nov 29 21:25:43 2008 +0100 @@ -33,43 +33,4 @@ // index a struct one level LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd); -struct DUnionField -{ - unsigned offset; - size_t size; - std::vector types; - LLConstant* init; - size_t initsize; - - DUnionField() { - offset = 0; - size = 0; - init = NULL; - initsize = 0; - } -}; - -struct DUnionIdx -{ - unsigned idx,idxos; - LLConstant* c; - - DUnionIdx() - : idx(0), c(0) {} - DUnionIdx(unsigned _idx, unsigned _idxos, LLConstant* _c) - : idx(_idx), idxos(_idxos), c(_c) {} - bool operator<(const DUnionIdx& i) const { - return (idx < i.idx) || (idx == i.idx && idxos < i.idxos); - } -}; - -class DUnion -{ - std::vector fields; - bool ispacked; -public: - DUnion(); - LLConstant* getConst(std::vector& in); -}; - #endif diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/tocall.cpp --- a/gen/tocall.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/tocall.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -41,11 +41,12 @@ { //TODO: StdCall is not a good base on Windows due to extra name mangling // applied there - if (global.params.cpu == ARCHx86 && global.params.os != OSWindows) - return llvm::CallingConv::X86_StdCall; + if (global.params.cpu == ARCHx86) + return (global.params.os != OSWindows) ? llvm::CallingConv::X86_StdCall : llvm::CallingConv::C; else return llvm::CallingConv::Fast; } + // on the other hand, here, it's exactly what we want!!! TODO: right? else if (l == LINKwindows) return llvm::CallingConv::X86_StdCall; else @@ -155,7 +156,6 @@ } // build type info array - assert(Type::typeinfo->ir.irStruct->constInit); const LLType* typeinfotype = DtoType(Type::typeinfo->type); const LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements()); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/todebug.cpp --- a/gen/todebug.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/todebug.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -452,14 +452,19 @@ definedCU = DtoDwarfCompileUnit(sd->getModule()); std::vector elems; - elems.reserve(ir->offsets.size()); - for (IrStruct::OffsetMap::iterator i=ir->offsets.begin(); i!=ir->offsets.end(); ++i) + if (!ir->aggrdecl->isInterfaceDeclaration()) // plain interfaces don't have one { - unsigned offset = i->first; - IrStruct::Offset& o = i->second; + std::vector& arr = ir->varDecls; + size_t narr = arr.size(); + elems.reserve(narr); + for (int k=0; kloc.linnum, o.var->type, compileUnit, definedCU, o.var->toChars(), offset); - elems.push_back(DBG_CAST(ptr)); + LLGlobalVariable* ptr = dwarfMemberType(vd->loc.linnum, vd->type, compileUnit, definedCU, vd->toChars(), vd->offset); + elems.push_back(DBG_CAST(ptr)); + } } const LLArrayType* at = LLArrayType::get(DBG_TYPE, elems.size()); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/toir.cpp --- a/gen/toir.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/toir.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -135,20 +135,27 @@ } else { Logger::println("a normal variable"); + // take care of forward references of global variables if (vd->isDataseg() || (vd->storage_class & STCextern)) { vd->toObjFile(0); // TODO: multiobj } - if (!vd->ir.isSet() || !vd->ir.getIrValue()) { + + LLValue* val; + + if (!vd->ir.isSet() || !(val = vd->ir.getIrValue())) { error("variable %s not resolved", vd->toChars()); if (Logger::enabled()) Logger::cout() << "unresolved variable had type: " << *DtoType(vd->type) << '\n'; fatal(); } + if (vd->isDataseg() || (vd->storage_class & STCextern)) { DtoConstInitGlobal(vd); + val = DtoBitCast(val, DtoType(type->pointerTo())); } - return new DVarValue(type, vd, vd->ir.getIrValue()); + + return new DVarValue(type, vd, val); } } else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) @@ -369,7 +376,7 @@ llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage; if (Logger::enabled()) Logger::cout() << "type: " << *at << "\ninit: " << *_init << '\n'; - llvm::GlobalVariable* gvar = new llvm::GlobalVariable(at,true,_linkage,_init,".stringliteral",gIR->module); + llvm::GlobalVariable* gvar = new llvm::GlobalVariable(at,true,_linkage,_init,".str",gIR->module); llvm::ConstantInt* zero = llvm::ConstantInt::get(LLType::Int32Ty, 0, false); LLConstant* idxs[2] = { zero, zero }; @@ -443,7 +450,7 @@ } llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage; - llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_init->getType(),true,_linkage,_init,".stringliteral",gIR->module); + llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_init->getType(),true,_linkage,_init,".str",gIR->module); llvm::ConstantInt* zero = llvm::ConstantInt::get(LLType::Int32Ty, 0, false); LLConstant* idxs[2] = { zero, zero }; @@ -1008,19 +1015,21 @@ assert(fdecl->vtblIndex > 0); assert(e1type->ty == Tclass); - LLValue* zero = llvm::ConstantInt::get(LLType::Int32Ty, 0, false); - LLValue* vtblidx = llvm::ConstantInt::get(LLType::Int32Ty, (size_t)fdecl->vtblIndex, false); + LLValue* zero = DtoConstUint(0); + size_t vtblidx = fdecl->vtblIndex; if (Logger::enabled()) Logger::cout() << "vthis: " << *vthis << '\n'; - funcval = DtoGEP(vthis, zero, zero); + funcval = vthis; + if (!fdecl->isMember2()->isInterfaceDeclaration()) + funcval = DtoGEP(funcval, zero, zero); funcval = DtoLoad(funcval); - funcval = DtoGEP(funcval, zero, vtblidx, toChars()); + Logger::println("vtblidx = %lu", vtblidx); + funcval = DtoGEP(funcval, zero, DtoConstUint(vtblidx), toChars()); funcval = DtoLoad(funcval); - #if OPAQUE_VTBLS + funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); if (Logger::enabled()) Logger::cout() << "funcval casted: " << *funcval << '\n'; - #endif } // static call else { @@ -2143,6 +2152,22 @@ ////////////////////////////////////////////////////////////////////////////////////////// +LLConstant* FuncExp::toConstElem(IRState* p) +{ + Logger::print("FuncExp::toConstElem: %s | %s\n", toChars(), type->toChars()); + LOG_SCOPE; + + assert(fd); + assert(fd->tok == TOKfunction); + + DtoForceDefineDsymbol(fd); + assert(fd->ir.irFunc->func); + + return fd->ir.irFunc->func; +} + +////////////////////////////////////////////////////////////////////////////////////////// + DValue* ArrayLiteralExp::toElem(IRState* p) { Logger::print("ArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); @@ -2252,91 +2277,147 @@ ////////////////////////////////////////////////////////////////////////////////////////// +void addZeros(std::vector& inits, unsigned pos, unsigned offset); + DValue* StructLiteralExp::toElem(IRState* p) { Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - const LLType* llt = DtoType(type); - - LLValue* mem = 0; - - LLValue* sptr = DtoAlloca(llt,"tmpstructliteral"); - - // default init the struct to take care of padding - // and unspecified members - TypeStruct* ts = (TypeStruct*)type->toBasetype(); - assert(ts->sym); - DtoForceConstInitDsymbol(ts->sym); - assert(ts->sym->ir.irStruct->init); - DtoAggrCopy(sptr, ts->sym->ir.irStruct->init); - - // num elements in literal - unsigned n = elements->dim; - - // unions might have different types for each literal - if (sd->ir.irStruct->hasUnions) { - // build the type of the literal - std::vector tys; - for (unsigned i=0; idata[i]; - if (!vx) continue; - tys.push_back(DtoType(vx->type)); + // get arrays + size_t n = elements->dim; + Expression** exprs = (Expression**)elements->data; + + assert(sd->fields.dim == n); + VarDeclaration** vars = (VarDeclaration**)sd->fields.data; + + // vector of values to build aggregate from + std::vector values; + + // trackers + size_t lastoffset = 0; + size_t lastsize = 0; + + // for through each field and build up the struct, padding with zeros + for (size_t i=0; ioffset > lastoffset + lastsize) + { + addZeros(values, lastoffset + lastsize, var->offset); } - const LLStructType* t = LLStructType::get(tys, sd->ir.irStruct->packed); - if (t != llt) { - if (getABITypeSize(t) != getABITypeSize(llt)) { - if (Logger::enabled()) - Logger::cout() << "got size " << getABITypeSize(t) << ", expected " << getABITypeSize(llt) << '\n'; - assert(0 && "type size mismatch"); - } - sptr = DtoBitCast(sptr, getPtrToType(t)); - if (Logger::enabled()) - Logger::cout() << "sptr type is now: " << *t << '\n'; - } + + // add the expression value + DValue* v = e->toElem(p); + values.push_back(v->getRVal()); + + // update offsets + lastoffset = var->offset; + lastsize = var->type->size(); + } + + // add any 0 padding needed at the end of the literal + const LLType* structtype = DtoType(sd->type); + size_t structsize = getABITypeSize(structtype); + + if (structsize > lastoffset+lastsize) + { + addZeros(values, lastoffset + lastsize, structsize); } - // build - unsigned j = 0; - for (unsigned i=0; i types(n, NULL); + + for (size_t i=0; idata[i]; - if (!vx) continue; - - if (Logger::enabled()) - Logger::cout() << "getting index " << j << " of " << *sptr << '\n'; - LLValue* arrptr = DtoGEPi(sptr,0,j); - DValue* darrptr = new DVarValue(vx->type, arrptr); - - DValue* ve = vx->toElem(p); - DtoAssign(loc, darrptr, ve); - - j++; + types[i] = values[i]->getType(); } - return new DImValue(type, sptr); + const LLStructType* sty = LLStructType::get(types, sd->ir.irStruct->packed); + + // allocate storage for the struct literal on the stack + LLValue* mem = DtoAlloca(sty, "tmpstructliteral"); + + // put all the values into the storage + for (size_t i=0; i& inits, unsigned pos, unsigned offset); + LLConstant* StructLiteralExp::toConstElem(IRState* p) { Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - unsigned n = elements->dim; - std::vector vals(n, NULL); - - for (unsigned i=0; idim; + Expression** exprs = (Expression**)elements->data; + + assert(sd->fields.dim == n); + VarDeclaration** vars = (VarDeclaration**)sd->fields.data; + + // vector of values to build aggregate from + std::vector values; + + // trackers + size_t lastoffset = 0; + size_t lastsize = 0; + + // for through each field and build up the struct, padding with zeros + for (size_t i=0; idata[i]; - vals[i] = vx->toConstElem(p); + Expression* e = exprs[i]; + VarDeclaration* var = vars[i]; + + // field is skipped + if (!e) + continue; + + // add any 0 padding needed before this field + if (var->offset > lastoffset + lastsize) + { + addZeros(values, lastoffset + lastsize, var->offset); + } + + // add the expression value + values.push_back(e->toConstElem(p)); + + // update offsets + lastoffset = var->offset; + lastsize = var->type->size(); } - assert(type->toBasetype()->ty == Tstruct); - const LLType* t = DtoType(type); - const LLStructType* st = isaStruct(t); - return llvm::ConstantStruct::get(st,vals); + // add any 0 padding needed at the end of the literal + const LLType* structtype = DtoType(sd->type); + size_t structsize = getABITypeSize(structtype); + + if (structsize > lastoffset+lastsize) + { + addZeros(values, lastoffset + lastsize, structsize); + } + + // return constant struct + return LLConstantStruct::get(values, sd->ir.irStruct->packed); } ////////////////////////////////////////////////////////////////////////////////////////// diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/tollvm.cpp --- a/gen/tollvm.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/tollvm.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -119,14 +119,14 @@ TypeStruct* ts = (TypeStruct*)t; assert(ts->sym); DtoResolveDsymbol(ts->sym); - return ts->sym->ir.irStruct->recty.get(); // t->ir.type->get(); + return ts->ir.type->get(); } case Tclass: { TypeClass* tc = (TypeClass*)t; assert(tc->sym); DtoResolveDsymbol(tc->sym); - return getPtrToType(tc->sym->ir.irStruct->recty.get()); // t->ir.type->get()); + return getPtrToType(tc->ir.type->get()); } // functions @@ -584,6 +584,13 @@ return gIR->ir->CreateBitCast(v, t, name ? name : "tmp"); } +LLConstant* DtoBitCast(LLConstant* v, const LLType* t) +{ + if (v->getType() == t) + return v; + return llvm::ConstantExpr::getBitCast(v, t); +} + ////////////////////////////////////////////////////////////////////////////////////////// const LLPointerType* isaPointer(LLValue* v) @@ -695,6 +702,33 @@ return gTargetData->getPrefTypeAlignment(t); } +const LLType* getBiggestType(const LLType** begin, size_t n) +{ + const LLType* bigTy = 0; + size_t bigSize = 0; + size_t bigAlign = 0; + + const LLType** end = begin+n; + while (begin != end) + { + const LLType* T = *begin; + + size_t sz = getABITypeSize(T); + size_t ali = getABITypeAlign(T); + if (sz > bigSize || (sz == bigSize && ali > bigAlign)) + { + bigTy = T; + bigSize = sz; + bigAlign = ali; + } + + ++begin; + } + + // will be null for n==0 + return bigTy; +} + ////////////////////////////////////////////////////////////////////////////////////////// const LLStructType* DtoInterfaceInfoType() diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/tollvm.h --- a/gen/tollvm.h Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/tollvm.h Sat Nov 29 21:25:43 2008 +0100 @@ -67,6 +67,7 @@ LLValue* DtoLoad(LLValue* src, const char* name=0); void DtoStore(LLValue* src, LLValue* dst); LLValue* DtoBitCast(LLValue* v, const LLType* t, const char* name=0); +LLConstant* DtoBitCast(LLConstant* v, const LLType* t); // llvm::dyn_cast wrappers const LLPointerType* isaPointer(LLValue* v); @@ -96,6 +97,9 @@ unsigned char getABITypeAlign(const LLType* t); unsigned char getPrefTypeAlign(const LLType* t); +// get biggest type, for unions ... +const LLType* getBiggestType(const LLType** begin, size_t n); + // pair type helpers LLValue* DtoAggrPair(const LLType* type, LLValue* V1, LLValue* V2, const char* name = 0); LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name = 0); diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/toobj.cpp --- a/gen/toobj.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/toobj.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -77,6 +77,8 @@ //printf("codegen: %s\n", srcfile->toChars()); + assert(!global.errors); + // start by deleting the old object file deleteObjFile(); @@ -156,16 +158,6 @@ fatal(); } - // start out by providing opaque for the built-in class types - if (!ClassDeclaration::object->type->ir.type) - ClassDeclaration::object->type->ir.type = new llvm::PATypeHolder(llvm::OpaqueType::get()); - - if (!Type::typeinfo->type->ir.type) - Type::typeinfo->type->ir.type = new llvm::PATypeHolder(llvm::OpaqueType::get()); - - if (!ClassDeclaration::classinfo->type->ir.type) - ClassDeclaration::classinfo->type->ir.type = new llvm::PATypeHolder(llvm::OpaqueType::get()); - // process module members for (int k=0; k < members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(members->data[k]); @@ -638,7 +630,7 @@ const LLStructType* modulerefTy = DtoModuleReferenceType(); std::vector mrefvalues; mrefvalues.push_back(LLConstant::getNullValue(modulerefTy->getContainedType(0))); - mrefvalues.push_back(moduleinfo); + mrefvalues.push_back(llvm::ConstantExpr::getBitCast(moduleinfo, modulerefTy->getContainedType(1))); LLConstant* thismrefinit = LLConstantStruct::get(modulerefTy, mrefvalues); // create the ModuleReference node for this module @@ -704,6 +696,13 @@ assert(moduleinfo); DtoForceConstInitDsymbol(moduleinfo); + // check for patch + if (moduleinfo->ir.irStruct->constInit->getNumOperands() != 11) + { + error("unpatched object.d detected, ModuleInfo incorrect"); + fatal(); + } + // moduleinfo llvm struct type const llvm::StructType* moduleinfoTy = isaStruct(moduleinfo->type->ir.type->get()); @@ -783,9 +782,15 @@ Logger::println("skipping interface '%s' in moduleinfo", cd->toPrettyChars()); continue; } + else if (cd->sizeok != 1) + { + Logger::println("skipping opaque class declaration '%s' in moduleinfo", cd->toPrettyChars()); + continue; + } Logger::println("class: %s", cd->toPrettyChars()); assert(cd->ir.irStruct->classInfo); - classInits.push_back(cd->ir.irStruct->classInfo); + c = llvm::ConstantExpr::getBitCast(cd->ir.irStruct->classInfo, getPtrToType(classinfoTy)); + classInits.push_back(c); } // has class array? if (!classInits.empty()) @@ -842,7 +847,7 @@ }*/ // create initializer - LLConstant* constMI = llvm::ConstantStruct::get(moduleinfoTy, initVec); + LLConstant* constMI = llvm::ConstantStruct::get(initVec); // create name std::string MIname("_D"); @@ -853,7 +858,8 @@ // flags will be modified at runtime so can't make it constant llvm::GlobalVariable* gvar = gIR->module->getGlobalVariable(MIname); - if (!gvar) gvar = new llvm::GlobalVariable(moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, MIname, gIR->module); + if (!gvar) gvar = new llvm::GlobalVariable(constMI->getType(), false, llvm::GlobalValue::ExternalLinkage, NULL, MIname, gIR->module); + else assert(gvar->getType()->getContainedType(0) == constMI->getType()); gvar->setInitializer(constMI); // build the modulereference and ctor for registering it @@ -988,7 +994,8 @@ #else bool _isconst = isConst(); #endif - if (parent && parent->isFuncDeclaration()) + Dsymbol* par = toParent2(); + if (par && par->isFuncDeclaration()) { static_local = true; if (init && init->isExpInitializer()) { @@ -1015,20 +1022,17 @@ } else { -#if DMDV2 - #if 0 + // might already have its irField, as classes derive each other without getting copies of the VarDeclaration if (!ir.irField) { - printf("dataseg: %d\n", isDataseg()); - printf("parent: %s %s\n", parent->kind(), parent->toPrettyChars()); - printf("this: %s %s\n", this->kind(), this->toPrettyChars()); + assert(!ir.isSet()); + ir.irField = new IrField(this); } - #endif -#else - assert(ir.irField != 0); -#endif + IrStruct* irstruct = gIR->topstruct(); + irstruct->addVar(this); + + Logger::println("added offset %u", offset); } - Logger::println("VarDeclaration::toObjFile is done"); } /* ================================================================== */ @@ -1056,3 +1060,28 @@ { gIR->resolveList.push_back(this); } + +/* ================================================================== */ + +void AnonDeclaration::toObjFile(int multiobj) +{ + Array *d = include(NULL, NULL); + + if (d) + { + // get real aggregate parent + IrStruct* irstruct = gIR->topstruct(); + + // push a block on the stack + irstruct->pushAnon(isunion); + + // go over children + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->toObjFile(multiobj); + } + + // finish + irstruct->popAnon(); + } +} diff -r 6e7a4c3b64d2 -r 340acf1535d0 gen/typinf.cpp --- a/gen/typinf.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/gen/typinf.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -379,7 +379,7 @@ const LLStructType* stype = isaStruct(base->type->ir.type->get()); // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoTypedefDeclaration::llvmDefine() @@ -390,10 +390,6 @@ ClassDeclaration* base = Type::typeinfotypedef; DtoForceConstInitDsymbol(base); - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - if (Logger::enabled()) - Logger::cout() << "got stype: " << *stype << '\n'; - // vtbl std::vector sinits; sinits.push_back(base->ir.irStruct->vtbl); @@ -408,13 +404,11 @@ // TypeInfo base sd->basetype = sd->basetype->merge(); // DMD does this! LLConstant* castbase = DtoTypeInfoOf(sd->basetype, true); - assert(castbase->getType() == stype->getElementType(2)); sinits.push_back(castbase); // char[] name char *name = sd->toPrettyChars(); sinits.push_back(DtoConstString(name)); - assert(sinits.back()->getType() == stype->getElementType(3)); // void[] init const LLPointerType* initpt = getPtrToType(LLType::Int8Ty); @@ -433,9 +427,14 @@ sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast)); } - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoTypedefDeclaration::toDt(dt_t **pdt) @@ -453,10 +452,8 @@ ClassDeclaration* base = Type::typeinfoenum; DtoResolveClass(base); - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoEnumDeclaration::llvmDefine() @@ -467,8 +464,6 @@ ClassDeclaration* base = Type::typeinfoenum; DtoForceConstInitDsymbol(base); - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // vtbl std::vector sinits; sinits.push_back(base->ir.irStruct->vtbl); @@ -482,13 +477,11 @@ // TypeInfo base LLConstant* castbase = DtoTypeInfoOf(sd->memtype, true); - assert(castbase->getType() == stype->getElementType(2)); sinits.push_back(castbase); // char[] name char *name = sd->toPrettyChars(); sinits.push_back(DtoConstString(name)); - assert(sinits.back()->getType() == stype->getElementType(3)); // void[] init const LLPointerType* initpt = getPtrToType(LLType::Int8Ty); @@ -512,9 +505,14 @@ #endif } - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoEnumDeclaration::toDt(dt_t **pdt) @@ -529,10 +527,8 @@ ClassDeclaration* base = cd; DtoResolveClass(base); - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - tid->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,tid->toChars(),gIR->module); + tid->ir.irGlobal->value = new llvm::GlobalVariable(tid->ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,tid->toChars(),gIR->module); } static LLConstant* LLVM_D_Define_TypeInfoBase(Type* basetype, TypeInfoDeclaration* tid, ClassDeclaration* cd) @@ -540,8 +536,6 @@ ClassDeclaration* base = cd; DtoForceConstInitDsymbol(base); - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // vtbl std::vector sinits; sinits.push_back(base->ir.irStruct->vtbl); @@ -551,11 +545,15 @@ // TypeInfo base LLConstant* castbase = DtoTypeInfoOf(basetype, true); - assert(castbase->getType() == stype->getElementType(2)); sinits.push_back(castbase); - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(tid->ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer isaGlobalVar(tid->ir.irGlobal->value)->setInitializer(tiInit); } @@ -628,11 +626,8 @@ ClassDeclaration* base = Type::typeinfostaticarray; DtoResolveClass(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoStaticArrayDeclaration::llvmDefine() @@ -665,9 +660,14 @@ // length sinits.push_back(DtoConstSize_t(tc->dim->toInteger())); - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoStaticArrayDeclaration::toDt(dt_t **pdt) @@ -686,11 +686,8 @@ ClassDeclaration* base = Type::typeinfoassociativearray; DtoResolveClass(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoAssociativeArrayDeclaration::llvmDefine() @@ -702,9 +699,6 @@ ClassDeclaration* base = Type::typeinfoassociativearray; DtoForceConstInitDsymbol(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // initializer vector std::vector sinits; // first is always the vtable @@ -719,17 +713,20 @@ // value typeinfo LLConstant* castbase = DtoTypeInfoOf(tc->next, true); - assert(castbase->getType() == stype->getElementType(2)); sinits.push_back(castbase); // key typeinfo castbase = DtoTypeInfoOf(tc->index, true); - assert(castbase->getType() == stype->getElementType(3)); sinits.push_back(castbase); - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoAssociativeArrayDeclaration::toDt(dt_t **pdt) @@ -810,10 +807,8 @@ ClassDeclaration* base = Type::typeinfostruct; DtoResolveClass(base); - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoStructDeclaration::llvmDefine() @@ -1001,9 +996,14 @@ #endif - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoStructDeclaration::toDt(dt_t **pdt) @@ -1023,11 +1023,8 @@ assert(base); DtoResolveClass(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true, llvm::GlobalValue::WeakLinkage, NULL, toChars(), gIR->module); } void TypeInfoClassDeclaration::llvmDefine() @@ -1040,9 +1037,6 @@ assert(base); DtoForceConstInitDsymbol(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // initializer vector std::vector sinits; // first is always the vtable @@ -1058,9 +1052,14 @@ assert(tc->sym->ir.irStruct->classInfo); sinits.push_back(tc->sym->ir.irStruct->classInfo); - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoClassDeclaration::toDt(dt_t **pdt) @@ -1080,11 +1079,8 @@ assert(base); DtoResolveClass(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoInterfaceDeclaration::llvmDefine() @@ -1114,9 +1110,14 @@ assert(tc->sym->ir.irStruct->classInfo); sinits.push_back(tc->sym->ir.irStruct->classInfo); - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoInterfaceDeclaration::toDt(dt_t **pdt) @@ -1136,11 +1137,8 @@ assert(base); DtoResolveClass(base); - // get type of typeinfo class - const LLStructType* stype = isaStruct(base->type->ir.type->get()); - // create the symbol - this->ir.irGlobal->value = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); + ir.irGlobal->value = new llvm::GlobalVariable(ir.irGlobal->type.get(), true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module); } void TypeInfoTupleDeclaration::llvmDefine() @@ -1199,9 +1197,14 @@ LLConstant* slice = DtoConstSlice(DtoConstSize_t(dim), arrptr); sinits.push_back(slice); - // create the symbol - LLConstant* tiInit = llvm::ConstantStruct::get(stype, sinits); - isaGlobalVar(this->ir.irGlobal->value)->setInitializer(tiInit); + // create the inititalizer + LLConstant* tiInit = llvm::ConstantStruct::get(sinits); + + // refine global type + llvm::cast(ir.irGlobal->type.get())->refineAbstractTypeTo(tiInit->getType()); + + // set the initializer + isaGlobalVar(ir.irGlobal->value)->setInitializer(tiInit); } void TypeInfoTupleDeclaration::toDt(dt_t **pdt) diff -r 6e7a4c3b64d2 -r 340acf1535d0 ir/irstruct.cpp --- a/ir/irstruct.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/ir/irstruct.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -3,54 +3,57 @@ #include "mtype.h" #include "aggregate.h" #include "declaration.h" +#include "init.h" #include "ir/irstruct.h" #include "gen/irstate.h" #include "gen/tollvm.h" +#include "gen/logger.h" IrInterface::IrInterface(BaseClass* b) +: vtblInitTy(llvm::OpaqueType::get()) { base = b; decl = b->base; - vtblTy = NULL; vtblInit = NULL; vtbl = NULL; infoTy = NULL; infoInit = NULL; info = NULL; - index = -1; -} - -IrInterface::~IrInterface() -{ - delete vtblTy; + index = 0; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -IrStruct::IrStruct(Type* t) - : recty((t->ir.type) ? *t->ir.type : llvm::OpaqueType::get()) +IrStruct::IrStruct(AggregateDeclaration* aggr) +: initOpaque(llvm::OpaqueType::get()), + classInfoOpaque(llvm::OpaqueType::get()), + vtblTy(llvm::OpaqueType::get()), + vtblInitTy(llvm::OpaqueType::get()) { - type = t; + aggrdecl = aggr; + defaultFound = false; + anon = NULL; + index = 0; + + type = aggr->type; defined = false; constinited = false; - interfaceInfosTy = NULL; + interfaceInfos = NULL; - vtbl = NULL; constVtbl = NULL; + init = NULL; constInit = NULL; + classInfo = NULL; constClassInfo = NULL; - hasUnions = false; - dunion = NULL; - - classDeclared = false; - classDefined = false; + classInfoDeclared = false; + classInfoDefined = false; packed = false; @@ -61,14 +64,294 @@ { } -void IrStruct::addField(VarDeclaration* v) +////////////////////////////////////////// + +void IrStruct::pushAnon(bool isunion) +{ + anon = new Anon(isunion, anon); +} + +////////////////////////////////////////// + +void IrStruct::popAnon() +{ + assert(anon); + + const LLType* BT; + + // get the anon type + if (anon->isunion) + { + // get biggest type in block + const LLType* biggest = getBiggestType(&anon->types[0], anon->types.size()); + std::vector vec(1, biggest); + BT = LLStructType::get(vec, aggrdecl->ir.irStruct->packed); + } + else + { + // build a struct from the types + BT = LLStructType::get(anon->types, aggrdecl->ir.irStruct->packed); + } + + // pop anon + Anon* tmp = anon; + anon = anon->parent; + delete tmp; + + // is there a parent anon? + if (anon) + { + // make sure type gets pushed in the anon, not the main + anon->types.push_back(BT); + // index is only manipulated at the top level, anons use raw offsets + } + // no parent anon, finally add to aggrdecl + else + { + types.push_back(BT); + // only advance to next position if main is not a union + if (!aggrdecl->isUnionDeclaration()) + { + index++; + } + } +} + +////////////////////////////////////////// + +void addZeros(std::vector& inits, size_t pos, size_t offset); + +void IrStruct::addVar(VarDeclaration * var) { - // might already have its irField, as classes derive each other without getting copies of the VarDeclaration - if (!v->ir.irField) + TypeVector* tvec = &types; + if (anon) + { + // make sure type gets pushed in the anon, not the main + tvec = &anon->types; + + // set but don't advance index + var->ir.irField->index = index; + + // set offset in bytes from start of anon block + var->ir.irField->unionOffset = var->offset - var->offset2; + } + else if (aggrdecl->isUnionDeclaration()) + { + // set but don't advance index + var->ir.irField->index = index; + } + else + { + // set and advance index + var->ir.irField->index = index++; + } + + // add type + tvec->push_back(DtoType(var->type)); + + // add var + varDecls.push_back(var); +} + +////////////////////////////////////////// + +const LLType* IrStruct::build() +{ + // if types is empty, add a byte + if (types.empty()) + { + types.push_back(LLType::Int8Ty); + } + + // union type + if (aggrdecl->isUnionDeclaration()) + { + const LLType* biggest = getBiggestType(&types[0], types.size()); + std::vector vec(1, biggest); + return LLStructType::get(vec, aggrdecl->ir.irStruct->packed); + } + // struct/class type + else + { + return LLStructType::get(types, aggrdecl->ir.irStruct->packed); + } +} + +void addZeros(std::vector& inits, size_t pos, size_t offset) +{ + assert(offset > pos); + size_t diff = offset - pos; + + size_t sz; + + do { - assert(!v->ir.isSet()); - v->ir.irField = new IrField(v); + if (pos%8 == 0 && diff >= 8) + sz = 8; + else if (pos%4 == 0 && diff >= 4) + sz = 4; + else if (pos%2 == 0 && diff >= 2) + sz = 2; + else // if (pos % 1 == 0) + sz = 1; + inits.push_back(LLIntegerType::get(sz*8)); + pos += sz; + diff -= sz; + } while (pos < offset); + + assert(pos == offset); +} + +void addZeros(std::vector& inits, size_t pos, size_t offset) +{ + assert(offset > pos); + size_t diff = offset - pos; + + size_t sz; + + do + { + if (pos%8 == 0 && diff >= 8) + sz = 8; + else if (pos%4 == 0 && diff >= 4) + sz = 4; + else if (pos%2 == 0 && diff >= 2) + sz = 2; + else // if (pos % 1 == 0) + sz = 1; + inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8))); + pos += sz; + diff -= sz; + } while (pos < offset); + + assert(pos == offset); +} + +// FIXME: body is exact copy of above +void addZeros(std::vector& inits, size_t pos, size_t offset) +{ + assert(offset > pos); + size_t diff = offset - pos; + + size_t sz; + + do + { + if (pos%8 == 0 && diff >= 8) + sz = 8; + else if (pos%4 == 0 && diff >= 4) + sz = 4; + else if (pos%2 == 0 && diff >= 2) + sz = 2; + else // if (pos % 1 == 0) + sz = 1; + inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8))); + pos += sz; + diff -= sz; + } while (pos < offset); + + assert(pos == offset); +} + +void IrStruct::buildDefaultConstInit(std::vector& inits) +{ + assert(!defaultFound); + defaultFound = true; + + const llvm::StructType* structtype = isaStruct(aggrdecl->type->ir.type->get()); + Logger::cout() << "struct type: " << *structtype << '\n'; + + size_t lastoffset = 0; + size_t lastsize = 0; + + { + Logger::println("Find the default fields"); + LOG_SCOPE; + + // go through all vars and find the ones that contribute to the default + size_t nvars = varDecls.size(); + for (size_t i=0; itype->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); + + // 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"); + lastoffset = offset; + lastsize = size; + defVars.push_back(var); + } + } } - const LLType* _type = DtoType(v->type); - offsets.insert(std::make_pair(v->offset, IrStruct::Offset(v, _type))); + + { + Logger::println("Build the default initializer"); + LOG_SCOPE; + + lastoffset = 0; + 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; itype->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 + assert(var->ir.irField->constInit); + inits.push_back(var->ir.irField->constInit); + + lastoffset = offset; + lastsize = var->type->size(); + } + + // there might still be padding after the last one, make sure that is zeroed as well + // is there space in between last last offset and this one? + size_t structsize = getABITypeSize(structtype); + + if (structsize > lastoffset+lastsize) + { + size_t pos = lastoffset + lastsize; + addZeros(inits, pos, structsize); + } + } } + +LLConstant* IrStruct::buildDefaultConstInit() +{ + // doesn't work for classes, they add stuff before and maybe after data fields + assert(!aggrdecl->isClassDeclaration()); + + // initializer llvm constant list + std::vector inits; + + // just start with an empty list + buildDefaultConstInit(inits); + + // build the constant + // note that the type matches the initializer, not the aggregate in cases with unions + LLConstant* c = LLConstantStruct::get(inits, aggrdecl->ir.irStruct->packed); + Logger::cout() << "llvm constant: " << *c << '\n'; +// assert(0); + return c; +} diff -r 6e7a4c3b64d2 -r 340acf1535d0 ir/irstruct.h --- a/ir/irstruct.h Sat Nov 29 12:28:10 2008 +0100 +++ b/ir/irstruct.h Sat Nov 29 21:25:43 2008 +0100 @@ -6,86 +6,168 @@ #include #include -struct IrInterface : IrBase -{ - BaseClass* base; - ClassDeclaration* decl; - - llvm::PATypeHolder* vtblTy; - LLConstant* vtblInit; - LLGlobalVariable* vtbl; - - const LLStructType* infoTy; - LLConstantStruct* infoInit; - LLConstant* info; - - int index; - - IrInterface(BaseClass* b); - ~IrInterface(); -}; +struct IrInterface; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // represents a struct or class +// it is used during codegen to hold all the vital info we need struct IrStruct : IrBase { - struct Offset - { - VarDeclaration* var; - const LLType* type; - LLConstant* init; + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// - Offset(VarDeclaration* v, const LLType* ty) - : var(v), type(ty), init(NULL) {} - }; + typedef std::vector VarDeclVector; - typedef std::multimap OffsetMap; - typedef std::vector VarDeclVector; - typedef std::map InterfaceMap; - typedef InterfaceMap::iterator InterfaceMapIter; + typedef std::map InterfaceMap; + typedef InterfaceMap::iterator InterfaceMapIter; + typedef std::vector InterfaceVector; typedef InterfaceVector::iterator InterfaceVectorIter; -public: - IrStruct(Type*); + // vector of LLVM types + typedef std::vector TypeVector; + + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + + // Anon represents an anonymous struct union block inside an aggregate + // during LLVM type construction. + struct Anon + { + bool isunion; + Anon* parent; + + TypeVector types; + + Anon(bool IsUnion, Anon* par) : isunion(IsUnion), parent(par) {} + }; + + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + + /// ctor + IrStruct(AggregateDeclaration* agg); + + /// dtor virtual ~IrStruct(); - void addField(VarDeclaration* v); + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + + /// push an anonymous struct/union + void pushAnon(bool isunion); + + /// pops an anonymous struct/union + void popAnon(); + + /// adds field + void addVar(VarDeclaration* var); + + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + + /// build the aggr type + const LLType* build(); + + /// put the aggr initializers in a vector + void buildDefaultConstInit(std::vector& inits); + + /// ditto - but also builds the constant struct, for convenience + LLConstant* buildDefaultConstInit(); + ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + + // the D aggregate + AggregateDeclaration* aggrdecl; + + // vector of VarDeclarations in this aggregate + VarDeclVector varDecls; + + // vector of VarDeclarations that contribute to the default initializer + VarDeclVector defVars; + + // true if the default initializer has been built + bool defaultFound; + + // top element + Anon* anon; + + // toplevel types in this aggr + TypeVector types; + + // current index + // always the same as types.size() + size_t index; + + // aggregate D type Type* type; - llvm::PATypeHolder recty; - OffsetMap offsets; - VarDeclVector defaultFields; + + // class vtable type + llvm::PATypeHolder vtblTy; + llvm::PATypeHolder vtblInitTy; + // initializer type opaque (type of global matches initializer, not formal type) + llvm::PATypeHolder initOpaque; + llvm::PATypeHolder classInfoOpaque; + + // map/vector of interfaces implemented InterfaceMap interfaceMap; InterfaceVector interfaceVec; - const llvm::ArrayType* interfaceInfosTy; + + // interface info array global LLGlobalVariable* interfaceInfos; + // ... bool defined; bool constinited; + // vtbl global and initializer LLGlobalVariable* vtbl; -#if OPAQUE_VTBLS LLConstant* constVtbl; -#else - LLConstantStruct* constVtbl; -#endif + + // static initializers global and constant LLGlobalVariable* init; LLConstant* constInit; + + // classinfo global and initializer constant LLGlobalVariable* classInfo; LLConstant* constClassInfo; - bool hasUnions; - DUnion* dunion; - bool classDeclared; - bool classDefined; + bool classInfoDeclared; + bool classInfoDefined; - bool packed; // true for: align(1) struct S { ... } + // align(1) struct S { ... } + bool packed; + // dwarf composite global LLGlobalVariable* dwarfComposite; }; +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// represents interface implemented by a class +struct IrInterface : IrBase +{ + BaseClass* base; + ClassDeclaration* decl; + + llvm::PATypeHolder vtblInitTy; + + LLConstant* vtblInit; + LLGlobalVariable* vtbl; + + const LLStructType* infoTy; + LLConstant* infoInit; + LLConstant* info; + + size_t index; + + IrInterface(BaseClass* b); +}; + #endif diff -r 6e7a4c3b64d2 -r 340acf1535d0 ir/irtype.cpp --- a/ir/irtype.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/ir/irtype.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -21,9 +21,6 @@ { assert(list.insert(this).second); type = s.type; -#if OPAQUE_VTBLS - vtblType = s.type; -#endif } IrType::~IrType() @@ -34,7 +31,4 @@ void IrType::reset() { type = NULL; -#if OPAQUE_VTBLS - vtblType = NULL; -#endif } diff -r 6e7a4c3b64d2 -r 340acf1535d0 ir/irtype.h --- a/ir/irtype.h Sat Nov 29 12:28:10 2008 +0100 +++ b/ir/irtype.h Sat Nov 29 21:25:43 2008 +0100 @@ -21,7 +21,6 @@ void reset(); llvm::PATypeHolder* type; - llvm::PATypeHolder* vtblType; }; #endif diff -r 6e7a4c3b64d2 -r 340acf1535d0 ir/irvar.cpp --- a/ir/irvar.cpp Sat Nov 29 12:28:10 2008 +0100 +++ b/ir/irvar.cpp Sat Nov 29 21:25:43 2008 +0100 @@ -1,4 +1,4 @@ -#include "llvm/DerivedTypes.h" +#include "gen/llvm.h" #include "declaration.h" #include "ir/irvar.h" @@ -38,8 +38,8 @@ IrField::IrField(VarDeclaration* v) : IrVar(v) { - index = -1; - indexOffset = 0; + index = 0; + unionOffset = 0; constInit = NULL; } diff -r 6e7a4c3b64d2 -r 340acf1535d0 ir/irvar.h --- a/ir/irvar.h Sat Nov 29 12:28:10 2008 +0100 +++ b/ir/irvar.h Sat Nov 29 21:25:43 2008 +0100 @@ -34,8 +34,9 @@ { IrField(VarDeclaration* v); - int index; - size_t indexOffset; + unsigned index; + unsigned unionOffset; + llvm::Constant* constInit; }; diff -r 6e7a4c3b64d2 -r 340acf1535d0 llvmdc.kdevelop --- a/llvmdc.kdevelop Sat Nov 29 12:28:10 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,684 +0,0 @@ - - - - Tomas Lindquist Olsen - tomas.l.olsen@gmail.com - 0.1 - KDevCustomProject - C++ - - C++ - Code - - - llvmdc - . - false - - - kdevsubversion - - - - - - - optimized - kdevgccoptions - kdevgppoptions - kdevg77options - -O2 -g0 - - - --enable-debug=full - debug - kdevgccoptions - kdevgppoptions - kdevg77options - -O0 -g3 - - - - - - ada - ada_bugs_gcc - bash - bash_bugs - clanlib - w3c-dom-level2-html - fortran_bugs_gcc - gnome1 - gnustep - gtk - gtk_bugs - haskell - haskell_bugs_ghc - java_bugs_gcc - java_bugs_sun - kde2book - opengl - pascal_bugs_fp - php - php_bugs - perl - perl_bugs - python - python_bugs - qt-kdev3 - ruby - ruby_bugs - sdl - w3c-svg - sw - w3c-uaag10 - wxwidgets_bugs - - - Guide to the Qt Translation Tools - Qt Assistant Manual - Qt Designer Manual - Qt Reference Documentation - qmake User Guide - - - KDE Libraries (Doxygen) - - - - - - - - - - - - - - true - false - - - *.bc - false - false - - - - - Doxygen Documentation Collection - llvmdc.tag - - - - llvmdc - llvmdc - Llvmdc - LLVMDC - Tomas Lindquist Olsen - tomas.l.olsen@gmail.com - GPL - COPYING - 0.1 - 2007 - /home/tomas/projects/llvmdc - - - - false - 3 - 3 - /opt/qt - EmbeddedKDevDesigner - /opt/qt/bin/qmake - /opt/qt/bin/designer - - - - false - true - true - 250 - 400 - 250 - false - 0 - true - true - false - std=_GLIBCXX_STD;__gnu_cxx=std - true - false - true - false - false - true - true - false - .; - - - - set - m_,_ - theValue - true - true - - - false - true - Vertical - - - - - - executable - /home/tomas/kdevprojects/llvmdc - - - /home/tomas/kdevprojects/llvmdc - false - false - false - false - false - - - - *.h - *.c - *.cpp - build.sh - - - demos - demos/ray.cpp - dmdorig - dmdorig/dmd - dmdorig/dmd/access.c - dmdorig/dmd/aggregate.h - dmdorig/dmd/array.c - dmdorig/dmd/arraytypes.h - dmdorig/dmd/attrib.c - dmdorig/dmd/attrib.h - dmdorig/dmd/bit.c - dmdorig/dmd/cast.c - dmdorig/dmd/class.c - dmdorig/dmd/complex_t.h - dmdorig/dmd/cond.c - dmdorig/dmd/cond.h - dmdorig/dmd/constfold.c - dmdorig/dmd/dchar.c - dmdorig/dmd/dchar.h - dmdorig/dmd/declaration.c - dmdorig/dmd/declaration.h - dmdorig/dmd/delegatize.c - dmdorig/dmd/doc.c - dmdorig/dmd/doc.h - dmdorig/dmd/dsymbol.c - dmdorig/dmd/dsymbol.h - dmdorig/dmd/dump.c - dmdorig/dmd/entity.c - dmdorig/dmd/enum.c - dmdorig/dmd/enum.h - dmdorig/dmd/expression.c - dmdorig/dmd/expression.h - dmdorig/dmd/func.c - dmdorig/dmd/gnuc.c - dmdorig/dmd/gnuc.h - dmdorig/dmd/hdrgen.c - dmdorig/dmd/hdrgen.h - dmdorig/dmd/html.c - dmdorig/dmd/html.h - dmdorig/dmd/identifier.c - dmdorig/dmd/identifier.h - dmdorig/dmd/idgen.c - dmdorig/dmd/impcnvgen.c - dmdorig/dmd/import.c - dmdorig/dmd/import.h - dmdorig/dmd/inifile.c - dmdorig/dmd/init.c - dmdorig/dmd/init.h - dmdorig/dmd/inline.c - dmdorig/dmd/interpret.c - dmdorig/dmd/lexer.c - dmdorig/dmd/lexer.h - dmdorig/dmd/link.c - dmdorig/dmd/lstring.c - dmdorig/dmd/lstring.h - dmdorig/dmd/macro.c - dmdorig/dmd/macro.h - dmdorig/dmd/mangle.c - dmdorig/dmd/mars.c - dmdorig/dmd/mars.h - dmdorig/dmd/mem.c - dmdorig/dmd/mem.h - dmdorig/dmd/module.c - dmdorig/dmd/module.h - dmdorig/dmd/mtype.c - dmdorig/dmd/mtype.h - dmdorig/dmd/opover.c - dmdorig/dmd/optimize.c - dmdorig/dmd/parse.c - dmdorig/dmd/parse.h - dmdorig/dmd/port.h - dmdorig/dmd/root.c - dmdorig/dmd/root.h - dmdorig/dmd/scope.c - dmdorig/dmd/scope.h - dmdorig/dmd/statement.c - dmdorig/dmd/statement.h - dmdorig/dmd/staticassert.c - dmdorig/dmd/staticassert.h - dmdorig/dmd/stringtable.c - dmdorig/dmd/stringtable.h - dmdorig/dmd/struct.c - dmdorig/dmd/template.c - dmdorig/dmd/template.h - dmdorig/dmd/tocsym.c - dmdorig/dmd/todt.c - dmdorig/dmd/toir.c - dmdorig/dmd/toir.h - dmdorig/dmd/toobj.c - dmdorig/dmd/total.h - dmdorig/dmd/typinf.c - dmdorig/dmd/unialpha.c - dmdorig/dmd/utf.c - dmdorig/dmd/utf.h - dmdorig/dmd/version.c - dmdorig/dmd/version.h - dmdorig/phobos - dmdorig/phobos/errno.c - dmdorig/phobos/etc - dmdorig/phobos/etc/c - dmdorig/phobos/etc/c/zlib - dmdorig/phobos/etc/c/zlib/adler32.c - dmdorig/phobos/etc/c/zlib/compress.c - dmdorig/phobos/etc/c/zlib/crc32.c - dmdorig/phobos/etc/c/zlib/crc32.h - dmdorig/phobos/etc/c/zlib/deflate.c - dmdorig/phobos/etc/c/zlib/deflate.h - dmdorig/phobos/etc/c/zlib/example.c - dmdorig/phobos/etc/c/zlib/gzio.c - dmdorig/phobos/etc/c/zlib/infback.c - dmdorig/phobos/etc/c/zlib/inffast.c - dmdorig/phobos/etc/c/zlib/inffast.h - dmdorig/phobos/etc/c/zlib/inffixed.h - dmdorig/phobos/etc/c/zlib/inflate.c - dmdorig/phobos/etc/c/zlib/inflate.h - dmdorig/phobos/etc/c/zlib/inftrees.c - dmdorig/phobos/etc/c/zlib/inftrees.h - dmdorig/phobos/etc/c/zlib/minigzip.c - dmdorig/phobos/etc/c/zlib/trees.c - dmdorig/phobos/etc/c/zlib/trees.h - dmdorig/phobos/etc/c/zlib/uncompr.c - dmdorig/phobos/etc/c/zlib/zconf.h - dmdorig/phobos/etc/c/zlib/zconf.in.h - dmdorig/phobos/etc/c/zlib/zlib.h - dmdorig/phobos/etc/c/zlib/zutil.c - dmdorig/phobos/etc/c/zlib/zutil.h - dmdorig/phobos/internal - dmdorig/phobos/internal/complex.c - dmdorig/phobos/internal/critical.c - dmdorig/phobos/internal/deh.c - dmdorig/phobos/internal/mars.h - dmdorig/phobos/internal/monitor.c - lphobos - lphobos/build.sh - suite - suite/dwarfdebug - suite/dwarfdebug/dwarf1 - suite/dwarfdebug/dwarf1/build.sh - suite/dwarfdebug/dwarf2 - suite/dwarfdebug/dwarf2/build.sh - tango - tango/lib - tango/lib/common - tango/lib/common/tango - tango/lib/common/tango/stdc - tango/lib/common/tango/stdc/wrap.c - tango/lib/compiler - tango/lib/compiler/llvmdc - tango/lib/compiler/llvmdc/critical.c - tango/lib/compiler/llvmdc/mars.h - tango/lib/compiler/llvmdc/monitor.c - tests - tests/dstress - tests/dstress/benchmark - tests/dstress/benchmark/ackermann - tests/dstress/benchmark/ackermann/ackermann_c.c - tests/dstress/benchmark/cowell-shah - tests/dstress/benchmark/cowell-shah/benchmark.c - tests/dstress/benchmark/known_gcc_problems - tests/dstress/benchmark/known_gcc_problems/common_subexpressions_01_c.c - tests/dstress/benchmark/oopack - tests/dstress/benchmark/oopack/oopack_v1p8_cpp.cpp - tests/dstress/crashRun.c - tests/dstress/dstress.c - tests/dstress/extract__.c - tests/dstress/ifeq__.c - tests/dstress/return__.c - e2ir.c - tango-llvmdc - tango-llvmdc/lib - tango-llvmdc/lib/common - tango-llvmdc/lib/common/tango - tango-llvmdc/lib/common/tango/stdc - tango-llvmdc/lib/common/tango/stdc/wrap.c - tango-llvmdc/lib/compiler - tango-llvmdc/lib/compiler/dmd - tango-llvmdc/lib/compiler/dmd/complex.c - tango-llvmdc/lib/compiler/dmd/critical.c - tango-llvmdc/lib/compiler/dmd/deh.c - tango-llvmdc/lib/compiler/dmd/mars.h - tango-llvmdc/lib/compiler/dmd/monitor.c - tango-llvmdc/lib/compiler/gdc - tango-llvmdc/lib/compiler/gdc/config - tango-llvmdc/lib/compiler/gdc/config/gen_config1.c - tango-llvmdc/lib/compiler/gdc/config/gen_math.c - tango-llvmdc/lib/compiler/gdc/config/gen_unix.c - tango-llvmdc/lib/compiler/gdc/config/makestruct.h - tango-llvmdc/lib/compiler/gdc/critical.c - tango-llvmdc/lib/compiler/gdc/deh.c - tango-llvmdc/lib/compiler/gdc/gcc - tango-llvmdc/lib/compiler/gdc/gcc/aix_float.h - tango-llvmdc/lib/compiler/gdc/gcc/cbridge_fdset.c - tango-llvmdc/lib/compiler/gdc/gcc/cbridge_math.c - tango-llvmdc/lib/compiler/gdc/gcc/cbridge_stdio.c - tango-llvmdc/lib/compiler/gdc/gcc/cbridge_time.c - tango-llvmdc/lib/compiler/gdc/mars.h - tango-llvmdc/lib/compiler/gdc/memory_dyld.c - tango-llvmdc/lib/compiler/gdc/memory_freebsd.c - tango-llvmdc/lib/compiler/gdc/monitor.c - tango-llvmdc/lib/compiler/llvmdc - tango-llvmdc/lib/compiler/llvmdc/critical.c - tango-llvmdc/lib/compiler/llvmdc/mars.h - tango-llvmdc/lib/compiler/llvmdc/monitor.c - tango-llvmdc/patches - tango-llvmdc/patches/proposals - tango-llvmdc/patches/proposals/integrated_locks - tango-llvmdc/patches/proposals/integrated_locks/lib - tango-llvmdc/patches/proposals/integrated_locks/lib/compiler - tango-llvmdc/patches/proposals/integrated_locks/lib/compiler/dmd - tango-llvmdc/patches/proposals/integrated_locks/lib/compiler/dmd/monitor.c - tango-llvmdc/patches/proposals/integrated_locks/lib/compiler/gdc - tango-llvmdc/patches/proposals/integrated_locks/lib/compiler/gdc/monitor.c - runtime/build.sh - runtime/internal - runtime/internal/critical.c - runtime/internal/mars.h - runtime/internal/monitor.c - build - build/CMakeFiles - build/CMakeFiles/CompilerIdC - build/CMakeFiles/CompilerIdC/CMakeCCompilerId.c - build/CMakeFiles/CompilerIdCXX - build/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp - build/dmd - build/dmd/id.c - build/dmd/id.h - build/dmd/impcnvtab.c - dmd2.020 - dmd2.020/access.c - dmd2.020/aggregate.h - dmd2.020/array.c - dmd2.020/arrayop.c - dmd2.020/arraytypes.h - dmd2.020/attrib.c - dmd2.020/attrib.h - dmd2.020/bit.c - dmd2.020/builtin.c - dmd2.020/cast.c - dmd2.020/class.c - dmd2.020/clone.c - dmd2.020/complex_t.h - dmd2.020/cond.c - dmd2.020/cond.h - dmd2.020/constfold.c - dmd2.020/dchar.c - dmd2.020/dchar.h - dmd2.020/declaration.c - dmd2.020/declaration.h - dmd2.020/delegatize.c - dmd2.020/doc.c - dmd2.020/doc.h - dmd2.020/dsymbol.c - dmd2.020/dsymbol.h - dmd2.020/dump.c - dmd2.020/e2ir.c - dmd2.020/entity.c - dmd2.020/enum.c - dmd2.020/enum.h - dmd2.020/expression.c - dmd2.020/expression.h - dmd2.020/func.c - dmd2.020/gnuc.c - dmd2.020/gnuc.h - dmd2.020/hdrgen.c - dmd2.020/hdrgen.h - dmd2.020/html.c - dmd2.020/html.h - dmd2.020/identifier.c - dmd2.020/identifier.h - dmd2.020/idgen.c - dmd2.020/impcnvgen.c - dmd2.020/import.c - dmd2.020/import.h - dmd2.020/inifile.c - dmd2.020/init.c - dmd2.020/init.h - dmd2.020/inline.c - dmd2.020/interpret.c - dmd2.020/lexer.c - dmd2.020/lexer.h - dmd2.020/lib.h - dmd2.020/libelf.c - dmd2.020/link.c - dmd2.020/lstring.c - dmd2.020/lstring.h - dmd2.020/macro.c - dmd2.020/macro.h - dmd2.020/man.c - dmd2.020/mangle.c - dmd2.020/mars.c - dmd2.020/mars.h - dmd2.020/md5.c - dmd2.020/md5.h - dmd2.020/mem.c - dmd2.020/mem.h - dmd2.020/module.c - dmd2.020/module.h - dmd2.020/mtype.c - dmd2.020/mtype.h - dmd2.020/opover.c - dmd2.020/optimize.c - dmd2.020/parse.c - dmd2.020/parse.h - dmd2.020/port.h - dmd2.020/root.c - dmd2.020/root.h - dmd2.020/scope.c - dmd2.020/scope.h - dmd2.020/statement.c - dmd2.020/statement.h - dmd2.020/staticassert.c - dmd2.020/staticassert.h - dmd2.020/stringtable.c - dmd2.020/stringtable.h - dmd2.020/struct.c - dmd2.020/template.c - dmd2.020/template.h - dmd2.020/tocsym.c - dmd2.020/todt.c - dmd2.020/toir.c - dmd2.020/toir.h - dmd2.020/toobj.c - dmd2.020/total.h - dmd2.020/traits.c - dmd2.020/typinf.c - dmd2.020/unialpha.c - dmd2.020/utf.c - dmd2.020/utf.h - dmd2.020/version.c - dmd2.020/version.h - dmd36 - dmd36/access.c - dmd36/aggregate.h - dmd36/array.c - dmd36/arrayop.c - dmd36/arraytypes.h - dmd36/attrib.c - dmd36/attrib.h - dmd36/bit.c - dmd36/cast.c - dmd36/class.c - dmd36/clone.c - dmd36/complex_t.h - dmd36/cond.c - dmd36/cond.h - dmd36/constfold.c - dmd36/dchar.c - dmd36/dchar.h - dmd36/declaration.c - dmd36/declaration.h - dmd36/delegatize.c - dmd36/doc.c - dmd36/doc.h - dmd36/dsymbol.c - dmd36/dsymbol.h - dmd36/dump.c - dmd36/e2ir.c - dmd36/entity.c - dmd36/enum.c - dmd36/enum.h - dmd36/expression.c - dmd36/expression.h - dmd36/func.c - dmd36/gnuc.c - dmd36/gnuc.h - dmd36/hdrgen.c - dmd36/hdrgen.h - dmd36/html.c - dmd36/html.h - dmd36/identifier.c - dmd36/identifier.h - dmd36/idgen.c - dmd36/impcnvgen.c - dmd36/import.c - dmd36/import.h - dmd36/inifile.c - dmd36/init.c - dmd36/init.h - dmd36/inline.c - dmd36/interpret.c - dmd36/lexer.c - dmd36/lexer.h - dmd36/lib.h - dmd36/libelf.c - dmd36/link.c - dmd36/lstring.c - dmd36/lstring.h - dmd36/macro.c - dmd36/macro.h - dmd36/man.c - dmd36/mangle.c - dmd36/mars.c - dmd36/mars.h - dmd36/md5.c - dmd36/md5.h - dmd36/mem.c - dmd36/mem.h - dmd36/module.c - dmd36/module.h - dmd36/mtype.c - dmd36/mtype.h - dmd36/opover.c - dmd36/optimize.c - dmd36/parse.c - dmd36/parse.h - dmd36/port.h - dmd36/root.c - dmd36/root.h - dmd36/scope.c - dmd36/scope.h - dmd36/statement.c - dmd36/statement.h - dmd36/staticassert.c - dmd36/staticassert.h - dmd36/stringtable.c - dmd36/stringtable.h - dmd36/struct.c - dmd36/template.c - dmd36/template.h - dmd36/tocsym.c - dmd36/todt.c - dmd36/toir.c - dmd36/toir.h - dmd36/toobj.c - dmd36/total.h - dmd36/typinf.c - dmd36/unialpha.c - dmd36/utf.c - dmd36/utf.h - dmd36/version.c - dmd36/version.h - - - make - - - - 0 - - - - default - - - - - - false - 0 - 0 - false - - - - default - - - - - - tangotests - - - - - .h - .cpp - - - - - - - - - - true - false - false - false - - - false - true - 10 - - - diff -r 6e7a4c3b64d2 -r 340acf1535d0 llvmdc.kdevelop.filelist --- a/llvmdc.kdevelop.filelist Sat Nov 29 12:28:10 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -# KDevelop Custom Project File List -dmd -dmd/access.c -dmd/aggregate.h -dmd/array.c -dmd/arrayop.c -dmd/arraytypes.h -dmd/attrib.c -dmd/attrib.h -dmd/cast.c -dmd/class.c -dmd/clone.c -dmd/complex_t.h -dmd/cond.c -dmd/cond.h -dmd/constfold.c -dmd/dchar.c -dmd/dchar.h -dmd/declaration.c -dmd/declaration.h -dmd/delegatize.c -dmd/doc.c -dmd/doc.h -dmd/dsymbol.c -dmd/dsymbol.h -dmd/dump.c -dmd/entity.c -dmd/enum.c -dmd/enum.h -dmd/expression.c -dmd/expression.h -dmd/func.c -dmd/gnuc.c -dmd/gnuc.h -dmd/hdrgen.c -dmd/hdrgen.h -dmd/html.c -dmd/html.h -dmd/identifier.c -dmd/identifier.h -dmd/idgen.c -dmd/impcnvgen.c -dmd/import.c -dmd/import.h -dmd/inifile.c -dmd/init.c -dmd/init.h -dmd/inline.c -dmd/interpret.c -dmd/lexer.c -dmd/lexer.h -dmd/lstring.c -dmd/lstring.h -dmd/macro.c -dmd/macro.h -dmd/mangle.c -dmd/mars.c -dmd/mars.h -dmd/mem.c -dmd/mem.h -dmd/module.c -dmd/module.h -dmd/mtype.c -dmd/mtype.h -dmd/opover.c -dmd/optimize.c -dmd/parse.c -dmd/parse.h -dmd/port.h -dmd/root.c -dmd/root.h -dmd/scope.c -dmd/scope.h -dmd/statement.c -dmd/statement.h -dmd/staticassert.c -dmd/staticassert.h -dmd/stringtable.c -dmd/stringtable.h -dmd/struct.c -dmd/template.c -dmd/template.h -dmd/total.h -dmd/unialpha.c -dmd/utf.c -dmd/utf.h -dmd/version.c -dmd/version.h -dmd2 -dmd2/access.c -dmd2/aggregate.h -dmd2/array.c -dmd2/arrayop.c -dmd2/arraytypes.h -dmd2/attrib.c -dmd2/attrib.h -dmd2/builtin.c -dmd2/cast.c -dmd2/class.c -dmd2/clone.c -dmd2/complex_t.h -dmd2/cond.c -dmd2/cond.h -dmd2/constfold.c -dmd2/dchar.c -dmd2/dchar.h -dmd2/declaration.c -dmd2/declaration.h -dmd2/delegatize.c -dmd2/doc.c -dmd2/doc.h -dmd2/dsymbol.c -dmd2/dsymbol.h -dmd2/dump.c -dmd2/entity.c -dmd2/enum.c -dmd2/enum.h -dmd2/expression.c -dmd2/expression.h -dmd2/func.c -dmd2/gnuc.c -dmd2/gnuc.h -dmd2/hdrgen.c -dmd2/hdrgen.h -dmd2/html.c -dmd2/html.h -dmd2/id.c -dmd2/id.h -dmd2/identifier.c -dmd2/identifier.h -dmd2/idgen.c -dmd2/impcnvgen.c -dmd2/impcnvtab.c -dmd2/import.c -dmd2/import.h -dmd2/inifile.c -dmd2/init.c -dmd2/init.h -dmd2/inline.c -dmd2/interpret.c -dmd2/lexer.c -dmd2/lexer.h -dmd2/lstring.c -dmd2/lstring.h -dmd2/macro.c -dmd2/macro.h -dmd2/man.c -dmd2/mangle.c -dmd2/mars.c -dmd2/mars.h -dmd2/mem.c -dmd2/mem.h -dmd2/module.c -dmd2/module.h -dmd2/mtype.c -dmd2/mtype.h -dmd2/opover.c -dmd2/optimize.c -dmd2/parse.c -dmd2/parse.h -dmd2/port.h -dmd2/root.c -dmd2/root.h -dmd2/scope.c -dmd2/scope.h -dmd2/statement.c -dmd2/statement.h -dmd2/staticassert.c -dmd2/staticassert.h -dmd2/stringtable.c -dmd2/stringtable.h -dmd2/struct.c -dmd2/template.c -dmd2/template.h -dmd2/total.h -dmd2/traits.c -dmd2/unialpha.c -dmd2/utf.c -dmd2/utf.h -dmd2/version.c -dmd2/version.h -gen -gen/aa.cpp -gen/aa.h -gen/arrays.cpp -gen/arrays.h -gen/asmstmt.cpp -gen/binops.cpp -gen/classes.cpp -gen/classes.h -gen/complex.cpp -gen/complex.h -gen/dvalue.cpp -gen/dvalue.h -gen/dwarftypes.cpp -gen/enums.h -gen/functions.cpp -gen/functions.h -gen/irstate.cpp -gen/irstate.h -gen/linker.cpp -gen/linker.h -gen/llvm.h -gen/llvmhelpers.cpp -gen/llvmhelpers.h -gen/logger.cpp -gen/logger.h -gen/optimizer.cpp -gen/runtime.cpp -gen/runtime.h -gen/statements.cpp -gen/structs.cpp -gen/structs.h -gen/tocall.cpp -gen/tocsym.cpp -gen/todebug.cpp -gen/todebug.h -gen/todt.cpp -gen/toir.cpp -gen/tollvm.cpp -gen/tollvm.h -gen/toobj.cpp -gen/typeinf.h -gen/typinf.cpp -ir -ir/ir.h -ir/irforw.h -ir/irfunction.cpp -ir/irfunction.h -ir/irmodule.cpp -ir/irmodule.h -ir/irstruct.cpp -ir/irstruct.h -ir/irsymbol.cpp -ir/irsymbol.h -ir/irtype.cpp -ir/irtype.h -ir/irvar.cpp -ir/irvar.h diff -r 6e7a4c3b64d2 -r 340acf1535d0 tests/mini/interface3.d --- a/tests/mini/interface3.d Sat Nov 29 12:28:10 2008 +0100 +++ b/tests/mini/interface3.d Sat Nov 29 21:25:43 2008 +0100 @@ -12,14 +12,14 @@ int i = 42; override void func() { - printf("hello %d\n", i); + printf("hello %d from %p\n", i, this); i++; } } void main() { - scope c = new C; + auto c = new C; {c.func();} { I i = c;