Mercurial > projects > ldc
diff gen/toir.cpp @ 1255:9014d7f0433f
Rewrote runtime struct literal codegen.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail com> |
---|---|
date | Wed, 22 Apr 2009 03:08:28 +0200 |
parents | 01909bd1132c |
children | dd135ff697fa |
line wrap: on
line diff
--- a/gen/toir.cpp Wed Apr 22 01:18:21 2009 +0200 +++ b/gen/toir.cpp Wed Apr 22 03:08:28 2009 +0200 @@ -37,6 +37,7 @@ #include "gen/functions.h" #include "gen/todebug.h" #include "gen/nested.h" +#include "gen/utils.h" #include "llvm/Support/ManagedStatic.h" @@ -2404,60 +2405,111 @@ ////////////////////////////////////////////////////////////////////////////////////////// +// building a struct literal is pretty much the same as building a default initializer. + +extern size_t add_zeros(std::vector<llvm::Value*>& values, size_t diff); +extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init); + DValue* StructLiteralExp::toElem(IRState* p) { Logger::print("StructLiteralExp::toElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; - // make sure the struct is resolved + // make sure the struct is fully resolved sd->codegen(Type::sir); - // get inits - std::vector<LLValue*> inits(sd->fields.dim, NULL); - + // final list of values to put in the struct + std::vector<LLValue*> initvalues; + + // offset tracker + size_t offset = 0; + + // align(1) struct S { ... } + bool packed = sd->type->alignsize() == 1; + + // ready elements data + assert(elements && "struct literal has null elements"); size_t nexprs = elements->dim;; Expression** exprs = (Expression**)elements->data; - for (size_t i = 0; i < nexprs; i++) + // go through fields + ArrayIter<VarDeclaration> it(sd->fields); + for (; !it.done(); it.next()) { - if (exprs[i]) + VarDeclaration* vd = it.get(); + + if (vd->offset < offset) + { + IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + continue; + } + + IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + + // get next aligned offset for this field + size_t alignedoffset = offset; + if (!packed) { - DValue* v = exprs[i]->toElem(p); - inits[i] = v->getRVal(); - - // make sure we get inner structs/staticarrays right - if (DtoIsPassedByRef(v->getType())) - inits[i] = DtoLoad(inits[i]); + size_t alignsize = vd->type->alignsize(); + alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + } + + // insert explicit padding? + if (alignedoffset < vd->offset) + { + add_zeros(initvalues, vd->offset - alignedoffset); } + + // add initializer + Expression* expr = (it.index < nexprs) ? exprs[it.index] : NULL; + IF_LOG Logger::println("expr: %p", expr); + if (expr) + { + IF_LOG Logger::println("expr = %s", it.index, expr->toChars()); + LLValue* v = DtoExprValue(vd->type, expr); + initvalues.push_back(v); + } + else + { + IF_LOG Logger::println("using default initializer"); + initvalues.push_back(get_default_initializer(vd, NULL)); + } + + // advance offset to right past this field + offset = vd->offset + vd->type->size(); } - // vector of values to build aggregate from - std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits); - - // get the struct type from the values - size_t n = values.size(); - std::vector<const LLType*> types(n, NULL); - - for (size_t i=0; i<n; i++) + // tail padding? + if (offset < sd->structsize) { - types[i] = values[i]->getType(); + add_zeros(initvalues, sd->structsize - offset); + } + + // build type + std::vector<const LLType*> valuetypes; + + size_t n = initvalues.size(); + valuetypes.reserve(n); + + for (size_t i = 0; i < n; i++) + { + valuetypes.push_back(initvalues[i]->getType()); } - const LLStructType* sty = LLStructType::get(types, sd->ir.irStruct->packed); - - // allocate storage for the struct literal on the stack - LLValue* mem = DtoAlloca(sty, "tmpstructliteral"); - - // put all the values into the storage - for (size_t i=0; i<n; i++) + const LLType* st = llvm::StructType::get(valuetypes, packed); + + // alloca a stack slot + LLValue* mem = DtoAlloca(st, ".structliteral"); + + // fill in values + for (size_t i = 0; i < n; i++) { - LLValue* ptr = DtoGEPi(mem, 0, i); - DtoStore(values[i], ptr); + LLValue* addr = DtoGEPi(mem, 0, i); + p->ir->CreateStore(initvalues[i], addr); } - // cast the alloca pointer to the "formal" struct type - const LLType* structtype = DtoType(sd->type); - mem = DtoBitCast(mem, getPtrToType(structtype)); + // cast to default struct type + mem = DtoBitCast(mem, DtoType(sd->type->pointerTo())); // return as a var return new DVarValue(type, mem);