Mercurial > projects > ldc
diff ir/irtypeclass.cpp @ 1270:dd135ff697fa
Fixed class default initializers and type generation. Bug #260 is fixed.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail com> |
---|---|
date | Mon, 27 Apr 2009 03:40:40 +0200 |
parents | bbe6d2b87842 |
children | 8fb39f7f1a7c |
line wrap: on
line diff
--- 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<const llvm::Type*>& 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<VarDeclaration> 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<VarDeclaration*, 16> 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<VarDeclaration> 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