diff --git a/gen/structs.cpp b/gen/structs.cpp index 3835022f..c5a57a3c 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -151,167 +151,6 @@ LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) // helper function that adds zero bytes to a vector of constants extern size_t add_zeros(std::vector& values, size_t diff); -// return a constant array of type arrTypeD initialized with a constant value, or that constant value -LLConstant* FillSArrayDims(Type* arrTypeD, LLConstant* init) -{ - if (arrTypeD->ty == Tsarray) - { - init = FillSArrayDims(arrTypeD->nextOf(), init); - size_t dim = static_cast(arrTypeD)->dim->toUInteger(); - LLArrayType* arrty = LLArrayType::get(init->getType(), dim); - return LLConstantArray::get(arrty, std::vector(dim, init)); - } - return init; -} - -std::vector DtoStructLiteralValues(const StructDeclaration* sd, - const std::vector& inits) -{ - // get arrays - size_t nvars = sd->fields.dim; - VarDeclaration** vars = (VarDeclaration**)sd->fields.data; - - assert(inits.size() == nvars); - - // first locate all explicit initializers - std::vector explicitInits; - for (size_t i=0; i < nvars; i++) - { - if (inits[i]) - { - explicitInits.push_back(vars[i]); - } - } - - // vector of values to build aggregate from - std::vector values; - - // offset trackers - size_t lastoffset = 0; - size_t lastsize = 0; - - // index of next explicit init - size_t exidx = 0; - // number of explicit inits - size_t nex = explicitInits.size(); - - // for through each field and build up the struct, padding with zeros - size_t i; - for (i=0; ioffset; - size_t sz = var->type->size(); - - // get next explicit - VarDeclaration* nextVar = NULL; - size_t nextOs = 0; - if (exidx < nex) - { - nextVar = explicitInits[exidx]; - nextOs = nextVar->offset; - } - // none, rest is defaults - else - { - break; - } - - // not explicit initializer, default initialize if there is room, otherwise skip - if (!inits[i]) - { - // default init if there is room - // (past current offset) and (small enough to fit before next explicit) - if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) - { - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("1added %lu zeros\n", os - lastoffset - lastsize); - add_zeros(values, os - lastoffset - lastsize); - } - - // get field default init - IrField* f = var->ir.irField; - assert(f); - values.push_back(f->getDefaultInit()); - - lastoffset = os; - lastsize = sz; - //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - // skip - continue; - } - - assert(nextVar == var); - - LLConstant* init = FillSArrayDims(var->type, inits[i]); - values.push_back(init); - - // update offsets - lastoffset = os; - // sometimes size of the initializer is less than size of the variable, - // so make sure that lastsize is correct - if (inits[i]->getType()->isSized()) - sz = ceil(gDataLayout->getTypeSizeInBits(init->getType()) / 8.0); - lastsize = sz; - - // go to next explicit init - exidx++; - - //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - - // fill out rest with default initializers - LLType* structtype = DtoType(sd->type); - size_t structsize = getTypePaddedSize(structtype); - - // FIXME: this could probably share some code with the above - if (structsize > lastoffset+lastsize) - { - for (/*continue from first loop*/; i < nvars; i++) - { - VarDeclaration* var = vars[i]; - - // get var info - size_t os = var->offset; - size_t sz = var->type->size(); - - // skip? - if (os < lastoffset + lastsize) - continue; - - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("2added %lu zeros\n", os - lastoffset - lastsize); - add_zeros(values, os - lastoffset - lastsize); - } - - // get field default init - IrField* f = var->ir.irField; - assert(f); - values.push_back(f->getDefaultInit()); - - lastoffset = os; - lastsize = sz; - //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - } - - // add any 0 padding needed at the end of the literal - if (structsize > lastoffset+lastsize) - { - //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); - add_zeros(values, structsize - lastoffset - lastsize); - } - - return values; -} - /// Return the type returned by DtoUnpaddedStruct called on a value of the /// specified type. /// Union types will get expanded into a struct, with a type for each member. diff --git a/gen/structs.h b/gen/structs.h index 8613744a..5af27956 100644 --- a/gen/structs.h +++ b/gen/structs.h @@ -39,10 +39,6 @@ void DtoResolveStruct(StructDeclaration* sd); /// Build constant struct initializer. llvm::Constant* DtoConstStructInitializer(StructInitializer* si); -/// Build values for a struct literal. -std::vector DtoStructLiteralValues(const StructDeclaration* sd, - const std::vector& inits); - /// Returns a boolean=true if the two structs are equal. llvm::Value* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs); diff --git a/gen/toir.cpp b/gen/toir.cpp index 4192e01d..a932e043 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -36,6 +36,7 @@ #include "gen/typeinf.h" #include "gen/utils.h" #include "gen/warnings.h" +#include "ir/irtypestruct.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include @@ -2988,37 +2989,21 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) sd->codegen(Type::sir); // get inits - std::vector inits(sd->fields.dim, 0); - - size_t nexprs = elements->dim;; - Expression** exprs = (Expression**)elements->data; + llvm::SmallVector varInits; + size_t nexprs = elements->dim; for (size_t i = 0; i < nexprs; i++) - if (exprs[i]) - inits[i] = exprs[i]->toConstElem(p); - - // vector of values to build aggregate from - std::vector values = DtoStructLiteralValues(sd, inits); - - // we know those values are constants.. cast them - std::vector constvals(values.size(), 0); - std::vector types(values.size(), 0); - for (size_t i = 0; i < values.size(); ++i) { - constvals[i] = llvm::cast(values[i]); - types[i] = values[i]->getType(); - } - - // return constant struct - if (!constType) { - if (type->ty == Ttypedef) // hack, see DtoConstInitializer. - constType = LLStructType::get(gIR->context(), types); - else - constType = isaStruct(DtoType(type)); + if ((*elements)[i]) + { + IrTypeStruct::VarInitConst v; + v.first = sd->fields[i]; + v.second = (*elements)[i]->toConstElem(p); + varInits.push_back(v); + } } - else if (constType->isOpaque()) - constType->setBody(types); - return LLConstantStruct::get(constType, llvm::makeArrayRef(constvals)); + + return sd->type->irtype->isStruct()->createInitializerConstant(varInits); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irtypestruct.cpp b/ir/irtypestruct.cpp index a7c473bc..b233d161 100644 --- a/ir/irtypestruct.cpp +++ b/ir/irtypestruct.cpp @@ -47,6 +47,20 @@ static bool struct_init_data_sort(const IrTypeAggr::VarInitConst& a, extern size_t add_zeros(std::vector& constants, size_t diff); +// return a constant array of type arrTypeD initialized with a constant value, or that constant value +static llvm::Constant* FillSArrayDims(Type* arrTypeD, llvm::Constant* init) +{ + if (arrTypeD->ty == Tsarray) + { + init = FillSArrayDims(arrTypeD->nextOf(), init); + size_t dim = static_cast(arrTypeD)->dim->toUInteger(); + llvm::ArrayType* arrty = llvm::ArrayType::get(init->getType(), dim); + return llvm::ConstantArray::get(arrty, + std::vector(dim, init)); + } + return init; +} + llvm::Constant* IrTypeAggr::createInitializerConstant( llvm::ArrayRef initializers, llvm::StructType* initializerType) @@ -90,7 +104,7 @@ llvm::Constant* IrTypeAggr::createInitializerConstant( IF_LOG Logger::println("adding field %s", vd->toChars()); - constants.push_back(initializers[i].second); + constants.push_back(FillSArrayDims(vd->type, initializers[i].second)); offset = vd->offset + vd->type->size(); }