changeset 1240:f295e51d2dd0

Fixed static struct initializers.
author Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
date Fri, 17 Apr 2009 00:36:21 +0200
parents ff1b4cc2e9be
children fc579f389f9a
files ir/irstruct.cpp
diffstat 1 files changed, 86 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/ir/irstruct.cpp	Thu Apr 16 22:20:26 2009 +0200
+++ b/ir/irstruct.cpp	Fri Apr 17 00:36:21 2009 +0200
@@ -14,6 +14,8 @@
 #include "ir/irstruct.h"
 #include "ir/irtypeclass.h"
 
+#include <algorithm>
+
 //////////////////////////////////////////////////////////////////////////////
 
 IrStruct::IrStruct(AggregateDeclaration* aggr)
@@ -206,6 +208,15 @@
 
 // yet another rewrite of the notorious StructInitializer.
 
+typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair;
+
+bool struct_init_data_sort(const VCPair& a, const VCPair& b)
+{
+    return (a.first && b.first)
+        ? a.first->offset < b.first->offset
+        : false;
+}
+
 // this time a bit more inspired by the DMD code.
 
 LLConstant * IrStruct::createStructInitializer(StructInitializer * si)
@@ -218,7 +229,6 @@
     assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer");
 
     // array of things to build
-    typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair;
     llvm::SmallVector<VCPair, 16> data(aggrdecl->fields.dim);
 
     // start by creating a map from initializer indices to field indices.
@@ -254,81 +264,105 @@
             continue;
         }
 
+        IF_LOG Logger::println("Explicit initializer: %s @+%u", vd->toChars(), vd->offset);
+        LOG_SCOPE;
+
         data[idx].first = vd;
         data[idx].second = get_default_initializer(vd, ini);
     }
 
-    // build array of constants and try to fill in default initializers
-    // where there is room.
-    size_t offset = 0;
-    std::vector<llvm::Constant*> constants;
-    constants.reserve(16);
-
+    // fill in implicit initializers
     n = data.size();
     for (size_t i = 0; i < n; i++)
     {
         VarDeclaration* vd = data[i].first;
+        if (vd)
+            continue;
 
-        // explicitly initialized?
-        if (vd != NULL)
-        {
-            // get next aligned offset for this field
-            size_t alignedoffset = offset;
-            if (!packed)
-            {
-                size_t alignsize = vd->type->alignsize();
-                alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
-            }
+        vd = (VarDeclaration*)aggrdecl->fields.data[i];
 
-            // insert explicit padding?
-            if (alignedoffset < vd->offset)
-            {
-                add_zeros(constants, vd->offset - alignedoffset);
-            }
+        unsigned vd_begin = vd->offset;
+        unsigned vd_end = vd_begin + vd->type->size();
 
-            IF_LOG Logger::println("using field: %s", vd->toChars());
-            constants.push_back(data[i].second);
-            offset = vd->offset + vd->type->size();
-        }
-        // not explicit! try and fit in the default initialization instead
-        // make sure we don't overlap with any following explicity initialized fields
-        else
+        // make sure it doesn't overlap any explicit initializers.
+        VarDeclarationIter it(aggrdecl->fields);
+        bool overlaps = false;
+        size_t j = 0;
+        for (; it.more(); it.next(), j++)
         {
-            vd = (VarDeclaration*)aggrdecl->fields.data[i];
+            if (i == j || !data[j].first)
+                continue;
 
-            // check all the way that we don't overlap, slow but it works!
-            for (size_t j = i+1; j <= n; j++)
-            {
-                if (j == n) // no overlap
-                {
-                    IF_LOG Logger::println("using field default: %s", vd->toChars());
-                    constants.push_back(get_default_initializer(vd, NULL));
-                    offset = vd->offset + vd->type->size();
-                    break;
-                }
+            unsigned f_begin = it->offset;
+            unsigned f_end = f_begin + it->type->size();
+
+            if (vd_begin >= f_end || vd_end <= f_begin)
+                continue;
 
-                VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j];
-
-                size_t o2 = vd->offset + vd->type->size();
+            overlaps = true;
+            break;
+        }
+        // add if no overlap found
+        if (!overlaps)
+        {
+            IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset);
+            LOG_SCOPE;
 
-                if (vd2->offset < o2 && data[i].first)
-                    break; // overlaps
-            }
+            data[i].first = vd;
+            data[i].second = get_default_initializer(vd, NULL);
         }
     }
 
-    // tail padding?
-    if (offset < aggrdecl->structsize)
-    {
-        add_zeros(constants, aggrdecl->structsize - offset);
-    }
-
     // stop if there were errors
     if (global.errors)
     {
         fatal();
     }
 
+    // sort data array by offset
+    std::sort(data.begin(), data.end(), struct_init_data_sort);
+
+    // build array of constants and make sure explicit zero padding is inserted when necessary.
+    size_t offset = 0;
+    std::vector<llvm::Constant*> constants;
+    constants.reserve(n);
+
+    for (size_t i = 0; i < n; i++)
+    {
+        VarDeclaration* vd = data[i].first;
+        if (vd == NULL)
+            continue;
+
+        // get next aligned offset for this field
+        size_t alignedoffset = offset;
+        if (!packed)
+        {
+            size_t alignsize = vd->type->alignsize();
+            alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
+        }
+
+        // insert explicit padding?
+        if (alignedoffset < vd->offset)
+        {
+            size_t diff = vd->offset - alignedoffset;
+            IF_LOG Logger::println("adding %zu bytes zero padding", diff);
+            add_zeros(constants, diff);
+        }
+
+        IF_LOG Logger::println("adding field %s", vd->toChars());
+
+        constants.push_back(data[i].second);
+        offset = vd->offset + vd->type->size();
+    }
+
+    // tail padding?
+    if (offset < aggrdecl->structsize)
+    {
+        size_t diff = aggrdecl->structsize - offset;
+        IF_LOG Logger::println("adding %zu bytes zero padding", diff);
+        add_zeros(constants, diff);
+    }
+
     // build constant
     assert(!constants.empty());
     llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed);