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);