changeset 870:af7a6faf9406

Fix #153. Factor out common code in StructLiteralExp::to(Const)Elem.
author Christian Kamm <kamm incasoftware de>
date Tue, 30 Dec 2008 11:42:01 +0100
parents 5dbc63f83380
children e70a0e7e2260
files gen/structs.cpp gen/structs.h gen/toir.cpp
diffstat 3 files changed, 207 insertions(+), 195 deletions(-) [+]
line wrap: on
line diff
--- a/gen/structs.cpp	Sat Dec 27 16:07:23 2008 +0100
+++ b/gen/structs.cpp	Tue Dec 30 11:42:01 2008 +0100
@@ -298,6 +298,164 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& 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<VarDeclaration*> 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<llvm::Value*> 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; i<nvars; i++)
+    {
+        VarDeclaration* var = vars[i];
+
+        // get var info
+        size_t os = var->offset;
+        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);
+                    addZeros(values, lastoffset + lastsize, os);
+                }
+
+                // get field default init
+                IrField* f = var->ir.irField;
+                assert(f);
+                if (!f->constInit)
+                    f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
+
+                values.push_back(f->constInit);
+
+                lastoffset = os;
+                lastsize = sz;
+                //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
+            }
+            // skip
+            continue;
+        }
+
+        assert(nextVar == var);
+
+        // add any 0 padding needed before this field
+        if (os > lastoffset + lastsize)
+        {
+            //printf("added %lu zeros\n", os - lastoffset - lastsize);
+            addZeros(values, lastoffset + lastsize, os);
+        }
+
+        // add the expression value
+        values.push_back(inits[i]);
+
+        // update offsets
+        lastoffset = os;
+        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
+    const LLType* structtype = DtoType(sd->type);
+    size_t structsize = getABITypeSize(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);
+                addZeros(values, lastoffset + lastsize, os);
+            }
+
+            // get field default init
+            IrField* f = var->ir.irField;
+            assert(f);
+            if (!f->constInit)
+                f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
+
+            values.push_back(f->constInit);
+
+            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);
+        addZeros(values, lastoffset + lastsize, structsize);
+    }
+
+    return values;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
 {
     Logger::println("indexing struct field %s:", vd->toPrettyChars());
--- a/gen/structs.h	Sat Dec 27 16:07:23 2008 +0100
+++ b/gen/structs.h	Tue Dec 30 11:42:01 2008 +0100
@@ -4,6 +4,7 @@
 struct StructInitializer;
 
 LLConstant* DtoConstStructInitializer(StructInitializer* si);
+std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& inits);
 
 /**
  * Resolves the llvm type for a struct
--- a/gen/toir.cpp	Sat Dec 27 16:07:23 2008 +0100
+++ b/gen/toir.cpp	Tue Dec 30 11:42:01 2008 +0100
@@ -860,15 +860,34 @@
     Logger::print("CastExp::toConstElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
-    LLConstant* c = e1->toConstElem(p);
+    LLConstant* res;
     const LLType* lltype = DtoType(type);
-
-    if(!isaPointer(c->getType()) || !isaPointer(lltype)) {
-        error("can only cast pointers to pointers at code generation time, not %s to %s", type->toChars(), e1->type->toChars());
-        fatal();
+    Type* tb = to->toBasetype();
+
+    // string literal to dyn array:
+    // reinterpret the string data as an array, calculate the length
+    if (e1->op == TOKstring && tb->ty == Tarray) {
+/*        StringExp *strexp = (StringExp*)e1;
+        size_t datalen = strexp->sz * strexp->len;
+        Type* eltype = tb->nextOf()->toBasetype();
+        if (datalen % eltype->size() != 0) {
+            error("the sizes don't line up");
+            return e1->toConstElem(p);
+        }
+        size_t arrlen = datalen / eltype->size();*/
+        error("ct cast of string to dynamic array not fully implemented");
+        return e1->toConstElem(p);
     }
-
-    return llvm::ConstantExpr::getBitCast(c, lltype);
+    // pointer to pointer
+    else if (tb->ty == Tpointer && e1->type->toBasetype()->ty == Tpointer) {
+        res = llvm::ConstantExpr::getBitCast(e1->toConstElem(p), lltype);
+    }
+    else {
+        error("can not cast %s to %s at compile time", e1->type->toChars(), type->toChars());
+        return e1->toConstElem(p);
+    }
+
+    return res;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -2364,161 +2383,23 @@
     Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
-    // get arrays 
+    // get inits
+    std::vector<LLValue*> inits(sd->fields.dim, NULL);
+
     size_t nexprs = elements->dim;;
     Expression** exprs = (Expression**)elements->data;
 
-    size_t nvars = sd->fields.dim;
-    VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
-
-    assert(nexprs <= nvars);
-
-    // first locate all explicit initializers
-    std::vector<VarDeclaration*> explicitInits;
-    for (size_t i=0; i < nexprs; i++)
+    for (size_t i = 0; i < nexprs; i++)
     {
         if (exprs[i])
         {
-            explicitInits.push_back(vars[i]);
+            DValue* v = exprs[i]->toElem(p);
+            inits[i] = v->getRVal();
         }
     }
 
     // vector of values to build aggregate from
-    std::vector<llvm::Value*> 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; i<nvars; i++)
-    {
-        Expression* e = (nexprs > i) ? exprs[i] : NULL;
-        VarDeclaration* var = vars[i];
-
-        // get var info
-        size_t os = var->offset;
-        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 (!e)
-        {
-            // 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);
-                    addZeros(values, lastoffset + lastsize, os);
-                }
-
-                // get field default init
-                IrField* f = var->ir.irField;
-                assert(f);
-                if (!f->constInit)
-                    f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
-
-                values.push_back(f->constInit);
-
-                lastoffset = os;
-                lastsize = sz;
-                //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz);
-            }
-            // skip
-            continue;
-        }
-
-        assert(nextVar == var);
-
-        // add any 0 padding needed before this field
-        if (os > lastoffset + lastsize)
-        {
-            //printf("added %lu zeros\n", os - lastoffset - lastsize);
-            addZeros(values, lastoffset + lastsize, os);
-        }
-
-        // add the expression value
-        DValue* v = e->toElem(p);
-        values.push_back(v->getRVal());
-
-        // update offsets
-        lastoffset = os;
-        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
-    const LLType* structtype = DtoType(sd->type);
-    size_t structsize = getABITypeSize(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);
-                addZeros(values, lastoffset + lastsize, os);
-            }
-
-            // get field default init
-            IrField* f = var->ir.irField;
-            assert(f);
-            if (!f->constInit)
-                f->constInit = DtoConstInitializer(var->loc, var->type, var->init);
-
-            values.push_back(f->constInit);
-
-            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);
-        addZeros(values, lastoffset + lastsize, structsize);
-    }
+    std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
 
     // get the struct type from the values
     size_t n = values.size();
@@ -2542,6 +2423,7 @@
     }
 
     // cast the alloca pointer to the "formal" struct type
+    const LLType* structtype = DtoType(sd->type);
     mem = DtoBitCast(mem, getPtrToType(structtype));
 
     // return as a var
@@ -2555,55 +2437,26 @@
     Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
-    // get arrays 
-    size_t n = elements->dim;
+    // get inits
+    std::vector<LLValue*> inits(sd->fields.dim, NULL);
+
+    size_t nexprs = elements->dim;;
     Expression** exprs = (Expression**)elements->data;
 
-    assert(sd->fields.dim == n);
-    VarDeclaration** vars = (VarDeclaration**)sd->fields.data;
+    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<llvm::Constant*> values;
-
-    // trackers
-    size_t lastoffset = 0;
-    size_t lastsize = 0;
-
-    // for through each field and build up the struct, padding with zeros
-    for (size_t i=0; i<n; i++)
-    {
-        Expression* e = exprs[i];
-        VarDeclaration* var = vars[i];
-
-        // field is skipped
-        if (!e)
-            continue;
-
-        // add any 0 padding needed before this field
-        if (var->offset > lastoffset + lastsize)
-        {
-            addZeros(values, lastoffset + lastsize, var->offset);
-        }
-
-        // add the expression value
-        values.push_back(e->toConstElem(p));
-
-        // update offsets
-        lastoffset = var->offset;
-        lastsize = var->type->size();
-    }
-
-    // add any 0 padding needed at the end of the literal
-    const LLType* structtype = DtoType(sd->type);
-    size_t structsize = getABITypeSize(structtype);
-
-    if (structsize > lastoffset+lastsize)
-    {
-        addZeros(values, lastoffset + lastsize, structsize);
-    }
+    std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
+
+    // we know those values are constants.. cast them
+    std::vector<LLConstant*> constvals(values.size(), NULL);
+    for (size_t i = 0; i < values.size(); ++i)
+        constvals[i] = llvm::cast<LLConstant>(values[i]);
 
     // return constant struct
-    return LLConstantStruct::get(values, sd->ir.irStruct->packed);
+    return LLConstantStruct::get(constvals, sd->ir.irStruct->packed);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////