# HG changeset patch # User Tomas Lindquist Olsen # Date 1239921381 -7200 # Node ID f295e51d2dd0b9d87fc2d25e332de2923121fa5f # Parent ff1b4cc2e9be8dee5b8db7ec257a5be8772780ec Fixed static struct initializers. diff -r ff1b4cc2e9be -r f295e51d2dd0 ir/irstruct.cpp --- a/ir/irstruct.cpp Thu Apr 16 22:20:26 2009 +0200 +++ b/ir/irstruct.cpp Fri Apr 17 00:36:21 2009 +0200 @@ -14,6 +14,8 @@ #include "ir/irstruct.h" #include "ir/irtypeclass.h" +#include + ////////////////////////////////////////////////////////////////////////////// IrStruct::IrStruct(AggregateDeclaration* aggr) @@ -206,6 +208,15 @@ // yet another rewrite of the notorious StructInitializer. +typedef std::pair VCPair; + +bool struct_init_data_sort(const VCPair& a, const VCPair& b) +{ + return (a.first && b.first) + ? a.first->offset < b.first->offset + : false; +} + // this time a bit more inspired by the DMD code. LLConstant * IrStruct::createStructInitializer(StructInitializer * si) @@ -218,7 +229,6 @@ assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); // array of things to build - typedef std::pair VCPair; llvm::SmallVector data(aggrdecl->fields.dim); // start by creating a map from initializer indices to field indices. @@ -254,81 +264,105 @@ continue; } + IF_LOG Logger::println("Explicit initializer: %s @+%u", vd->toChars(), vd->offset); + LOG_SCOPE; + data[idx].first = vd; data[idx].second = get_default_initializer(vd, ini); } - // build array of constants and try to fill in default initializers - // where there is room. - size_t offset = 0; - std::vector constants; - constants.reserve(16); - + // fill in implicit initializers n = data.size(); for (size_t i = 0; i < n; i++) { VarDeclaration* vd = data[i].first; + if (vd) + continue; - // explicitly initialized? - if (vd != NULL) - { - // get next aligned offset for this field - size_t alignedoffset = offset; - if (!packed) - { - size_t alignsize = vd->type->alignsize(); - alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); - } + vd = (VarDeclaration*)aggrdecl->fields.data[i]; - // insert explicit padding? - if (alignedoffset < vd->offset) - { - add_zeros(constants, vd->offset - alignedoffset); - } + unsigned vd_begin = vd->offset; + unsigned vd_end = vd_begin + vd->type->size(); - IF_LOG Logger::println("using field: %s", vd->toChars()); - constants.push_back(data[i].second); - offset = vd->offset + vd->type->size(); - } - // not explicit! try and fit in the default initialization instead - // make sure we don't overlap with any following explicity initialized fields - else + // make sure it doesn't overlap any explicit initializers. + VarDeclarationIter it(aggrdecl->fields); + bool overlaps = false; + size_t j = 0; + for (; it.more(); it.next(), j++) { - vd = (VarDeclaration*)aggrdecl->fields.data[i]; + if (i == j || !data[j].first) + continue; - // check all the way that we don't overlap, slow but it works! - for (size_t j = i+1; j <= n; j++) - { - if (j == n) // no overlap - { - IF_LOG Logger::println("using field default: %s", vd->toChars()); - constants.push_back(get_default_initializer(vd, NULL)); - offset = vd->offset + vd->type->size(); - break; - } + unsigned f_begin = it->offset; + unsigned f_end = f_begin + it->type->size(); + + if (vd_begin >= f_end || vd_end <= f_begin) + continue; - VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j]; - - size_t o2 = vd->offset + vd->type->size(); + overlaps = true; + break; + } + // add if no overlap found + if (!overlaps) + { + IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset); + LOG_SCOPE; - if (vd2->offset < o2 && data[i].first) - break; // overlaps - } + data[i].first = vd; + data[i].second = get_default_initializer(vd, NULL); } } - // tail padding? - if (offset < aggrdecl->structsize) - { - add_zeros(constants, aggrdecl->structsize - offset); - } - // stop if there were errors if (global.errors) { fatal(); } + // sort data array by offset + std::sort(data.begin(), data.end(), struct_init_data_sort); + + // build array of constants and make sure explicit zero padding is inserted when necessary. + size_t offset = 0; + std::vector constants; + constants.reserve(n); + + for (size_t i = 0; i < n; i++) + { + VarDeclaration* vd = data[i].first; + if (vd == NULL) + continue; + + // get next aligned offset for this field + size_t alignedoffset = offset; + if (!packed) + { + size_t alignsize = vd->type->alignsize(); + alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + } + + // insert explicit padding? + if (alignedoffset < vd->offset) + { + size_t diff = vd->offset - alignedoffset; + IF_LOG Logger::println("adding %zu bytes zero padding", diff); + add_zeros(constants, diff); + } + + IF_LOG Logger::println("adding field %s", vd->toChars()); + + constants.push_back(data[i].second); + offset = vd->offset + vd->type->size(); + } + + // tail padding? + if (offset < aggrdecl->structsize) + { + size_t diff = aggrdecl->structsize - offset; + IF_LOG Logger::println("adding %zu bytes zero padding", diff); + add_zeros(constants, diff); + } + // build constant assert(!constants.empty()); llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed);