# HG changeset patch # User Tomas Lindquist Olsen # Date 1228072929 -3600 # Node ID 69a5e4a6fc0ffc86328b2bc8de37d573b6aae173 # Parent 4ad1e7b1037814951f4b6782bbca39d28114baaa Changed some hardcoded offset/alignment for classes in DMD, broke offsets for 64bits. Changed ClassInfo generation to no longer access the default initializer of ClassInfo, fixes problems with index mismatch. diff -r 4ad1e7b10378 -r 69a5e4a6fc0f dmd/class.c --- a/dmd/class.c Sun Nov 30 19:19:39 2008 +0100 +++ b/dmd/class.c Sun Nov 30 20:22:09 2008 +0100 @@ -551,8 +551,8 @@ // sc->offset += PTRSIZE; // room for uplevel context pointer } else - { sc->offset = 8; // allow room for vptr[] and monitor - alignsize = 4; + { sc->offset = 2*PTRSIZE; // allow room for vptr[] and monitor + alignsize = PTRSIZE; } structsize = sc->offset; Scope scsave = *sc; @@ -1139,7 +1139,7 @@ sc->linkage = LINKwindows; sc->structalign = 8; structalign = sc->structalign; - sc->offset = 8; + sc->offset = 2*PTRSIZE; inuse++; for (i = 0; i < members->dim; i++) { diff -r 4ad1e7b10378 -r 69a5e4a6fc0f dmd2/class.c --- a/dmd2/class.c Sun Nov 30 19:19:39 2008 +0100 +++ b/dmd2/class.c Sun Nov 30 20:22:09 2008 +0100 @@ -559,7 +559,7 @@ } else { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor - alignsize = 4; + alignsize = PTRSIZE; } structsize = sc->offset; Scope scsave = *sc; diff -r 4ad1e7b10378 -r 69a5e4a6fc0f gen/classes.cpp --- a/gen/classes.cpp Sun Nov 30 19:19:39 2008 +0100 +++ b/gen/classes.cpp Sun Nov 30 20:22:09 2008 +0100 @@ -75,6 +75,8 @@ iri->index = irstruct->index++; } +////////////////////////////////////////////////////////////////////////////////////////// + static void add_class_data(ClassDeclaration* target, ClassDeclaration* cd) { Logger::println("Adding data from class: %s", cd->toChars()); @@ -443,7 +445,7 @@ std::vector defVars; defVars.reserve(nfields); - size_t lastoffset = offsetbegin; // vtbl,monitor + size_t lastoffset = offsetbegin; size_t lastsize = 0; // find fields that contribute to default @@ -455,13 +457,21 @@ size_t size = var->type->size(); if (offset >= lastoffset+lastsize) { - Logger::println(" added"); + Logger::println(" added %s", var->toChars()); lastoffset = offset; lastsize = size; defVars.push_back(var); } + else + { + Logger::println(" skipped %s", var->toChars()); + } } + // reset offsets, we're going from beginning again + lastoffset = offsetbegin; + lastsize = 0; + // go through the default vars and build the default constant initializer // adding zeros along the way to live up to alignment expectations size_t nvars = defVars.size(); @@ -760,11 +770,13 @@ { // always do interface info array when possible std::vector infoInits; - infoInits.reserve(irstruct->interfaceVec.size()); + + size_t n = irstruct->interfaceVec.size(); + infoInits.reserve(n); - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) + for (size_t i=0; i < n; i++) { - IrInterface* iri = *i; + IrInterface* iri = irstruct->interfaceVec[i]; assert(iri->infoInit); infoInits.push_back(iri->infoInit); } @@ -834,13 +846,13 @@ 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; - } +// if (Logger::enabled()) +// { +// Logger::cout() << "initZ: " << *irstruct->init << std::endl; +// Logger::cout() << "cinitZ: " << *irstruct->constInit << std::endl; +// Logger::cout() << "vtblZ: " << *irstruct->vtbl << std::endl; +// Logger::cout() << "cvtblZ: " << *irstruct->constVtbl << std::endl; +// } // set initializers irstruct->init->setInitializer(irstruct->constInit); @@ -1184,29 +1196,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx) -{ - // start at the bottom of the inheritance chain - if (cd->baseClass != 0) { - unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx); - if (o != (unsigned)-1) - return o; - } - - // check this class - unsigned i; - for (i=0; ifields.dim; ++i) { - VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i]; - if (os == vd->offset) - return i+idx; - } - idx += i; - - return (unsigned)-1; -} - -////////////////////////////////////////////////////////////////////////////////////////// - LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) { Logger::println("indexing class field %s:", vd->toPrettyChars()); @@ -1255,24 +1244,31 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl) { - assert(fdecl->isVirtual());//fdecl->isAbstract() || (!fdecl->isFinal() && fdecl->isVirtual())); - assert(fdecl->vtblIndex > 0); + // sanity checks + assert(fdecl->isVirtual()); + assert(fdecl->vtblIndex > 0); // 0 is always ClassInfo/Interface* assert(inst->getType()->toBasetype()->ty == Tclass); + // get instance LLValue* vthis = inst->getRVal(); if (Logger::enabled()) Logger::cout() << "vthis: " << *vthis << '\n'; LLValue* funcval = vthis; - if (!fdecl->isMember2()->isInterfaceDeclaration()) + // get the vtbl for objects + if (!fdecl->isMember()->isInterfaceDeclaration()) funcval = DtoGEPi(funcval, 0, 0, "tmp"); + // load vtbl ptr funcval = DtoLoad(funcval); + // index vtbl funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toChars()); + // load funcptr funcval = DtoLoad(funcval); if (Logger::enabled()) Logger::cout() << "funcval: " << *funcval << '\n'; + // cast to final funcptr type funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); if (Logger::enabled()) Logger::cout() << "funcval casted: " << *funcval << '\n'; @@ -1292,9 +1288,11 @@ Logger::println("DtoDeclareClassInfo(%s)", cd->toChars()); LOG_SCOPE; + // resovle ClassInfo ClassDeclaration* cinfo = ClassDeclaration::classinfo; DtoResolveClass(cinfo); + // do the mangle std::string gname("_D"); gname.append(cd->mangle()); if (!cd->isInterfaceDeclaration()) @@ -1302,74 +1300,67 @@ else gname.append("11__InterfaceZ"); + // create global irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, DtoLinkage(cd), NULL, gname, gIR->module); } +////////////////////////////////////////////////////////////////////////////////////////// + +// build a single element for the OffsetInfo[] of ClassInfo static LLConstant* build_offti_entry(ClassDeclaration* cd, VarDeclaration* vd) { - std::vector types; - std::vector inits; - - types.push_back(DtoSize_t()); + std::vector inits(2); + // size_t offset; + // assert(vd->ir.irField); + // grab the offset from llvm and the formal class type size_t offset = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(vd->ir.irField->index); + // offset nested struct/union fields offset += vd->ir.irField->unionOffset; - inits.push_back(DtoConstSize_t(offset)); - LLConstant* c = DtoTypeInfoOf(vd->type, true); - const LLType* tiTy = c->getType(); - //Logger::cout() << "tiTy = " << *tiTy << '\n'; + // assert that it matches DMD + Logger::println("offsets: %lu vs %u", offset, vd->offset); + assert(offset == vd->offset); + + inits[0] = DtoConstSize_t(offset); - types.push_back(tiTy); - inits.push_back(c); + // TypeInfo ti; + inits[1] = DtoTypeInfoOf(vd->type, true); - const llvm::StructType* sTy = llvm::StructType::get(types); - return llvm::ConstantStruct::get(sTy, inits); + // done + return llvm::ConstantStruct::get(inits); } -static LLConstant* build_offti_array(ClassDeclaration* cd, LLConstant* init) +static LLConstant* build_offti_array(ClassDeclaration* cd, const LLType* arrayT) { - const llvm::StructType* initTy = isaStruct(init->getType()); - assert(initTy); + IrStruct* irstruct = cd->ir.irStruct; - std::vector arrayInits; - - VarDeclaration** fields = &cd->ir.irStruct->varDecls[0]; - size_t nvars = cd->ir.irStruct->varDecls.size(); + size_t nvars = irstruct->varDecls.size(); + std::vector arrayInits(nvars); for (size_t i=0; ivarDecls[i]); } - size_t ninits = arrayInits.size(); - LLConstant* size = DtoConstSize_t(ninits); + LLConstant* size = DtoConstSize_t(nvars); LLConstant* ptr; - if (ninits > 0) { - // OffsetTypeInfo type - std::vector elemtypes; - elemtypes.push_back(DtoSize_t()); - const LLType* tiTy = getPtrToType(Type::typeinfo->type->ir.type->get()); - elemtypes.push_back(tiTy); - const llvm::StructType* sTy = llvm::StructType::get(elemtypes); + if (nvars == 0) + return LLConstant::getNullValue( arrayT ); + + // array type + const llvm::ArrayType* arrTy = llvm::ArrayType::get(arrayInits[0]->getType(), nvars); + LLConstant* arrInit = llvm::ConstantArray::get(arrTy, arrayInits); - // array type - const llvm::ArrayType* arrTy = llvm::ArrayType::get(sTy, ninits); - LLConstant* arrInit = llvm::ConstantArray::get(arrTy, arrayInits); - - std::string name(cd->type->vtinfo->toChars()); - name.append("__OffsetTypeInfos"); + // mangle + std::string name(cd->type->vtinfo->toChars()); + name.append("__OffsetTypeInfos"); - llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,DtoInternalLinkage(cd),arrInit,name,gIR->module); - ptr = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(sTy)); - } - else { - ptr = llvm::ConstantPointerNull::get(isaPointer(initTy->getElementType(1))); - } + // create symbol + llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,DtoInternalLinkage(cd),arrInit,name,gIR->module); + ptr = DtoBitCast(gvar, getPtrToType(arrTy->getElementType())); return DtoConstSlice(size, ptr); } @@ -1446,7 +1437,8 @@ assert(ir->classInfo); TypeClass* cdty = (TypeClass*)cd->type; - if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) { + if (!cd->isInterfaceDeclaration() && !cd->isAbstract()) + { assert(ir->init); assert(ir->constInit); assert(ir->vtbl); @@ -1460,28 +1452,26 @@ DtoForceConstInitDsymbol(cinfo); assert(cinfo->ir.irStruct->constInit); - // def init constant - LLConstant* defc = cinfo->ir.irStruct->constInit; - assert(defc); - LLConstant* c; + const LLType* voidPtr = getVoidPtrType(); + const LLType* voidPtrPtr = getPtrToType(voidPtr); + // own vtable - c = defc->getOperand(0); + c = cinfo->ir.irStruct->vtbl; assert(c); inits.push_back(c); // monitor - c = defc->getOperand(1); + c = LLConstant::getNullValue(voidPtr); inits.push_back(c); // byte[] init - const LLType* byteptrty = getPtrToType(LLType::Int8Ty); - if (cd->isInterfaceDeclaration() || cd->isAbstract()) { - c = defc->getOperand(2); - } - else { - c = llvm::ConstantExpr::getBitCast(ir->init, byteptrty); + if (cd->isInterfaceDeclaration()) + c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(voidPtr)); + else + { + c = DtoBitCast(ir->init, voidPtr); //Logger::cout() << *ir->constInit->getType() << std::endl; size_t initsz = getABITypeSize(ir->constInit->getType()); c = DtoConstSlice(DtoConstSize_t(initsz), c); @@ -1501,34 +1491,30 @@ inits.push_back(c); // vtbl array - if (cd->isInterfaceDeclaration() || cd->isAbstract()) { - c = defc->getOperand(4); - } + if (cd->isInterfaceDeclaration()) + c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(getPtrToType(voidPtr))); else { - const LLType* byteptrptrty = getPtrToType(byteptrty); - c = llvm::ConstantExpr::getBitCast(cd->ir.irStruct->vtbl, byteptrptrty); - - assert(ir->constVtbl); - size_t vtblsz = ir->constVtbl->getNumOperands(); - c = DtoConstSlice(DtoConstSize_t(vtblsz), c); + c = DtoBitCast(ir->vtbl, voidPtrPtr); + c = DtoConstSlice(DtoConstSize_t(cd->vtbl.dim), c); } inits.push_back(c); // interfaces array - IrStruct* irstruct = cd->ir.irStruct; - if (!irstruct->interfaceInfos) { - c = defc->getOperand(5); - } + VarDeclaration* intersVar = (VarDeclaration*)cinfo->fields.data[3]; + const LLType* intersTy = DtoType(intersVar->type); + if (!ir->interfaceInfos) + c = LLConstant::getNullValue(intersTy); else { - const LLType* t = defc->getOperand(5)->getType()->getContainedType(1); - c = llvm::ConstantExpr::getBitCast(irstruct->interfaceInfos, t); - size_t iisz = irstruct->interfaceVec.size(); + const LLType* t = intersTy->getContainedType(1); // .ptr + c = DtoBitCast(ir->interfaceInfos, t); + size_t iisz = ir->interfaceVec.size(); c = DtoConstSlice(DtoConstSize_t(iisz), c); } inits.push_back(c); // base classinfo - if (cd->baseClass && !cd->isInterfaceDeclaration() && !cd->isAbstract()) { + // interfaces never get a base , just the interfaces[] + if (cd->baseClass && !cd->isInterfaceDeclaration()) { DtoDeclareClassInfo(cd->baseClass); c = cd->baseClass->ir.irStruct->classInfo; assert(c); @@ -1536,34 +1522,33 @@ } else { // null - c = defc->getOperand(6); + c = LLConstant::getNullValue(DtoType(cinfo->type)); inits.push_back(c); } // destructor - if (cd->isInterfaceDeclaration() || cd->isAbstract()) { - c = defc->getOperand(7); - } - else { + if (cd->isInterfaceDeclaration()) + c = LLConstant::getNullValue(voidPtr); + else c = build_class_dtor(cd); - } inits.push_back(c); // invariant - if (cd->inv) { + VarDeclaration* invVar = (VarDeclaration*)cinfo->fields.data[6]; + const LLType* invTy = DtoType(invVar->type); + if (cd->inv) + { DtoForceDeclareDsymbol(cd->inv); c = cd->inv->ir.irFunc->func; - c = llvm::ConstantExpr::getBitCast(c, defc->getOperand(8)->getType()); + c = DtoBitCast(c, invTy); } - else { - c = defc->getOperand(8); - } + else + c = LLConstant::getNullValue(invTy); inits.push_back(c); // uint flags - if (cd->isInterfaceDeclaration() || cd->isAbstract()) { - c = defc->getOperand(9); - } + if (cd->isInterfaceDeclaration()) + c = DtoConstUint(0); else { unsigned flags = build_classinfo_flags(cd); c = DtoConstUint(flags); @@ -1571,42 +1556,44 @@ inits.push_back(c); // deallocator - if (cd->aggDelete) { + if (cd->aggDelete) + { DtoForceDeclareDsymbol(cd->aggDelete); c = cd->aggDelete->ir.irFunc->func; - c = llvm::ConstantExpr::getBitCast(c, defc->getOperand(10)->getType()); + c = DtoBitCast(c, voidPtr); } - else { - c = defc->getOperand(10); - } + else + c = LLConstant::getNullValue(voidPtr); inits.push_back(c); // offset typeinfo - if (cd->isInterfaceDeclaration() || cd->isAbstract()) { - c = defc->getOperand(11); - } - else { - c = build_offti_array(cd, defc->getOperand(11)); - } + VarDeclaration* offTiVar = (VarDeclaration*)cinfo->fields.data[9]; + const LLType* offTiTy = DtoType(offTiVar->type); + if (cd->isInterfaceDeclaration()) + c = LLConstant::getNullValue(offTiTy); + else + c = build_offti_array(cd, offTiTy); inits.push_back(c); // default constructor - if (cd->defaultCtor && !cd->isInterfaceDeclaration() && !cd->isAbstract()) { + if (cd->defaultCtor) + { DtoForceDeclareDsymbol(cd->defaultCtor); c = isaConstant(cd->defaultCtor->ir.irFunc->func); - const LLType* toTy = defc->getOperand(12)->getType(); - c = llvm::ConstantExpr::getBitCast(c, toTy); + c = DtoBitCast(c, voidPtr); } - else { - c = defc->getOperand(12); - } + else + c = LLConstant::getNullValue(voidPtr); inits.push_back(c); #if DMDV2 // xgetMembers - c = defc->getOperand(13); - inits.push_back(c); + VarDeclaration* xgetVar = (VarDeclaration*)cinfo->fields.data[11]; + const LLType* xgetTy = DtoType(xgetVar->type); + + // FIXME: fill it out! + inits.push_back( LLConstant::getNullValue(xgetTy) ); #else #endif diff -r 4ad1e7b10378 -r 69a5e4a6fc0f gen/structs.cpp --- a/gen/structs.cpp Sun Nov 30 19:19:39 2008 +0100 +++ b/gen/structs.cpp Sun Nov 30 20:22:09 2008 +0100 @@ -138,7 +138,7 @@ qsort(&vars[0], nvars, sizeof(VarInitPair), &varinit_offset_cmp_func); // check integrity - // and do error checking, since the frontend does verify static struct initializers + // and do error checking, since the frontend does not verify static struct initializers size_t lastoffset = 0; size_t lastsize = 0; bool overlap = false; diff -r 4ad1e7b10378 -r 69a5e4a6fc0f gen/toir.cpp --- a/gen/toir.cpp Sun Nov 30 19:19:39 2008 +0100 +++ b/gen/toir.cpp Sun Nov 30 20:22:09 2008 +0100 @@ -2035,7 +2035,7 @@ DValue* u = e1->toElem(p); LLValue* value = u->getRVal(); - LLValue* minusone = llvm::ConstantInt::get(value->getType(), -1, true); + LLValue* minusone = llvm::ConstantInt::get(value->getType(), (uint64_t)-1, true); value = llvm::BinaryOperator::Create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb()); return new DImValue(type, value);