changeset 1270:dd135ff697fa

Fixed class default initializers and type generation. Bug #260 is fixed.
author Tomas Lindquist Olsen <tomas.l.olsen gmail com>
date Mon, 27 Apr 2009 03:40:40 +0200
parents b8a51aa44d4c
children 0686701178d3
files gen/classes.cpp gen/structs.cpp gen/toir.cpp ir/irclass.cpp ir/irstruct.cpp ir/irstruct.h ir/irtypeclass.cpp ir/irtypestruct.cpp ir/irtypestruct.h
diffstat 9 files changed, 169 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/gen/classes.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/gen/classes.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -205,7 +205,11 @@
 
     // copy the rest from the static initializer
     LLValue* dstarr = DtoGEPi(dst,0,2,"tmp");
-    LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->getInitSymbol(),0,2,"tmp");
+
+    // init symbols might not have valid types
+    LLValue* initsym = tc->sym->ir.irStruct->getInitSymbol();
+    initsym = DtoBitCast(initsym, DtoType(tc));
+    LLValue* srcarr = DtoGEPi(initsym,0,2,"tmp");
 
     DtoMemCpy(dstarr, srcarr, DtoConstSize_t(n));
 }
--- a/gen/structs.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/gen/structs.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -44,13 +44,13 @@
     IrStruct* irstruct = new IrStruct(sd);
     sd->ir.irStruct = irstruct;
 
-    // emit the initZ symbol
-    LLGlobalVariable* initZ = irstruct->getInitSymbol();
-
     // perform definition
     bool needs_def = mustDefineSymbol(sd);
     if (needs_def)
     {
+        // emit the initZ symbol
+        LLGlobalVariable* initZ = irstruct->getInitSymbol();
+
         // set initZ initializer
         initZ->setInitializer(irstruct->getDefaultInit());
     }
--- a/gen/toir.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/gen/toir.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -217,7 +217,9 @@
         assert(ts->sym);
         ts->sym->codegen(Type::sir);
 
-        return new DVarValue(type, ts->sym->ir.irStruct->getInitSymbol());
+        LLValue* initsym = ts->sym->ir.irStruct->getInitSymbol();
+        initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
+        return new DVarValue(type, initsym);
     }
     else
     {
@@ -1645,7 +1647,7 @@
         else {
             assert(ts->sym);
             ts->sym->codegen(Type::sir);
-            DtoAggrCopy(mem,ts->sym->ir.irStruct->getInitSymbol());
+            DtoAggrCopy(mem, ts->sym->ir.irStruct->getInitSymbol());
         }
         return new DImValue(type, mem);
     }
--- a/ir/irclass.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/ir/irclass.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -183,21 +183,20 @@
         addBaseClassInits(constants, base->baseClass, offset, field_index);
     }
 
-    ArrayIter<VarDeclaration> it(base->fields);
-    for (; !it.done(); it.next())
-    {
-        VarDeclaration* vd = it.get();
+    IrTypeClass* tc = base->type->irtype->isClass();
+    assert(tc);
 
-        // skip if offset moved backwards
-        if (vd->offset < offset)
-        {
-            IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset);
-            continue;
-        }
+    // go through fields
+    IrTypeAggr::iterator it;
+    for (it = tc->def_begin(); it != tc->def_end(); ++it)
+    {
+        VarDeclaration* vd = *it;
 
         IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
         LOG_SCOPE;
 
+        assert(vd->offset >= offset && "default fields not sorted by offset");
+
         // get next aligned offset for this type
         size_t alignsize = vd->type->alignsize();
         size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
@@ -216,13 +215,15 @@
     }
 
     // has interface vtbls?
-    if (base->vtblInterfaces)
+    if (base->vtblInterfaces && base->vtblInterfaces->dim > 0)
     {
         // false when it's not okay to use functions from super classes
         bool newinsts = (base == aggrdecl->isClassDeclaration());
 
         size_t inter_idx = interfacesWithVtbls.size();
 
+        offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1);
+
         ArrayIter<BaseClass> it2(*base->vtblInterfaces);
         for (; !it2.done(); it2.next())
         {
--- a/ir/irstruct.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/ir/irstruct.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -19,7 +19,8 @@
 //////////////////////////////////////////////////////////////////////////////
 
 IrStruct::IrStruct(AggregateDeclaration* aggr)
-:   diCompositeType(NULL)
+:   diCompositeType(NULL),
+    init_pa(llvm::OpaqueType::get())
 {
     aggrdecl = aggr;
 
@@ -57,7 +58,7 @@
     llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
 
     init = new llvm::GlobalVariable(
-        type->irtype->getPA().get(), true, _linkage, NULL, initname, gIR->module);
+        init_pa.get(), true, _linkage, NULL, initname, gIR->module);
 
     return init;
 }
@@ -78,6 +79,9 @@
         constInit = createClassDefaultInitializer();
     }
 
+    llvm::OpaqueType* o = llvm::cast<llvm::OpaqueType>(init_pa.get());
+    o->refineAbstractTypeTo(constInit->getType());
+
     return constInit;
 }
 
@@ -157,11 +161,7 @@
     {
         VarDeclaration* vd = *it;
 
-        if (vd->offset < offset)
-        {
-            IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
-            continue;
-        }
+        assert(vd->offset >= offset && "default fields not sorted by offset");
 
         IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
 
--- a/ir/irstruct.h	Mon Apr 27 01:43:29 2009 +0200
+++ b/ir/irstruct.h	Mon Apr 27 03:40:40 2009 +0200
@@ -68,6 +68,8 @@
     llvm::GlobalVariable* init;
     /// Static default initializer constant.
     LLConstant* constInit;
+    /// Static default initialier type holder.
+    llvm::PATypeHolder init_pa;
 
     /// Vtbl global.
     llvm::GlobalVariable* vtbl;
--- a/ir/irtypeclass.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/ir/irtypeclass.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -14,6 +14,7 @@
 //////////////////////////////////////////////////////////////////////////////
 
 extern size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff);
+extern bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2);
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -40,29 +41,112 @@
         addBaseClassData(defaultTypes, base->baseClass, offset, field_index);
     }
 
-    ArrayIter<VarDeclaration> it(base->fields);
-    for (; !it.done(); it.next())
+    // FIXME: merge code with structs in IrTypeAggr
+
+    // mirror the sd->fields array but only fill in contributors
+    size_t n = base->fields.dim;
+    LLSmallVector<VarDeclaration*, 16> data(n, NULL);
+    default_fields.reserve(n);
+
+    // first fill in the fields with explicit initializers
+    VarDeclarationIter field_it(base->fields);
+    for (; field_it.more(); field_it.next())
     {
-        VarDeclaration* vd = it.get();
+        // init is !null for explicit inits
+        if (field_it->init != NULL)
+        {
+            IF_LOG Logger::println("adding explicit initializer for struct field %s",
+                field_it->toChars());
+
+            data[field_it.index] = *field_it;
+
+            size_t f_begin = field_it->offset;
+            size_t f_end = f_begin + field_it->type->size();
+
+            // make sure there is no overlap
+            for (size_t i = 0; i < field_it.index; i++)
+            {
+                if (data[i] != NULL)
+                {
+                    VarDeclaration* vd = data[i];
+                    size_t v_begin = vd->offset;
+                    size_t v_end = v_begin + vd->type->size();
+
+                    if (v_begin >= f_end || v_end <= f_begin)
+                        continue;
 
-        // skip if offset moved backwards
-        if (vd->offset < offset)
+                    base->error(vd->loc, "has overlapping initialization for %s and %s",
+                        field_it->toChars(), vd->toChars());
+                }
+            }
+        }
+    }
+
+    if (global.errors)
+    {
+        fatal();
+    }
+
+    // fill in default initializers
+    field_it = VarDeclarationIter(base->fields);
+    for (;field_it.more(); field_it.next())
+    {
+        if (data[field_it.index])
+            continue;
+
+        size_t f_begin = field_it->offset;
+        size_t f_end = f_begin + field_it->type->size();
+
+        // make sure it doesn't overlap anything explicit
+        bool overlaps = false;
+        for (size_t i = 0; i < n; i++)
         {
-            IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset);
-            if (vd->ir.irField == NULL)
+            if (data[i])
             {
-                new IrField(vd, 2, vd->offset - PTRSIZE * 2);
+                size_t v_begin = data[i]->offset;
+                size_t v_end = v_begin + data[i]->type->size();
+
+                if (v_begin >= f_end || v_end <= f_begin)
+                    continue;
+
+                overlaps = true;
+                break;
             }
-            continue;
         }
 
-        IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
+        // if no overlap was found, add the default initializer
+        if (!overlaps)
+        {
+            IF_LOG Logger::println("adding default initializer for struct field %s",
+                field_it->toChars());
+            data[field_it.index] = *field_it;
+        }
+    }
+
+    // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary.
+
+    // first we sort the list by offset
+    std::sort(data.begin(), data.end(), var_offset_sort_cb);
+
+    // add types to list
+    for (size_t i = 0; i < n; i++)
+    {
+        VarDeclaration* vd = data[i];
+
+        if (vd == NULL)
+            continue;
+
+        assert(vd->offset >= offset && "it's a bug...");
+
+        // add to default field list
+        if (cd == base)
+            default_fields.push_back(vd);
 
         // get next aligned offset for this type
         size_t alignsize = vd->type->alignsize();
         size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
 
-        // do we need to insert explicit padding before the field?
+        // insert explicit padding?
         if (alignedoffset < vd->offset)
         {
             field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
@@ -74,19 +158,27 @@
         // advance offset to right past this field
         offset = vd->offset + vd->type->size();
 
-        // give field index
-        // the IrField creation doesn't really belong here, but it's a trivial operation
-        // and it save yet another of these loops.
-        IF_LOG Logger::println("Field index: %zu", field_index);
+        // create ir field
         if (vd->ir.irField == NULL)
-        {
             new IrField(vd, field_index);
-        }
+        else
+            assert(vd->ir.irField->index == field_index &&
+                vd->ir.irField->unionOffset == 0 &&
+                "inconsistent field data");
         field_index++;
     }
 
+    // make sure all fields really get their ir field
+    ArrayIter<VarDeclaration> it(base->fields);
+    for (; !it.done(); it.next())
+    {
+        VarDeclaration* vd = it.get();
+        if (vd->ir.irField == NULL)
+            new IrField(vd, 0, vd->offset);
+    }
+
     // any interface implementations?
-    if (base->vtblInterfaces)
+    if (base->vtblInterfaces && base->vtblInterfaces->dim > 0)
     {
         bool new_instances = (base == cd);
 
@@ -95,6 +187,9 @@
         VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
         Type* first = interfaces_idx->type->next->pointerTo();
 
+        // align offset
+        offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1);
+
         for (; !it2.done(); it2.next())
         {
             BaseClass* b = it2.get();
@@ -117,12 +212,14 @@
         }
     }
 
+#if 0
     // tail padding?
     if (offset < base->structsize)
     {
         field_index += add_zeros(defaultTypes, base->structsize - offset);
         offset = base->structsize;
     }
+#endif
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -159,6 +256,15 @@
 
         // add data members recursively
         addBaseClassData(defaultTypes, cd, offset, field_index);
+
+#if 1
+        // tail padding?
+        if (offset < cd->structsize)
+        {
+            field_index += add_zeros(defaultTypes, cd->structsize - offset);
+            offset = cd->structsize;
+        }
+#endif
     }
 
     // errors are fatal during codegen
--- a/ir/irtypestruct.cpp	Mon Apr 27 01:43:29 2009 +0200
+++ b/ir/irtypestruct.cpp	Mon Apr 27 03:40:40 2009 +0200
@@ -64,10 +64,15 @@
 
 bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2)
 {
-    if (v1 && v2) return v1->offset < v2->offset;
-    else return false;
+    if (v1 && v2)
+        return v1->offset < v2->offset;
+    else
+        return false;
 }
 
+// this is pretty much the exact same thing we need to do for fields in each
+// base class of a class
+
 const llvm::Type* IrTypeStruct::buildType()
 {
     IF_LOG Logger::println("Building struct type %s @ %s",
--- a/ir/irtypestruct.h	Mon Apr 27 01:43:29 2009 +0200
+++ b/ir/irtypestruct.h	Mon Apr 27 03:40:40 2009 +0200
@@ -33,6 +33,11 @@
     /// AggregateDeclaration this type represents.
     AggregateDeclaration* aggr;
 
+    /// Sorted list of all default fields.
+    /// A default field is a field that contributes to the default initializer
+    /// and the default type, and thus it has it's own unique GEP index into
+    /// the aggregate.
+    /// For classes, field of any super classes are not included.
     std::vector<VarDeclaration*> default_fields;
 };