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)
         {
-            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]);
+            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)
+        {
+            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);
     }
 
-    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++)
+    // build type
+    std::vector<const LLType*> valuetypes;
+
+    size_t n = initvalues.size();
+    valuetypes.reserve(n);
+
+    for (size_t i = 0; i < n; i++)
     {
-        LLValue* ptr = DtoGEPi(mem, 0, i);
-        DtoStore(values[i], ptr);
+        valuetypes.push_back(initvalues[i]->getType());
     }
 
-    // cast the alloca pointer to the "formal" struct type
-    const LLType* structtype = DtoType(sd->type);
-    mem = DtoBitCast(mem, getPtrToType(structtype));
+    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* addr = DtoGEPi(mem, 0, i);
+        p->ir->CreateStore(initvalues[i], addr);
+    }
+
+    // cast to default struct type
+    mem = DtoBitCast(mem, DtoType(sd->type->pointerTo()));
 
     // return as a var
     return new DVarValue(type, mem);