Mercurial > projects > ldc
changeset 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 | 747fdd9245d7 |
children | 6af2359b433a |
files | gen/llvmhelpers.cpp gen/llvmhelpers.h gen/toir.cpp |
diffstat | 3 files changed, 159 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/gen/llvmhelpers.cpp Wed Apr 22 01:18:21 2009 +0200 +++ b/gen/llvmhelpers.cpp Wed Apr 22 03:08:28 2009 +0200 @@ -1186,6 +1186,78 @@ ////////////////////////////////////////////////////////////////////////////////////////// +static LLValue* expand_value_to_sarray(Type *base, Expression* exp) +{ + Logger::println("building type %s from expression (%s) of type %s", base->toChars(), exp->toChars(), exp->type->toChars()); + const LLType* dstTy = DtoType(base); + if (Logger::enabled()) + Logger::cout() << "final llvm type requested: " << *dstTy << '\n'; + + // get initial value + LLValue* val = exp->toElem(gIR)->getRVal(); + if (DtoIsPassedByRef(exp->type)) + val = DtoLoad(val); + + Type* expbase = exp->type->toBasetype(); + Logger::println("expbase: %s", expbase->toChars()); + Type* t = base->toBasetype(); + + LLSmallVector<size_t, 4> dims; + + while(1) + { + Logger::println("t: %s", t->toChars()); + if (t->equals(expbase)) + break; + assert(t->ty == Tsarray); + TypeSArray* tsa = (TypeSArray*)t; + dims.push_back(tsa->dim->toInteger()); + assert(t->nextOf()); + t = t->nextOf()->toBasetype(); + } + + size_t i = dims.size(); + assert(i); + + std::vector<LLValue*> inits; + while (i--) + { + // start with undefined array + const LLArrayType* arrty = LLArrayType::get(val->getType(), dims[i]); + LLValue* tmp = llvm::UndefValue::get(arrty); + for (size_t j = 0; j < dims[i]; j++) + { + tmp = gIR->ir->CreateInsertValue(tmp, val, j); + } + val = tmp; + } + + return val; +} + +LLValue* DtoExprValue(Type* type, Expression* e) +{ + Type* t1 = e->type->toBasetype(); + Type* t2 = type->toBasetype(); + + // expand static arrays + if (t2->ty == Tsarray && !t1->equals(t2)) + { + return expand_value_to_sarray(t2, e); + } + // or not + else + { + DValue* dv = e->toElem(gIR); + LLValue* v = dv->getRVal(); + if (DtoIsPassedByRef(e->type)) + v = DtoLoad(v); + return v; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + void DtoAnnotation(const char* str) { std::string s("CODE: ");
--- a/gen/llvmhelpers.h Wed Apr 22 01:18:21 2009 +0200 +++ b/gen/llvmhelpers.h Wed Apr 22 03:08:28 2009 +0200 @@ -102,6 +102,8 @@ LLConstant* DtoConstExpInit(Loc loc, Type* t, Expression* exp); DValue* DtoInitializer(LLValue* target, Initializer* init); +LLValue* DtoExprValue(Type* type, Expression* e); + // annotation generator void DtoAnnotation(const char* str);
--- 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);