packed struct implementation, attribute assignment isn't always correct yet
authorMatthias Braun <matze@braunis.de>
Sun, 8 Mar 2009 19:23:44 +0000 (19:23 +0000)
committerMatthias Braun <matze@braunis.de>
Sun, 8 Mar 2009 19:23:44 +0000 (19:23 +0000)
[r25642]

ast2firm.c
attribute.c
entity_t.h
parser.c
type.c
type.h

index 222965c..0fa1e3e 100644 (file)
@@ -323,13 +323,13 @@ static ir_type *create_complex_type(const complex_type_t *type)
 /**
  * Creates a Firm type for an imaginary type
  */
-static ir_type *create_imaginary_type(const imaginary_type_t *type)
+static ir_type *create_imaginary_type(imaginary_type_t *type)
 {
        atomic_type_kind_t  kind      = type->akind;
        ir_mode            *mode      = atomic_modes[kind];
        ident              *id        = get_mode_ident(mode);
        ir_type            *irtype    = new_type_primitive(id, mode);
-       il_alignment_t      alignment = get_type_alignment((const type_t*) type);
+       il_alignment_t      alignment = get_type_alignment((type_t*) type);
 
        set_type_alignment_bytes(irtype, alignment);
 
@@ -599,6 +599,12 @@ static ir_type *create_compound_type(compound_type_t *type,
        if (incomplete)
                return irtype;
 
+       if (is_union) {
+               layout_union_type(type);
+       } else {
+               layout_struct_type(type);
+       }
+
        compound->irtype_complete = true;
 
        entity_t *entry = compound->members.entities;
index 8bca90b..1a868d6 100644 (file)
@@ -246,18 +246,32 @@ static void warn_arguments(const attribute_t *attribute)
        }
 }
 
-static void handle_attribute_packed(const attribute_t *attribute,
-                                    entity_t *entity)
+static void handle_attribute_packed_e(const attribute_t *attribute,
+                                      entity_t *entity)
 {
+#if 0
+       if (entity->kind != ENTITY_STRUCT) {
+               warningf(&attribute->source_position,
+                        "packed attribute on %s '%s' ignored",
+                                get_entity_kind_name(entity->kind),
+                                entity->base.symbol->string);
+               return;
+       }
+#endif
+
        warn_arguments(attribute);
+       entity->compound.packed = true;
+}
 
-       if (entity->kind == ENTITY_STRUCT) {
-               entity->compound.packed = true;
-       } else if (warning.other) {
+static void handle_attribute_packed(const attribute_t *attribute, type_t *type)
+{
+       if (type->kind != TYPE_COMPOUND_STRUCT) {
                warningf(&attribute->source_position,
-                        "packed attribute on %s ignored",
-                                get_entity_kind_name(entity->kind));
+                        "packed attribute on type '%T' ignored", type);
+               return;
        }
+
+       handle_attribute_packed_e(attribute, (entity_t*) type->compound.compound);
 }
 
 void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
@@ -310,8 +324,9 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                case ATTRIBUTE_MS_NOALIAS:       modifiers |= DM_NOALIAS; break;
 
                case ATTRIBUTE_GNU_PACKED:
-                       handle_attribute_packed(attribute, entity);
-                       break;
+                       handle_attribute_packed_e(attribute, entity);
+                       break;
+
                case ATTRIBUTE_MS_ALIGN:
                case ATTRIBUTE_GNU_ALIGNED:
                        handle_attribute_aligned(attribute, entity);
@@ -360,6 +375,9 @@ type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
        const attribute_t *attribute = attributes;
        for ( ; attribute != NULL; attribute = attribute->next) {
                switch(attribute->kind) {
+               case ATTRIBUTE_GNU_PACKED:
+                       handle_attribute_packed(attribute, type);
+                       break;
                case ATTRIBUTE_GNU_CDECL:
                case ATTRIBUTE_MS_CDECL:
                        type = change_calling_convention(type, CC_CDECL);
index 76ce5e6..ee19b7b 100644 (file)
@@ -125,6 +125,7 @@ struct compound_t {
        entity_t         *alias; /* used for name mangling of anonymous types */
        scope_t           members;
        decl_modifiers_t  modifiers;
+       bool              layouted          : 1;
        bool              complete          : 1;
        bool              transparent_union : 1;
        bool              packed            : 1;
index 7321f2d..4d1b44b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2532,11 +2532,12 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                eat(T_union);
        }
 
-       symbol_t   *symbol   = NULL;
-       compound_t *compound = NULL;
+       symbol_t    *symbol   = NULL;
+       compound_t  *compound = NULL;
+       attribute_t *attributes = NULL;
 
        if (token.type == T___attribute__) {
-               parse_attributes(NULL);
+               attributes = parse_attributes(NULL);
        }
 
        entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
@@ -2590,7 +2591,6 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
 
        if (token.type == '{') {
                parse_compound_type_entries(compound);
-               parse_attributes(NULL);
 
                /* ISO/IEC 14882:1998(E) ยง7.1.3:5 */
                if (symbol == NULL) {
@@ -2599,6 +2599,10 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                }
        }
 
+       if (attributes != NULL) {
+               handle_entity_attributes(attributes, (entity_t*) compound);
+       }
+
        return compound;
 }
 
@@ -2978,163 +2982,6 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        return entity;
 }
 
-static entity_t *pack_bitfield_members(il_size_t *size, type_t *type,
-                                       size_t offset, entity_t *first)
-{
-       /* TODO: packed handling */
-       type_t *base_type      = skip_typeref(type->bitfield.base_type);
-       size_t  remaining_bits = get_type_size(base_type) * BITS_PER_BYTE;
-       size_t  bit_offset     = 0;
-
-       entity_t *member;
-       for (member = first; member != NULL; member = member->base.next) {
-               /* TODO: make this an assert */
-               if (member->kind != ENTITY_COMPOUND_MEMBER)
-                       continue;
-
-               type_t *member_type = member->declaration.type;
-               if (member_type->kind != TYPE_BITFIELD)
-                       break;
-               if (base_type != NULL
-                   && skip_typeref(member_type->bitfield.base_type) != base_type)
-                       break;
-
-               size_t bit_size = member_type->bitfield.bit_size;
-               if (bit_size > remaining_bits)
-                       break;
-
-               member->compound_member.offset     = offset;
-               member->compound_member.bit_offset = bit_offset;
-
-               bit_offset += bit_size;
-
-               /* 0-size members end current bucket. multiple 0-size buckets
-                * seem to not start-end multiple buckets */
-               if (bit_size == 0) {
-                       remaining_bits = 0;
-               } else {
-                       remaining_bits -= bit_size;
-               }
-       }
-       assert(member != first);
-
-       *size += (bit_offset + (BITS_PER_BYTE-1)) / BITS_PER_BYTE;
-
-       return member;
-}
-
-/**
- * Finish the construction of a struct type by calculating its size, offsets,
- * alignment.
- */
-static void finish_struct_type(compound_type_t *type)
-{
-       assert(type->compound != NULL);
-
-       compound_t *compound = type->compound;
-       if (!compound->complete)
-               return;
-
-       il_size_t      offset;
-       il_size_t      size      = 0;
-       il_alignment_t alignment = compound->alignment;
-       bool           need_pad  = false;
-
-       entity_t *entry = compound->members.entities;
-       while (entry != NULL) {
-               if (entry->kind != ENTITY_COMPOUND_MEMBER) {
-                       entry = entry->base.next;
-                       continue;
-               }
-
-               type_t *m_type  = entry->declaration.type;
-               type_t *skipped = skip_typeref(m_type);
-               if (! is_type_valid(skipped)) {
-                       entry = entry->base.next;
-                       continue;
-               }
-
-               type_t *base_type = m_type;
-               if (skipped->kind == TYPE_BITFIELD) {
-                       base_type = m_type->bitfield.base_type;
-               }
-
-               il_alignment_t m_alignment = get_type_alignment(base_type);
-               il_size_t      m_size      = get_type_size(base_type);
-               if (m_alignment > alignment)
-                       alignment = m_alignment;
-
-               offset = (size + m_alignment - 1) & -m_alignment;
-
-               if (offset > size)
-                       need_pad = true;
-
-               if (skipped->kind == TYPE_BITFIELD) {
-                       entry = pack_bitfield_members(&size, m_type, offset, entry);
-               } else {
-                       entry->compound_member.offset = offset;
-                       size                          = offset + m_size;
-
-                       entry = entry->base.next;
-               }
-       }
-
-       offset = (size + alignment - 1) & -alignment;
-       if (offset > size)
-               need_pad = true;
-
-       if (need_pad) {
-               if (warning.padded) {
-                       warningf(&compound->base.source_position, "'%T' needs padding",
-                                type);
-               }
-       } else if (compound->packed && warning.packed) {
-               warningf(&compound->base.source_position,
-                        "superfluous packed attribute on '%T'", type);
-       }
-
-       compound->size      = offset;
-       compound->alignment = alignment;
-}
-
-/**
- * Finish the construction of an union type by calculating
- * its size and alignment.
- */
-static void finish_union_type(compound_type_t *type)
-{
-       assert(type->compound != NULL);
-
-       compound_t *compound = type->compound;
-       if (! compound->complete)
-               return;
-
-       il_size_t      size      = 0;
-       il_alignment_t alignment = compound->alignment;
-
-       entity_t *entry = compound->members.entities;
-       for (; entry != NULL; entry = entry->base.next) {
-               if (entry->kind != ENTITY_COMPOUND_MEMBER)
-                       continue;
-
-               type_t *m_type = entry->declaration.type;
-               if (! is_type_valid(skip_typeref(m_type)))
-                       continue;
-
-               entry->compound_member.offset = 0;
-               il_size_t m_size = get_type_size(m_type);
-               if (m_size > size)
-                       size = m_size;
-               il_alignment_t m_alignment = get_type_alignment(m_type);
-               if (m_alignment > alignment)
-                       alignment = m_alignment;
-       }
-       size = (size + alignment - 1) & -alignment;
-
-       compound->size      = size;
-       compound->alignment = alignment;
-}
-
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
        type_t            *type              = NULL;
@@ -3280,13 +3127,11 @@ wrong_thread_stoarge_class:
                        type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
 
                        type->compound.compound = parse_compound_type_specifier(true);
-                       finish_struct_type(&type->compound);
                        break;
                case T_union:
                        CHECK_DOUBLE_TYPE();
                        type = allocate_type_zero(TYPE_COMPOUND_UNION);
                        type->compound.compound = parse_compound_type_specifier(false);
-                       finish_union_type(&type->compound);
                        break;
                case T_enum:
                        CHECK_DOUBLE_TYPE();
diff --git a/type.c b/type.c
index 0c73682..4671d37 100644 (file)
--- a/type.c
+++ b/type.c
@@ -30,6 +30,8 @@
 #include "adt/error.h"
 #include "adt/util.h"
 #include "lang_features.h"
+#include "warning.h"
+#include "diagnostic.h"
 
 static struct obstack   _type_obst;
 static FILE            *out;
@@ -1274,7 +1276,7 @@ type_t *skip_typeref(type_t *type)
        return type;
 }
 
-unsigned get_type_size(const type_t *type)
+unsigned get_type_size(type_t *type)
 {
        switch (type->kind) {
        case TYPE_INVALID:
@@ -1288,7 +1290,10 @@ unsigned get_type_size(const type_t *type)
        case TYPE_IMAGINARY:
                return get_atomic_type_size(type->imaginary.akind);
        case TYPE_COMPOUND_UNION:
+               layout_union_type(&type->compound);
+               return type->compound.compound->size;
        case TYPE_COMPOUND_STRUCT:
+               layout_struct_type(&type->compound);
                return type->compound.compound->size;
        case TYPE_ENUM:
                return get_atomic_type_size(type->enumt.akind);
@@ -1319,7 +1324,7 @@ unsigned get_type_size(const type_t *type)
        panic("invalid type in get_type_size");
 }
 
-unsigned get_type_alignment(const type_t *type)
+unsigned get_type_alignment(type_t *type)
 {
        switch (type->kind) {
        case TYPE_INVALID:
@@ -1333,7 +1338,10 @@ unsigned get_type_alignment(const type_t *type)
        case TYPE_IMAGINARY:
                return get_atomic_type_alignment(type->imaginary.akind);
        case TYPE_COMPOUND_UNION:
+               layout_union_type(&type->compound);
+               return type->compound.compound->alignment;
        case TYPE_COMPOUND_STRUCT:
+               layout_struct_type(&type->compound);
                return type->compound.compound->alignment;
        case TYPE_ENUM:
                return get_atomic_type_alignment(type->enumt.akind);
@@ -1672,6 +1680,177 @@ type_t *make_array_type(type_t *element_type, size_t size,
        return identify_new_type(type);
 }
 
+static entity_t *pack_bitfield_members(il_size_t *size, bool packed,
+                                       type_t *type, size_t offset,
+                                                                          entity_t *first)
+{
+       /* TODO: packed handling */
+       type_t *base_type      = skip_typeref(type->bitfield.base_type);
+       size_t  remaining_bits = get_type_size(base_type) * BITS_PER_BYTE;
+       size_t  bit_offset     = 0;
+
+       entity_t *member;
+       for (member = first; member != NULL; member = member->base.next) {
+               /* TODO: make this an assert */
+               if (member->kind != ENTITY_COMPOUND_MEMBER)
+                       continue;
+
+               type_t *member_type = member->declaration.type;
+               if (member_type->kind != TYPE_BITFIELD)
+                       break;
+               size_t bit_size = member_type->bitfield.bit_size;
+               if (!packed) {
+                       if (base_type != NULL
+                           && skip_typeref(member_type->bitfield.base_type) != base_type)
+                               break;
+                       if (bit_size > remaining_bits)
+                               break;
+               }
+
+               member->compound_member.offset     = offset;
+               member->compound_member.bit_offset = bit_offset;
+
+               bit_offset += bit_size;
+
+               /* 0-size members end current bucket. multiple 0-size buckets
+                * seem to not start-end multiple buckets */
+               if (bit_size == 0) {
+                       remaining_bits = 0;
+               } else {
+                       remaining_bits -= bit_size;
+               }
+       }
+       assert(member != first);
+
+       *size += (bit_offset + (BITS_PER_BYTE-1)) / BITS_PER_BYTE;
+
+       return member;
+}
+
+/**
+ * Finish the construction of a struct type by calculating its size, offsets,
+ * alignment.
+ */
+void layout_struct_type(compound_type_t *type)
+{
+       assert(type->compound != NULL);
+
+       compound_t *compound = type->compound;
+       if (!compound->complete)
+               return;
+       if (type->compound->layouted)
+               return;
+
+       il_size_t      offset;
+       il_size_t      size      = 0;
+       il_alignment_t alignment = compound->alignment;
+       bool           need_pad  = false;
+
+       entity_t *entry = compound->members.entities;
+       while (entry != NULL) {
+               if (entry->kind != ENTITY_COMPOUND_MEMBER) {
+                       entry = entry->base.next;
+                       continue;
+               }
+
+               type_t *m_type  = entry->declaration.type;
+               type_t *skipped = skip_typeref(m_type);
+               if (! is_type_valid(skipped)) {
+                       entry = entry->base.next;
+                       continue;
+               }
+
+               type_t *base_type = m_type;
+               if (skipped->kind == TYPE_BITFIELD) {
+                       base_type = m_type->bitfield.base_type;
+               }
+
+               il_alignment_t m_alignment = get_type_alignment(base_type);
+               il_size_t      m_size      = get_type_size(base_type);
+               if (m_alignment > alignment)
+                       alignment = m_alignment;
+
+               if (compound->packed) {
+                       offset = size;
+               } else {
+                       offset = (size + m_alignment - 1) & -m_alignment;
+               }
+
+               if (offset > size)
+                       need_pad = true;
+
+               if (skipped->kind == TYPE_BITFIELD) {
+                       entry = pack_bitfield_members(&size, compound->packed,
+                                                     m_type, offset, entry);
+               } else {
+                       entry->compound_member.offset = offset;
+                       size                          = offset + m_size;
+
+                       entry = entry->base.next;
+               }
+       }
+
+       if (!compound->packed) {
+               offset = (size + alignment - 1) & -alignment;
+               if (offset > size)
+                       need_pad = true;
+       } else {
+               offset = size;
+       }
+
+       if (need_pad) {
+               if (warning.padded) {
+                       warningf(&compound->base.source_position, "'%T' needs padding",
+                                type);
+               }
+       } else if (compound->packed && warning.packed) {
+               warningf(&compound->base.source_position,
+                        "superfluous packed attribute on '%T'", type);
+       }
+
+       compound->size      = offset;
+       compound->alignment = alignment;
+       compound->layouted  = true;
+}
+
+/**
+ * Finish the construction of an union type by calculating
+ * its size and alignment.
+ */
+void layout_union_type(compound_type_t *type)
+{
+       assert(type->compound != NULL);
+
+       compound_t *compound = type->compound;
+       if (! compound->complete)
+               return;
+
+       il_size_t      size      = 0;
+       il_alignment_t alignment = compound->alignment;
+
+       entity_t *entry = compound->members.entities;
+       for (; entry != NULL; entry = entry->base.next) {
+               if (entry->kind != ENTITY_COMPOUND_MEMBER)
+                       continue;
+
+               type_t *m_type = entry->declaration.type;
+               if (! is_type_valid(skip_typeref(m_type)))
+                       continue;
+
+               entry->compound_member.offset = 0;
+               il_size_t m_size = get_type_size(m_type);
+               if (m_size > size)
+                       size = m_size;
+               il_alignment_t m_alignment = get_type_alignment(m_type);
+               if (m_alignment > alignment)
+                       alignment = m_alignment;
+       }
+       size = (size + alignment - 1) & -alignment;
+
+       compound->size      = size;
+       compound->alignment = alignment;
+}
+
 /**
  * Debug helper. Prints the given type to stdout.
  */
diff --git a/type.h b/type.h
index cf0e5a1..8c7872e 100644 (file)
--- a/type.h
+++ b/type.h
@@ -192,8 +192,8 @@ unsigned get_atomic_type_size(atomic_type_kind_t kind);
  */
 unsigned get_atomic_type_alignment(atomic_type_kind_t kind);
 
-unsigned         get_type_alignment(const type_t *type);
-unsigned         get_type_size(const type_t *type);
+unsigned         get_type_alignment(type_t *type);
+unsigned         get_type_size(type_t *type);
 decl_modifiers_t get_type_modifiers(const type_t *type);
 
 /**
@@ -216,4 +216,7 @@ atomic_type_kind_t find_unsigned_int_atomic_type_kind_for_size(unsigned size);
 
 const char *get_atomic_kind_name(atomic_type_kind_t kind);
 
+void layout_struct_type(compound_type_t *type);
+void layout_union_type(compound_type_t *type);
+
 #endif