# HG changeset patch # User Tomas Lindquist Olsen # Date 1240796440 -7200 # Node ID dd135ff697fa461d0ee1afd20822fddcf9e9dfa5 # Parent b8a51aa44d4c4301aeb1424265da601540004cee Fixed class default initializers and type generation. Bug #260 is fixed. diff -r b8a51aa44d4c -r dd135ff697fa gen/classes.cpp --- a/gen/classes.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/gen/classes.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -205,7 +205,11 @@ // copy the rest from the static initializer LLValue* dstarr = DtoGEPi(dst,0,2,"tmp"); - LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->getInitSymbol(),0,2,"tmp"); + + // init symbols might not have valid types + LLValue* initsym = tc->sym->ir.irStruct->getInitSymbol(); + initsym = DtoBitCast(initsym, DtoType(tc)); + LLValue* srcarr = DtoGEPi(initsym,0,2,"tmp"); DtoMemCpy(dstarr, srcarr, DtoConstSize_t(n)); } diff -r b8a51aa44d4c -r dd135ff697fa gen/structs.cpp --- a/gen/structs.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/gen/structs.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -44,13 +44,13 @@ IrStruct* irstruct = new IrStruct(sd); sd->ir.irStruct = irstruct; - // emit the initZ symbol - LLGlobalVariable* initZ = irstruct->getInitSymbol(); - // perform definition bool needs_def = mustDefineSymbol(sd); if (needs_def) { + // emit the initZ symbol + LLGlobalVariable* initZ = irstruct->getInitSymbol(); + // set initZ initializer initZ->setInitializer(irstruct->getDefaultInit()); } diff -r b8a51aa44d4c -r dd135ff697fa gen/toir.cpp --- a/gen/toir.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/gen/toir.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -217,7 +217,9 @@ assert(ts->sym); ts->sym->codegen(Type::sir); - return new DVarValue(type, ts->sym->ir.irStruct->getInitSymbol()); + LLValue* initsym = ts->sym->ir.irStruct->getInitSymbol(); + initsym = DtoBitCast(initsym, DtoType(ts->pointerTo())); + return new DVarValue(type, initsym); } else { @@ -1645,7 +1647,7 @@ else { assert(ts->sym); ts->sym->codegen(Type::sir); - DtoAggrCopy(mem,ts->sym->ir.irStruct->getInitSymbol()); + DtoAggrCopy(mem, ts->sym->ir.irStruct->getInitSymbol()); } return new DImValue(type, mem); } diff -r b8a51aa44d4c -r dd135ff697fa ir/irclass.cpp --- a/ir/irclass.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/ir/irclass.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -183,21 +183,20 @@ addBaseClassInits(constants, base->baseClass, offset, field_index); } - ArrayIter it(base->fields); - for (; !it.done(); it.next()) - { - VarDeclaration* vd = it.get(); + IrTypeClass* tc = base->type->irtype->isClass(); + assert(tc); - // skip if offset moved backwards - if (vd->offset < offset) - { - IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); - continue; - } + // go through fields + IrTypeAggr::iterator it; + for (it = tc->def_begin(); it != tc->def_end(); ++it) + { + VarDeclaration* vd = *it; IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); LOG_SCOPE; + assert(vd->offset >= offset && "default fields not sorted by offset"); + // get next aligned offset for this type size_t alignsize = vd->type->alignsize(); size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); @@ -216,13 +215,15 @@ } // has interface vtbls? - if (base->vtblInterfaces) + if (base->vtblInterfaces && base->vtblInterfaces->dim > 0) { // false when it's not okay to use functions from super classes bool newinsts = (base == aggrdecl->isClassDeclaration()); size_t inter_idx = interfacesWithVtbls.size(); + offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); + ArrayIter it2(*base->vtblInterfaces); for (; !it2.done(); it2.next()) { diff -r b8a51aa44d4c -r dd135ff697fa ir/irstruct.cpp --- a/ir/irstruct.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/ir/irstruct.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -19,7 +19,8 @@ ////////////////////////////////////////////////////////////////////////////// IrStruct::IrStruct(AggregateDeclaration* aggr) -: diCompositeType(NULL) +: diCompositeType(NULL), + init_pa(llvm::OpaqueType::get()) { aggrdecl = aggr; @@ -57,7 +58,7 @@ llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); init = new llvm::GlobalVariable( - type->irtype->getPA().get(), true, _linkage, NULL, initname, gIR->module); + init_pa.get(), true, _linkage, NULL, initname, gIR->module); return init; } @@ -78,6 +79,9 @@ constInit = createClassDefaultInitializer(); } + llvm::OpaqueType* o = llvm::cast(init_pa.get()); + o->refineAbstractTypeTo(constInit->getType()); + return constInit; } @@ -157,11 +161,7 @@ { VarDeclaration* vd = *it; - if (vd->offset < offset) - { - IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); - continue; - } + assert(vd->offset >= offset && "default fields not sorted by offset"); IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); diff -r b8a51aa44d4c -r dd135ff697fa ir/irstruct.h --- a/ir/irstruct.h Mon Apr 27 01:43:29 2009 +0200 +++ b/ir/irstruct.h Mon Apr 27 03:40:40 2009 +0200 @@ -68,6 +68,8 @@ llvm::GlobalVariable* init; /// Static default initializer constant. LLConstant* constInit; + /// Static default initialier type holder. + llvm::PATypeHolder init_pa; /// Vtbl global. llvm::GlobalVariable* vtbl; diff -r b8a51aa44d4c -r dd135ff697fa ir/irtypeclass.cpp --- a/ir/irtypeclass.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/ir/irtypeclass.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -14,6 +14,7 @@ ////////////////////////////////////////////////////////////////////////////// extern size_t add_zeros(std::vector& defaultTypes, size_t diff); +extern bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2); ////////////////////////////////////////////////////////////////////////////// @@ -40,29 +41,112 @@ addBaseClassData(defaultTypes, base->baseClass, offset, field_index); } - ArrayIter it(base->fields); - for (; !it.done(); it.next()) + // FIXME: merge code with structs in IrTypeAggr + + // mirror the sd->fields array but only fill in contributors + size_t n = base->fields.dim; + LLSmallVector data(n, NULL); + default_fields.reserve(n); + + // first fill in the fields with explicit initializers + VarDeclarationIter field_it(base->fields); + for (; field_it.more(); field_it.next()) { - VarDeclaration* vd = it.get(); + // init is !null for explicit inits + if (field_it->init != NULL) + { + IF_LOG Logger::println("adding explicit initializer for struct field %s", + field_it->toChars()); + + data[field_it.index] = *field_it; + + size_t f_begin = field_it->offset; + size_t f_end = f_begin + field_it->type->size(); + + // make sure there is no overlap + for (size_t i = 0; i < field_it.index; i++) + { + if (data[i] != NULL) + { + VarDeclaration* vd = data[i]; + size_t v_begin = vd->offset; + size_t v_end = v_begin + vd->type->size(); + + if (v_begin >= f_end || v_end <= f_begin) + continue; - // skip if offset moved backwards - if (vd->offset < offset) + base->error(vd->loc, "has overlapping initialization for %s and %s", + field_it->toChars(), vd->toChars()); + } + } + } + } + + if (global.errors) + { + fatal(); + } + + // fill in default initializers + field_it = VarDeclarationIter(base->fields); + for (;field_it.more(); field_it.next()) + { + if (data[field_it.index]) + continue; + + size_t f_begin = field_it->offset; + size_t f_end = f_begin + field_it->type->size(); + + // make sure it doesn't overlap anything explicit + bool overlaps = false; + for (size_t i = 0; i < n; i++) { - IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); - if (vd->ir.irField == NULL) + if (data[i]) { - new IrField(vd, 2, vd->offset - PTRSIZE * 2); + size_t v_begin = data[i]->offset; + size_t v_end = v_begin + data[i]->type->size(); + + if (v_begin >= f_end || v_end <= f_begin) + continue; + + overlaps = true; + break; } - continue; } - IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + // if no overlap was found, add the default initializer + if (!overlaps) + { + IF_LOG Logger::println("adding default initializer for struct field %s", + field_it->toChars()); + data[field_it.index] = *field_it; + } + } + + // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary. + + // first we sort the list by offset + std::sort(data.begin(), data.end(), var_offset_sort_cb); + + // add types to list + for (size_t i = 0; i < n; i++) + { + VarDeclaration* vd = data[i]; + + if (vd == NULL) + continue; + + assert(vd->offset >= offset && "it's a bug..."); + + // add to default field list + if (cd == base) + default_fields.push_back(vd); // get next aligned offset for this type size_t alignsize = vd->type->alignsize(); size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); - // do we need to insert explicit padding before the field? + // insert explicit padding? if (alignedoffset < vd->offset) { field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); @@ -74,19 +158,27 @@ // advance offset to right past this field offset = vd->offset + vd->type->size(); - // give field index - // the IrField creation doesn't really belong here, but it's a trivial operation - // and it save yet another of these loops. - IF_LOG Logger::println("Field index: %zu", field_index); + // create ir field if (vd->ir.irField == NULL) - { new IrField(vd, field_index); - } + else + assert(vd->ir.irField->index == field_index && + vd->ir.irField->unionOffset == 0 && + "inconsistent field data"); field_index++; } + // make sure all fields really get their ir field + ArrayIter it(base->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + if (vd->ir.irField == NULL) + new IrField(vd, 0, vd->offset); + } + // any interface implementations? - if (base->vtblInterfaces) + if (base->vtblInterfaces && base->vtblInterfaces->dim > 0) { bool new_instances = (base == cd); @@ -95,6 +187,9 @@ VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); Type* first = interfaces_idx->type->next->pointerTo(); + // align offset + offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); + for (; !it2.done(); it2.next()) { BaseClass* b = it2.get(); @@ -117,12 +212,14 @@ } } +#if 0 // tail padding? if (offset < base->structsize) { field_index += add_zeros(defaultTypes, base->structsize - offset); offset = base->structsize; } +#endif } ////////////////////////////////////////////////////////////////////////////// @@ -159,6 +256,15 @@ // add data members recursively addBaseClassData(defaultTypes, cd, offset, field_index); + +#if 1 + // tail padding? + if (offset < cd->structsize) + { + field_index += add_zeros(defaultTypes, cd->structsize - offset); + offset = cd->structsize; + } +#endif } // errors are fatal during codegen diff -r b8a51aa44d4c -r dd135ff697fa ir/irtypestruct.cpp --- a/ir/irtypestruct.cpp Mon Apr 27 01:43:29 2009 +0200 +++ b/ir/irtypestruct.cpp Mon Apr 27 03:40:40 2009 +0200 @@ -64,10 +64,15 @@ bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2) { - if (v1 && v2) return v1->offset < v2->offset; - else return false; + if (v1 && v2) + return v1->offset < v2->offset; + else + return false; } +// this is pretty much the exact same thing we need to do for fields in each +// base class of a class + const llvm::Type* IrTypeStruct::buildType() { IF_LOG Logger::println("Building struct type %s @ %s", diff -r b8a51aa44d4c -r dd135ff697fa ir/irtypestruct.h --- a/ir/irtypestruct.h Mon Apr 27 01:43:29 2009 +0200 +++ b/ir/irtypestruct.h Mon Apr 27 03:40:40 2009 +0200 @@ -33,6 +33,11 @@ /// AggregateDeclaration this type represents. AggregateDeclaration* aggr; + /// Sorted list of all default fields. + /// A default field is a field that contributes to the default initializer + /// and the default type, and thus it has it's own unique GEP index into + /// the aggregate. + /// For classes, field of any super classes are not included. std::vector default_fields; };