changeset 1262:ec1d9dc1d32a

Fixed struct default initializers.
author Tomas Lindquist Olsen <tomas.l.olsen gmail com>
date Sat, 25 Apr 2009 18:26:54 +0200
parents 7af860e4f403
children 4fc43e173a0f
files gen/classes.cpp gen/utils.h ir/irclass.cpp ir/irstruct.cpp ir/irtypestruct.cpp ir/irtypestruct.h
diffstat 6 files changed, 163 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/gen/classes.cpp	Wed Apr 22 14:49:49 2009 -0600
+++ b/gen/classes.cpp	Sat Apr 25 18:26:54 2009 +0200
@@ -187,8 +187,7 @@
 {
     tc->sym->codegen(Type::sir);
 
-    size_t presz = 2*getTypePaddedSize(DtoSize_t());
-    uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz;
+    uint64_t n = tc->sym->structsize - PTRSIZE * 2;
 
     // set vtable field seperately, this might give better optimization
     LLValue* tmp = DtoGEPi(dst,0,0,"vtbl");
--- a/gen/utils.h	Wed Apr 22 14:49:49 2009 -0600
+++ b/gen/utils.h	Sat Apr 25 18:26:54 2009 +0200
@@ -7,35 +7,57 @@
 template<class C>
 struct ArrayIter
 {
-    Array& array;
+    Array* array;
     size_t index;
 
     ArrayIter(Array& arr, size_t idx = 0)
+    :   array(&arr), index(idx)
+    { }
+    ArrayIter(Array* arr, size_t idx = 0)
     :   array(arr), index(idx)
-    { }
+    { assert(arr && "null array"); }
+
+    ArrayIter<C>& operator=(const Array& arr)
+    {
+        array = &arr;
+        index = 0;
+        return *this;
+    }
+    ArrayIter<C>& operator=(const Array* arr)
+    {
+        assert(arr && "null array");
+        array = arr;
+        index = 0;
+        return *this;
+    }
 
     bool done()
     {
-        return index >= array.dim;
+        return index >= array->dim;
     }
     bool more()
     {
-        return index < array.dim;
+        return index < array->dim;
     }
 
-    C* get()
-    {
-        return static_cast<C*>(array.data[index]);
+    C* get() {
+        return static_cast<C*>(array->data[index]);
     }
-    C* operator->()
-    {
-        return static_cast<C*>(array.data[index]);
+    C* operator->() {
+        return get();
+    }
+    C* operator*() {
+        return get();
     }
 
     void next()
     {
         ++index;
     }
+
+    bool operator==(const ArrayIter<C>& other) {
+        return &array->data[index] == &other.array->data[other.index];
+    }
 };
 
 // some aliases
--- a/ir/irclass.cpp	Wed Apr 22 14:49:49 2009 -0600
+++ b/ir/irclass.cpp	Sat Apr 25 18:26:54 2009 +0200
@@ -276,9 +276,6 @@
     // build the constant
     llvm::Constant* definit = llvm::ConstantStruct::get(constants, false);
 
-    // sanity check
-    assert(definit->getType() == type->irtype->getPA().get() && "class initializer type mismatch");
-
     return definit;
 }
 
--- a/ir/irstruct.cpp	Wed Apr 22 14:49:49 2009 -0600
+++ b/ir/irstruct.cpp	Sat Apr 25 18:26:54 2009 +0200
@@ -142,6 +142,9 @@
 
     assert(type->ty == Tstruct && "cannot build struct default initializer for non struct type");
 
+    IrTypeStruct* ts = type->irtype->isStruct();
+    assert(ts);
+
     // start at offset zero
     size_t offset = 0;
 
@@ -149,10 +152,10 @@
     std::vector<llvm::Constant*> constants;
 
     // go through fields
-    ArrayIter<VarDeclaration> it(aggrdecl->fields);
-    for (; !it.done(); it.next())
+    IrTypeAggr::iterator it;
+    for (it = ts->def_begin(); it != ts->def_end(); ++it)
     {
-        VarDeclaration* vd = it.get();
+        VarDeclaration* vd = *it;
 
         if (vd->offset < offset)
         {
@@ -195,12 +198,6 @@
     IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl;
 #endif
 
-    // sanity check
-    if (definit->getType() != type->irtype->get())
-    {
-        assert(0 && "default initializer type does not match the default struct type");
-    }
-
     return definit;
 }
 
--- a/ir/irtypestruct.cpp	Wed Apr 22 14:49:49 2009 -0600
+++ b/ir/irtypestruct.cpp	Sat Apr 25 18:26:54 2009 +0200
@@ -62,18 +62,103 @@
     return defaultTypes.size() - n;
 }
 
+bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2)
+{
+    if (v1 && v2) return v1->offset < v2->offset;
+    else return false;
+}
+
 const llvm::Type* IrTypeStruct::buildType()
 {
-    IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->locToChars());
+    IF_LOG Logger::println("Building struct type %s @ %s",
+        sd->toPrettyChars(), sd->locToChars());
     LOG_SCOPE;
 
     // if it's a forward declaration, all bets are off, stick with the opaque
     if (sd->sizeok != 1)
         return pa.get();
 
-    // find the fields that contribute to the default initializer.
-    // these will define the default type.
+    // mirror the sd->fields array but only fill in contributors
+    size_t n = sd->fields.dim;
+    LLSmallVector<VarDeclaration*, 16> data(n, NULL);
+    default_fields.reserve(n);
+
+    // first fill in the fields with explicit initializers
+    VarDeclarationIter field_it(sd->fields);
+    for (; field_it.more(); field_it.next())
+    {
+        // 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;
+
+                    sd->error(vd->loc, "overlapping initialization for %s and %s",
+                        field_it->toChars(), vd->toChars());
+                }
+            }
+        }
+    }
 
+    if (global.errors)
+    {
+        fatal();
+    }
+
+    // fill in default initializers
+    field_it = VarDeclarationIter(sd->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 (data[i])
+            {
+                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;
+            }
+        }
+
+        // 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.
     std::vector<const llvm::Type*> defaultTypes;
     defaultTypes.reserve(16);
 
@@ -82,24 +167,21 @@
 
     bool packed = (sd->type->alignsize() == 1);
 
-    ArrayIter<VarDeclaration> it(sd->fields);
-    for (; !it.done(); it.next())
+    // 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 = it.get();
-        //Logger::println("vd: %s", vd->toPrettyChars());
-
-        //assert(vd->ir.irField == NULL && "struct inheritance is not allowed, how can this happen?");
+        VarDeclaration* vd = data[i];
 
-        // 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);
-            if (vd->ir.irField == NULL)
-                new IrField(vd, 0, vd->offset);
+        if (vd == NULL)
             continue;
-        }
+
+        assert(vd->offset >= offset);
 
-        IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
+        // add to default field list
+        default_fields.push_back(vd);
 
         // get next aligned offset for this type
         size_t alignedoffset = offset;
@@ -121,12 +203,13 @@
         // 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++;
     }
 
@@ -136,6 +219,15 @@
         add_zeros(defaultTypes, sd->structsize - offset);
     }
 
+    // make sure all fields really get their ir field
+    ArrayIter<VarDeclaration> it(sd->fields);
+    for (; !it.done(); it.next())
+    {
+        VarDeclaration* vd = it.get();
+        if (vd->ir.irField == NULL)
+            new IrField(vd, 0, vd->offset);
+    }
+
     // build the llvm type
     const llvm::Type* st = llvm::StructType::get(defaultTypes, packed);
 
--- a/ir/irtypestruct.h	Wed Apr 22 14:49:49 2009 -0600
+++ b/ir/irtypestruct.h	Sat Apr 25 18:26:54 2009 +0200
@@ -20,9 +20,20 @@
     ///
     IrTypeAggr* isAggr()            { return this; }
 
+    ///
+    typedef std::vector<VarDeclaration*>::iterator iterator;
+
+    ///
+    iterator def_begin()        { return default_fields.begin(); }
+
+    ///
+    iterator def_end()          { return default_fields.end(); }
+
 protected:
     /// AggregateDeclaration this type represents.
     AggregateDeclaration* aggr;
+
+    std::vector<VarDeclaration*> default_fields;
 };
 
 //////////////////////////////////////////////////////////////////////////////