support for variable sized compound/array types
authorMatthias Braun <matthias.braun@kit.edu>
Mon, 12 Mar 2012 18:31:12 +0000 (19:31 +0100)
committerMatthias Braun <matthias.braun@kit.edu>
Mon, 12 Mar 2012 18:31:12 +0000 (19:31 +0100)
This adds support for C99/gcc style compound types where the last
element is an array of unspecified size. The compound size is the
minimum size (assuming the array has no elements), or is calculated
by the size of an initializer.

include/libfirm/typerep.h
ir/be/begnuas.c
ir/tr/type.c
ir/tr/type_t.h

index c409f04..4a8341d 100644 (file)
@@ -1880,6 +1880,19 @@ FIRM_API void set_array_element_entity(ir_type *array, ir_entity *ent);
 /** Returns the array element entity. */
 FIRM_API ir_entity *get_array_element_entity(const ir_type *array);
 
+/**
+ * Sets the array variable size flag.
+ * If this flag is set then no upper/lower bounds need to be set and
+ * get_type_size_bytes() returns -1
+ */
+FIRM_API void set_array_variable_size(ir_type *array, int variable_size_flag);
+
+/**
+ * Returns the array variable size flag.
+ * @see set_array_variable_size()
+ */
+FIRM_API int is_array_variable_size(const ir_type *array);
+
 /** Returns true if a type is an array type. */
 FIRM_API int is_Array_type(const ir_type *array);
 
@@ -2188,6 +2201,20 @@ FIRM_API size_t get_compound_member_index(const ir_type *tp, ir_entity *member);
 /** Remove a member from a compound type. */
 FIRM_API void remove_compound_member(ir_type *compound, ir_entity *entity);
 
+/**
+ * Sets the variable size flag of a compound type.
+ * The last member of a variable size compound type may be an array type
+ * without explicit size. So the get_type_size_bytes() of a variable size
+ * compound type only returns a minimum size for the type (the size if the
+ * last members size is 0)
+ */
+FIRM_API void set_compound_variable_size(ir_type *compound, int variable_size);
+
+/**
+ * Returns the variable size flag. @see set_compound_variable_size()
+ */
+FIRM_API int is_compound_variable_size(const ir_type *compound);
+
 /**
  * layout members of a struct/union or class type in a default way.
  */
index 707196a..bfb32a9 100644 (file)
@@ -930,13 +930,6 @@ typedef struct {
        } v;
 } normal_or_bitfield;
 
-static int is_type_variable_size(ir_type *type)
-{
-       (void) type;
-       /* TODO */
-       return 0;
-}
-
 static size_t get_initializer_size(const ir_initializer_t *initializer,
                                    ir_type *type)
 {
@@ -948,28 +941,34 @@ static size_t get_initializer_size(const ir_initializer_t *initializer,
        case IR_INITIALIZER_NULL:
                return get_type_size_bytes(type);
        case IR_INITIALIZER_COMPOUND:
-               if (!is_type_variable_size(type)) {
-                       return get_type_size_bytes(type);
+               if (is_Array_type(type)) {
+                       if (is_array_variable_size(type)) {
+                               ir_type   *element_type = get_array_element_type(type);
+                               unsigned   element_size = get_type_size_bytes(element_type);
+                               unsigned   element_align
+                                       = get_type_alignment_bytes(element_type);
+                               unsigned   misalign     = element_size % element_align;
+                               size_t     n_inits
+                                       = get_initializer_compound_n_entries(initializer);
+                               element_size += element_align - misalign;
+                               return n_inits * element_size;
+                       } else {
+                               return get_type_size_bytes(type);
+                       }
                } else {
-                       size_t n_entries
-                               = get_initializer_compound_n_entries(initializer);
-                       size_t i;
-                       unsigned initializer_size = get_type_size_bytes(type);
-                       for (i = 0; i < n_entries; ++i) {
-                               ir_entity *entity = get_compound_member(type, i);
-                               ir_type   *type   = get_entity_type(entity);
-
-                               const ir_initializer_t *sub_initializer
-                                       = get_initializer_compound_value(initializer, i);
-
-                               unsigned offset = get_entity_offset(entity);
-                               unsigned size   = get_initializer_size(sub_initializer, type);
-
-                               if (offset + size > initializer_size) {
-                                       initializer_size = offset + size;
-                               }
+                       assert(is_compound_type(type));
+                       size_t size = get_type_size_bytes(type);
+                       if (is_compound_variable_size(type)) {
+                               /* last initializer has to be an array of variable size */
+                               size_t l = get_initializer_compound_n_entries(initializer)-1;
+                               const ir_initializer_t *last
+                                       = get_initializer_compound_value(initializer, l);
+                               const ir_entity *last_ent  = get_compound_member(type, l);
+                               ir_type         *last_type = get_entity_type(last_ent);
+                               assert(is_array_variable_size(last_type));
+                               size += get_initializer_size(last, last_type);
                        }
-                       return initializer_size;
+                       return size;
                }
        }
 
index 192b0b3..88144aa 100644 (file)
@@ -46,6 +46,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stddef.h>
+#include <stdbool.h>
 
 #include "type_t.h"
 
@@ -1448,7 +1449,7 @@ ir_type *new_type_array(size_t n_dimensions, ir_type *element_type)
 
 void free_array_automatic_entities(ir_type *array)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        free_entity(get_array_element_entity(array));
 }
 
@@ -1475,7 +1476,7 @@ size_t get_array_n_dimensions(const ir_type *array)
 void set_array_bounds(ir_type *array, size_t dimension, ir_node *lower_bound,
                       ir_node *upper_bound)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        assert(lower_bound && "lower_bound node may not be NULL.");
        assert(upper_bound && "upper_bound node may not be NULL.");
        assert(dimension < array->attr.aa.n_dimensions);
@@ -1495,7 +1496,7 @@ void set_array_bounds_int(ir_type *array, size_t dimension, int lower_bound,
 void set_array_lower_bound(ir_type *array, size_t dimension,
                            ir_node *lower_bound)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        assert(lower_bound && "lower_bound node may not be NULL.");
        array->attr.aa.lower_bound[dimension] = lower_bound;
 }
@@ -1509,7 +1510,7 @@ void set_array_lower_bound_int(ir_type *array, size_t dimension, int lower_bound
 
 void set_array_upper_bound(ir_type *array, size_t dimension, ir_node *upper_bound)
 {
-  assert(array && (array->type_op == type_array));
+  assert(array->type_op == type_array);
   assert(upper_bound && "upper_bound node may not be NULL.");
   array->attr.aa.upper_bound[dimension] = upper_bound;
 }
@@ -1523,20 +1524,20 @@ void set_array_upper_bound_int(ir_type *array, size_t dimension, int upper_bound
 
 int has_array_lower_bound(const ir_type *array, size_t dimension)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return !is_Unknown(array->attr.aa.lower_bound[dimension]);
 }
 
 ir_node *get_array_lower_bound(const ir_type *array, size_t dimension)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return array->attr.aa.lower_bound[dimension];
 }
 
 long get_array_lower_bound_int(const ir_type *array, size_t dimension)
 {
        ir_node *node;
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        node = array->attr.aa.lower_bound[dimension];
        assert(is_Const(node));
        return get_tarval_long(get_Const_tarval(node));
@@ -1544,20 +1545,20 @@ long get_array_lower_bound_int(const ir_type *array, size_t dimension)
 
 int has_array_upper_bound(const ir_type *array, size_t dimension)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return !is_Unknown(array->attr.aa.upper_bound[dimension]);
 }
 
 ir_node *get_array_upper_bound(const ir_type *array, size_t dimension)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return array->attr.aa.upper_bound[dimension];
 }
 
 long get_array_upper_bound_int(const ir_type *array, size_t dimension)
 {
        ir_node *node;
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        node = array->attr.aa.upper_bound[dimension];
        assert(is_Const(node));
        return get_tarval_long(get_Const_tarval(node));
@@ -1565,13 +1566,13 @@ long get_array_upper_bound_int(const ir_type *array, size_t dimension)
 
 void set_array_order(ir_type *array, size_t dimension, size_t order)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        array->attr.aa.order[dimension] = order;
 }
 
 size_t get_array_order(const ir_type *array, size_t dimension)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return array->attr.aa.order[dimension];
 }
 
@@ -1590,20 +1591,20 @@ size_t find_array_dimension(const ir_type *array, size_t order)
 
 void set_array_element_type(ir_type *array, ir_type *tp)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        assert(!is_Method_type(tp));
        array->attr.aa.element_type = tp;
 }
 
 ir_type *get_array_element_type(const ir_type *array)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return array->attr.aa.element_type;
 }
 
 void set_array_element_entity(ir_type *array, ir_entity *ent)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        assert((get_entity_type(ent)->type_op != type_method));
        array->attr.aa.element_ent = ent;
        array->attr.aa.element_type = get_entity_type(ent);
@@ -1611,10 +1612,23 @@ void set_array_element_entity(ir_type *array, ir_entity *ent)
 
 ir_entity *get_array_element_entity(const ir_type *array)
 {
-       assert(array && (array->type_op == type_array));
+       assert(array->type_op == type_array);
        return array->attr.aa.element_ent;
 }
 
+int is_array_variable_size(const ir_type *array)
+{
+       assert(array->type_op == type_array);
+       return (array->flags & tf_variable_size) != 0;
+}
+
+void set_array_variable_size(ir_type *array, int flag)
+{
+       assert(array->type_op == type_array);
+       array->flags = (array->flags & ~tf_variable_size)
+                      | (flag != 0 ? tf_variable_size : 0);
+}
+
 int (is_Array_type)(const ir_type *array)
 {
        return _is_array_type(array);
@@ -1880,6 +1894,19 @@ size_t get_compound_member_index(const ir_type *tp, ir_entity *member)
        return op->ops.get_member_index(tp, member);
 }
 
+void set_compound_variable_size(ir_type *tp, int variable_size_flag)
+{
+       assert(is_compound_type(tp));
+       tp->flags = (tp->flags & ~tf_variable_size)
+                   | (variable_size_flag != 0 ? tf_variable_size : 0);
+}
+
+int is_compound_variable_size(const ir_type *tp)
+{
+       assert(is_compound_type(tp));
+       return (tp->flags & tf_variable_size) != 0;
+}
+
 int is_compound_type(const ir_type *tp)
 {
        assert(tp->kind == k_type);
@@ -1982,21 +2009,29 @@ void set_default_size(ir_type *tp, unsigned size)
 
 void default_layout_compound_type(ir_type *type)
 {
-       size_t i;
-       size_t n = get_compound_n_members(type);
-       int size = 0;
+       size_t   i;
+       size_t   n         = get_compound_n_members(type);
+       int      size      = 0;
        unsigned align_all = 1;
+       bool     var_size  = is_compound_variable_size(type);
 
        for (i = 0; i < n; ++i) {
                ir_entity *entity      = get_compound_member(type, i);
                ir_type   *entity_type = get_entity_type(entity);
                unsigned   align;
                unsigned   misalign;
+               unsigned   entity_size;
 
                if (is_Method_type(entity_type))
                        continue;
 
-               assert(get_type_state(entity_type) == layout_fixed);
+               if (i+1 < n || !var_size) {
+                       assert(get_type_state(entity_type) == layout_fixed);
+                       entity_size = get_type_size_bytes(entity_type);
+               } else {
+                       entity_size = 0;
+               }
+
                align     = get_type_alignment_bytes(entity_type);
                align_all = align > align_all ? align : align_all;
                misalign  = (align ? size % align : 0);
@@ -2004,7 +2039,7 @@ void default_layout_compound_type(ir_type *type)
 
                set_entity_offset(entity, size);
                if (!is_Union_type(type)) {
-                       size += get_type_size_bytes(entity_type);
+                       size += entity_size;
                }
        }
        if (align_all > 0 && size % align_all) {
index b5f3fd7..7923b1e 100644 (file)
@@ -139,6 +139,7 @@ enum type_flags {
        tf_tls_type         = 1U << 5, /**< Set only for the tls type */
        tf_constructors     = 1U << 6, /**< Set only for the constructors segment type */
        tf_destructors      = 1U << 7, /**< Set only for the destructors segment type */
+       tf_variable_size    = 1U << 8, /**< compound or array type may have variable size last element */
 };
 ENUM_BITSET(type_flags)