X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=type.c;h=667a912be41a78d20e40c36d8862e79b7e4e0a4b;hb=798ad4944c5714d572ce492a72a0836b83a55dd4;hp=0c736829ad22e58099e3a12c617d00f5bd8281c4;hpb=6a7adde8512cf76b6cc5c67bece168b43c913c26;p=cparser diff --git a/type.c b/type.c index 0c73682..667a912 100644 --- a/type.c +++ b/type.c @@ -1,6 +1,6 @@ /* * This file is part of cparser. - * Copyright (C) 2007-2008 Matthias Braun + * Copyright (C) 2007-2009 Matthias Braun * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,11 +30,16 @@ #include "adt/error.h" #include "adt/util.h" #include "lang_features.h" +#include "warning.h" +#include "diagnostic.h" +#include "driver/firm_cmdline.h" + +/** The default calling convention. */ +cc_kind_t default_calling_convention = CC_CDECL; static struct obstack _type_obst; static FILE *out; struct obstack *type_obst = &_type_obst; -static int type_visited = 0; static bool print_implicit_array_size = false; static void intern_print_type_pre(const type_t *type); @@ -184,6 +189,10 @@ void init_types(void) props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 4; props[ATOMIC_TYPE_LONGLONG].alignment = 4; props[ATOMIC_TYPE_ULONGLONG].alignment = 4; + if (firm_opt.os_support == OS_SUPPORT_MACHO) { + props[ATOMIC_TYPE_LONG_DOUBLE].size = 16; + props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 16; + } /* TODO: make this configurable for platforms which do not use byte sized * bools. */ @@ -202,11 +211,6 @@ void type_set_output(FILE *stream) out = stream; } -void inc_type_visited(void) -{ - type_visited++; -} - void print_type_qualifiers(type_qualifiers_t qualifiers) { int first = 1; @@ -329,12 +333,20 @@ static void print_function_type_pre(const function_type_t *type) intern_print_type_pre(type->return_type); - switch (type->calling_convention) { - case CC_CDECL: fputs("__cdecl ", out); break; - case CC_STDCALL: fputs("__stdcall ", out); break; - case CC_FASTCALL: fputs("__fastcall ", out); break; - case CC_THISCALL: fputs("__thiscall ", out); break; - case CC_DEFAULT: break; + cc_kind_t cc = type->calling_convention; +restart: + switch (cc) { + case CC_CDECL: fputs(" __cdecl", out); break; + case CC_STDCALL: fputs(" __stdcall", out); break; + case CC_FASTCALL: fputs(" __fastcall", out); break; + case CC_THISCALL: fputs(" __thiscall", out); break; + case CC_DEFAULT: + if (default_calling_convention != CC_CDECL) { + /* show the default calling convention if its not cdecl */ + cc = default_calling_convention; + goto restart; + } + break; } } @@ -1095,11 +1107,15 @@ static bool function_types_compatible(const function_type_t *func1, if (func1->linkage != func2->linkage) return false; - /* this would make alot of sense, but gcc doesn't seem to do this */ -#if 0 - if (func1->calling_convention != func2->calling_convention) + cc_kind_t cc1 = func1->calling_convention; + if (cc1 == CC_DEFAULT) + cc1 = default_calling_convention; + cc_kind_t cc2 = func2->calling_convention; + if (cc2 == CC_DEFAULT) + cc2 = default_calling_convention; + + if (cc1 != cc2) return false; -#endif /* can parameters be compared? */ if (func1->unspecified_parameters || func2->unspecified_parameters) @@ -1274,7 +1290,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 +1304,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 +1338,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 +1352,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 +1694,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 *struct_offset, + il_alignment_t *struct_alignment, + bool packed, entity_t *first) +{ + il_size_t offset = *struct_offset; + il_alignment_t alignment = *struct_alignment; + size_t bit_offset = 0; + + entity_t *member; + for (member = first; member != NULL; member = member->base.next) { + if (member->kind != ENTITY_COMPOUND_MEMBER) + break; + + type_t *type = member->declaration.type; + if (type->kind != TYPE_BITFIELD) + break; + + type_t *base_type = skip_typeref(type->bitfield.base_type); + il_alignment_t base_alignment = get_type_alignment(base_type); + il_alignment_t alignment_mask = base_alignment-1; + if (base_alignment > alignment) + alignment = base_alignment; + + size_t bit_size = type->bitfield.bit_size; + if (!packed) { + bit_offset += (offset & alignment_mask) * BITS_PER_BYTE; + offset &= ~alignment_mask; + size_t base_size = get_type_size(base_type) * BITS_PER_BYTE; + + if (bit_offset + bit_size > base_size || bit_size == 0) { + offset += (bit_offset+BITS_PER_BYTE-1) / BITS_PER_BYTE; + offset = (offset + base_alignment-1) & ~alignment_mask; + bit_offset = 0; + } + } + + member->compound_member.offset = offset; + member->compound_member.bit_offset = bit_offset; + + bit_offset += bit_size; + offset += bit_offset / BITS_PER_BYTE; + bit_offset %= BITS_PER_BYTE; + } + + if (bit_offset > 0) + offset += 1; + + *struct_offset = offset; + *struct_alignment = alignment; + + 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 = 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; + } + + if (skipped->kind == TYPE_BITFIELD) { + entry = pack_bitfield_members(&offset, &alignment, + compound->packed, entry); + continue; + } + + il_alignment_t m_alignment = get_type_alignment(m_type); + if (m_alignment > alignment) + alignment = m_alignment; + + if (!compound->packed) { + il_size_t new_offset = (offset + m_alignment-1) & -m_alignment; + + if (new_offset > offset) { + need_pad = true; + offset = new_offset; + } + } + + entry->compound_member.offset = offset; + offset += get_type_size(m_type); + + entry = entry->base.next; + } + + if (!compound->packed) { + il_size_t new_offset = (offset + alignment-1) & -alignment; + if (new_offset > offset) { + need_pad = true; + offset = new_offset; + } + } + + 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. */