changeset 1231:212ec2d9d176

Fixed some minitest regressions.
author Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
date Thu, 16 Apr 2009 19:21:30 +0200
parents e67c85d6e680
children 79c6c8bc866c
files gen/classes.cpp gen/structs.cpp gen/toir.cpp ir/irclass.cpp ir/irstruct.cpp ir/irtypeclass.cpp ir/irtypestruct.cpp ir/irvar.cpp ir/irvar.h
diffstat 9 files changed, 272 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/gen/classes.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/gen/classes.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -486,8 +486,7 @@
 
     LLValue* funcval = vthis;
     // get the vtbl for objects
-    if (!fdecl->isMember()->isInterfaceDeclaration())
-        funcval = DtoGEPi(funcval, 0, 0, "tmp");
+    funcval = DtoGEPi(funcval, 0, 0, "tmp");
     // load vtbl ptr
     funcval = DtoLoad(funcval);
     // index vtbl
--- a/gen/structs.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/gen/structs.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -22,46 +22,6 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
-{
-    Logger::println("indexing struct field %s:", vd->toPrettyChars());
-    LOG_SCOPE;
-
-    DtoResolveStruct(sd);
-
-    // vd must be a field
-    IrField* field = vd->ir.irField;
-    assert(field);
-
-    // get the start pointer
-    const LLType* st = getPtrToType(DtoType(sd->type));
-
-    // cast to the formal struct type
-    src = DtoBitCast(src, st);
-
-    // gep to the index
-    LLValue* val = DtoGEPi(src, 0, field->index);
-
-    // do we need to offset further? (union area)
-    if (field->unionOffset)
-    {
-        // cast to void*
-        val = DtoBitCast(val, getVoidPtrType());
-        // offset
-        val = DtoGEPi1(val, field->unionOffset);
-    }
-
-    // cast it to the right type
-    val = DtoBitCast(val, getPtrToType(DtoType(vd->type)));
-
-    if (Logger::enabled())
-        Logger::cout() << "value: " << *val << '\n';
-
-    return val;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
 void DtoResolveStruct(StructDeclaration* sd)
 {
     // don't do anything if already been here
@@ -128,3 +88,226 @@
     LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz));
     return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp");
 }
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
+{
+    Logger::println("indexing struct field %s:", vd->toPrettyChars());
+    LOG_SCOPE;
+
+    DtoResolveStruct(sd);
+
+    // vd must be a field
+    IrField* field = vd->ir.irField;
+    assert(field);
+
+    // get the start pointer
+    const LLType* st = getPtrToType(DtoType(sd->type));
+
+    // cast to the formal struct type
+    src = DtoBitCast(src, st);
+
+    // gep to the index
+    LLValue* val = DtoGEPi(src, 0, field->index);
+
+    // do we need to offset further? (union area)
+    if (field->unionOffset)
+    {
+        // cast to void*
+        val = DtoBitCast(val, getVoidPtrType());
+        // offset
+        val = DtoGEPi1(val, field->unionOffset);
+    }
+
+    // cast it to the right type
+    val = DtoBitCast(val, getPtrToType(DtoType(vd->type)));
+
+    if (Logger::enabled())
+        Logger::cout() << "value: " << *val << '\n';
+
+    return val;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// helper function that adds zero bytes to a vector of constants
+size_t add_zeros(std::vector<llvm::Value*>& values, size_t diff)
+{
+    size_t n = values.size();
+    bool is64 = global.params.is64bit;
+    while (diff)
+    {
+        if (is64 && diff % 8 == 0)
+        {
+            values.push_back(llvm::Constant::getNullValue(llvm::Type::Int64Ty));
+            diff -= 8;
+        }
+        else if (diff % 4 == 0)
+        {
+            values.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty));
+            diff -= 4;
+        }
+        else if (diff % 2 == 0)
+        {
+            values.push_back(llvm::Constant::getNullValue(llvm::Type::Int16Ty));
+            diff -= 2;
+        }
+        else
+        {
+            values.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty));
+            diff -= 1;
+        }
+    }
+    return values.size() - n;
+}
+
+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);
+                    add_zeros(values, os - lastoffset - lastsize);
+                }
+
+                // get field default init
+                IrField* f = var->ir.irField;
+                assert(f);
+                values.push_back(f->getDefaultInit());
+
+                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);
+            add_zeros(values, os - lastoffset - lastsize);
+        }
+
+        // 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 = getTypePaddedSize(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);
+                add_zeros(values, os - lastoffset - lastsize);
+            }
+
+            // get field default init
+            IrField* f = var->ir.irField;
+            assert(f);
+            values.push_back(f->getDefaultInit());
+
+            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);
+        add_zeros(values, structsize - lastoffset - lastsize);
+    }
+
+    return values;
+}
\ No newline at end of file
--- a/gen/toir.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/gen/toir.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -982,6 +982,7 @@
     }
     else if (e1->op == TOKstructliteral)
     {
+        // FIXME: is this right?
         StructLiteralExp* slexp = (StructLiteralExp*)e1;
         LLConstant* lit = slexp->toConstElem(p);
         return lit;
@@ -2409,8 +2410,7 @@
     }
 
     // vector of values to build aggregate from
-    std::vector<LLValue*> values;// = DtoStructLiteralValues(sd, inits);
-    assert(0 && "struct literal exp todo");
+    std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
 
     // get the struct type from the values
     size_t n = values.size();
@@ -2459,8 +2459,7 @@
             inits[i] = exprs[i]->toConstElem(p);
 
     // vector of values to build aggregate from
-    std::vector<LLValue*> values;// = DtoStructLiteralValues(sd, inits);
-    assert(0 && "struct literal const exp todo");
+    std::vector<LLValue*> values = DtoStructLiteralValues(sd, inits);
 
     // we know those values are constants.. cast them
     std::vector<LLConstant*> constvals(values.size(), NULL);
--- a/ir/irclass.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/ir/irclass.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -81,6 +81,8 @@
 
     ClassDeclaration* cd = aggrdecl->isClassDeclaration();
 
+    // FIXME:
+    // also happens for mini/s.d :(
     assert(cd->vtblInterfaces && cd->vtblInterfaces->dim > 0 &&
         "should not create interface info array for class with no explicit "
         "interface implementations");
@@ -324,7 +326,14 @@
     for (size_t i = 1; i < n; i++)
     {
         Dsymbol* dsym = (Dsymbol*)vtbl_array.data[i];
-        assert(dsym && "null vtbl member");
+        if (dsym == NULL)
+        {
+            // FIXME
+            // why is this null?
+            // happens for mini/s.d
+            constants.push_back(getNullValue(getVoidPtrType()));
+            continue;
+        }
 
         FuncDeclaration* fd = dsym->isFuncDeclaration();
         assert(fd && "vtbl entry not a function");
--- a/ir/irstruct.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/ir/irstruct.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -23,7 +23,9 @@
 
     type = aggr->type;
 
-    packed = false;
+    packed = (type->ty == Tstruct)
+        ? type->alignsize() == 1
+        : false;
 
     // above still need to be looked at
 
@@ -190,8 +192,10 @@
     IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl;
 
     // sanity check
-    assert(definit->getType() == type->irtype->get() &&
-        "default initializer type does not match the default struct type");
+    if (definit->getType() != type->irtype->get())
+    {
+        assert(0 && "default initializer type does not match the default struct type");
+    }
 
     return definit;
 }
--- a/ir/irtypeclass.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/ir/irtypeclass.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -212,7 +212,17 @@
 
     for (; !it.done(); it.next())
     {
-        FuncDeclaration* fd = it.get()->isFuncDeclaration();
+        Dsymbol* dsym = it.get();
+        if (dsym == NULL)
+        {
+            // FIXME
+            // why is this null?
+            // happens for mini/s.d
+            types.push_back(getVoidPtrType());
+            continue;
+        }
+
+        FuncDeclaration* fd = dsym->isFuncDeclaration();
         assert(fd && "invalid vtbl entry");
 
         IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars());
--- a/ir/irtypestruct.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/ir/irtypestruct.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -138,8 +138,8 @@
     // name types
     Type::sir->getState()->module->addTypeName(sd->toPrettyChars(), pa.get());
 
-#if 0
-    IF_LOG Logger::cout() << "struct type: " << *pa.get() << std::endl;
+#if 1
+    IF_LOG Logger::cout() << "final struct type: " << *pa.get() << std::endl;
 #endif
 
     return pa.get();
--- a/ir/irvar.cpp	Thu Apr 16 13:18:56 2009 +0200
+++ b/ir/irvar.cpp	Thu Apr 16 19:21:30 2009 +0200
@@ -46,6 +46,18 @@
     V->ir.irField = this;
 }
 
+extern LLConstant* get_default_initializer(
+    VarDeclaration* vd,
+    Initializer* init);
+
+llvm::Constant * IrField::getDefaultInit()
+{
+    if (constInit)
+        return constInit;
+    constInit = get_default_initializer(V, V->init);
+    return constInit;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
--- a/ir/irvar.h	Thu Apr 16 13:18:56 2009 +0200
+++ b/ir/irvar.h	Thu Apr 16 19:21:30 2009 +0200
@@ -39,7 +39,10 @@
     unsigned index;
     unsigned unionOffset;
 
+    llvm::Constant* getDefaultInit();
+
 protected:
+    /// FIXME: only used for StructLiteralsExps
     llvm::Constant* constInit;
 };