/**
* 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);
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;
}
}
-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)
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);
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);
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;
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;
if (token.type == '{') {
parse_compound_type_entries(compound);
- parse_attributes(NULL);
/* ISO/IEC 14882:1998(E) ยง7.1.3:5 */
if (symbol == NULL) {
}
}
+ if (attributes != NULL) {
+ handle_entity_attributes(attributes, (entity_t*) compound);
+ }
+
return compound;
}
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;
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();
#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;
return type;
}
-unsigned get_type_size(const type_t *type)
+unsigned get_type_size(type_t *type)
{
switch (type->kind) {
case TYPE_INVALID:
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);
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:
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);
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.
*/
*/
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);
/**
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