# HG changeset patch # User Tomas Lindquist Olsen # Date 1240676814 -7200 # Node ID ec1d9dc1d32adb0e7de043f63893790f7c8c341c # Parent 7af860e4f4035540fe93c93859f48a64beed4a42 Fixed struct default initializers. diff -r 7af860e4f403 -r ec1d9dc1d32a gen/classes.cpp --- a/gen/classes.cpp Wed Apr 22 14:49:49 2009 -0600 +++ b/gen/classes.cpp Sat Apr 25 18:26:54 2009 +0200 @@ -187,8 +187,7 @@ { tc->sym->codegen(Type::sir); - size_t presz = 2*getTypePaddedSize(DtoSize_t()); - uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz; + uint64_t n = tc->sym->structsize - PTRSIZE * 2; // set vtable field seperately, this might give better optimization LLValue* tmp = DtoGEPi(dst,0,0,"vtbl"); diff -r 7af860e4f403 -r ec1d9dc1d32a gen/utils.h --- a/gen/utils.h Wed Apr 22 14:49:49 2009 -0600 +++ b/gen/utils.h Sat Apr 25 18:26:54 2009 +0200 @@ -7,35 +7,57 @@ template struct ArrayIter { - Array& array; + Array* array; size_t index; ArrayIter(Array& arr, size_t idx = 0) + : array(&arr), index(idx) + { } + ArrayIter(Array* arr, size_t idx = 0) : array(arr), index(idx) - { } + { assert(arr && "null array"); } + + ArrayIter& operator=(const Array& arr) + { + array = &arr; + index = 0; + return *this; + } + ArrayIter& operator=(const Array* arr) + { + assert(arr && "null array"); + array = arr; + index = 0; + return *this; + } bool done() { - return index >= array.dim; + return index >= array->dim; } bool more() { - return index < array.dim; + return index < array->dim; } - C* get() - { - return static_cast(array.data[index]); + C* get() { + return static_cast(array->data[index]); } - C* operator->() - { - return static_cast(array.data[index]); + C* operator->() { + return get(); + } + C* operator*() { + return get(); } void next() { ++index; } + + bool operator==(const ArrayIter& other) { + return &array->data[index] == &other.array->data[other.index]; + } }; // some aliases diff -r 7af860e4f403 -r ec1d9dc1d32a ir/irclass.cpp --- a/ir/irclass.cpp Wed Apr 22 14:49:49 2009 -0600 +++ b/ir/irclass.cpp Sat Apr 25 18:26:54 2009 +0200 @@ -276,9 +276,6 @@ // build the constant llvm::Constant* definit = llvm::ConstantStruct::get(constants, false); - // sanity check - assert(definit->getType() == type->irtype->getPA().get() && "class initializer type mismatch"); - return definit; } diff -r 7af860e4f403 -r ec1d9dc1d32a ir/irstruct.cpp --- a/ir/irstruct.cpp Wed Apr 22 14:49:49 2009 -0600 +++ b/ir/irstruct.cpp Sat Apr 25 18:26:54 2009 +0200 @@ -142,6 +142,9 @@ assert(type->ty == Tstruct && "cannot build struct default initializer for non struct type"); + IrTypeStruct* ts = type->irtype->isStruct(); + assert(ts); + // start at offset zero size_t offset = 0; @@ -149,10 +152,10 @@ std::vector constants; // go through fields - ArrayIter it(aggrdecl->fields); - for (; !it.done(); it.next()) + IrTypeAggr::iterator it; + for (it = ts->def_begin(); it != ts->def_end(); ++it) { - VarDeclaration* vd = it.get(); + VarDeclaration* vd = *it; if (vd->offset < offset) { @@ -195,12 +198,6 @@ IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl; #endif - // sanity check - if (definit->getType() != type->irtype->get()) - { - assert(0 && "default initializer type does not match the default struct type"); - } - return definit; } diff -r 7af860e4f403 -r ec1d9dc1d32a ir/irtypestruct.cpp --- a/ir/irtypestruct.cpp Wed Apr 22 14:49:49 2009 -0600 +++ b/ir/irtypestruct.cpp Sat Apr 25 18:26:54 2009 +0200 @@ -62,18 +62,103 @@ return defaultTypes.size() - n; } +bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2) +{ + if (v1 && v2) return v1->offset < v2->offset; + else return false; +} + const llvm::Type* IrTypeStruct::buildType() { - IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->locToChars()); + IF_LOG Logger::println("Building struct type %s @ %s", + sd->toPrettyChars(), sd->locToChars()); LOG_SCOPE; // if it's a forward declaration, all bets are off, stick with the opaque if (sd->sizeok != 1) return pa.get(); - // find the fields that contribute to the default initializer. - // these will define the default type. + // mirror the sd->fields array but only fill in contributors + size_t n = sd->fields.dim; + LLSmallVector data(n, NULL); + default_fields.reserve(n); + + // first fill in the fields with explicit initializers + VarDeclarationIter field_it(sd->fields); + for (; field_it.more(); field_it.next()) + { + // 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; + + sd->error(vd->loc, "overlapping initialization for %s and %s", + field_it->toChars(), vd->toChars()); + } + } + } + } + if (global.errors) + { + fatal(); + } + + // fill in default initializers + field_it = VarDeclarationIter(sd->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 (data[i]) + { + 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; + } + } + + // 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. std::vector defaultTypes; defaultTypes.reserve(16); @@ -82,24 +167,21 @@ bool packed = (sd->type->alignsize() == 1); - ArrayIter it(sd->fields); - for (; !it.done(); it.next()) + // 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 = it.get(); - //Logger::println("vd: %s", vd->toPrettyChars()); - - //assert(vd->ir.irField == NULL && "struct inheritance is not allowed, how can this happen?"); + VarDeclaration* vd = data[i]; - // 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); - if (vd->ir.irField == NULL) - new IrField(vd, 0, vd->offset); + if (vd == NULL) continue; - } + + assert(vd->offset >= offset); - IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + // add to default field list + default_fields.push_back(vd); // get next aligned offset for this type size_t alignedoffset = offset; @@ -121,12 +203,13 @@ // 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++; } @@ -136,6 +219,15 @@ add_zeros(defaultTypes, sd->structsize - offset); } + // make sure all fields really get their ir field + ArrayIter it(sd->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + if (vd->ir.irField == NULL) + new IrField(vd, 0, vd->offset); + } + // build the llvm type const llvm::Type* st = llvm::StructType::get(defaultTypes, packed); diff -r 7af860e4f403 -r ec1d9dc1d32a ir/irtypestruct.h --- a/ir/irtypestruct.h Wed Apr 22 14:49:49 2009 -0600 +++ b/ir/irtypestruct.h Sat Apr 25 18:26:54 2009 +0200 @@ -20,9 +20,20 @@ /// IrTypeAggr* isAggr() { return this; } + /// + typedef std::vector::iterator iterator; + + /// + iterator def_begin() { return default_fields.begin(); } + + /// + iterator def_end() { return default_fields.end(); } + protected: /// AggregateDeclaration this type represents. AggregateDeclaration* aggr; + + std::vector default_fields; }; //////////////////////////////////////////////////////////////////////////////