rework architecture specific type handling
authorMatthias Braun <matze@braunis.de>
Wed, 10 Aug 2011 10:43:48 +0000 (12:43 +0200)
committerMatthias Braun <matze@braunis.de>
Wed, 10 Aug 2011 10:43:48 +0000 (12:43 +0200)
move lots of architecture exceptions to main.c; adapt to latest libfirm

12 files changed:
ast.c
ast2firm.c
builtins.c
builtins.h
lang_features.h
main.c
parser.c
type.c
type.h
type_t.h
types.c
types.h

diff --git a/ast.c b/ast.c
index 2f327f2..b7588c5 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1647,7 +1647,7 @@ expression_classification_t is_linker_constant(const expression_t *expression)
                if (!is_type_pointer(dest) && (
                                dest->kind != TYPE_ATOMIC                                               ||
                                !(get_atomic_type_flags(dest->atomic.akind) & ATOMIC_TYPE_FLAG_INTEGER) ||
-                               get_atomic_type_size(dest->atomic.akind) < get_atomic_type_size(get_intptr_kind())
+                               get_atomic_type_size(dest->atomic.akind) < get_type_size(type_void_ptr)
                    ))
                        return EXPR_CLASS_VARIABLE;
 
index b81722d..a6658fc 100644 (file)
@@ -181,6 +181,15 @@ static ir_node *_expression_to_firm(const expression_t *expression);
 static ir_node *expression_to_firm(const expression_t *expression);
 static void create_local_declaration(entity_t *entity);
 
+static unsigned decide_modulo_shift(unsigned type_size)
+{
+       if (architecture_modulo_shift == 0)
+               return 0;
+       if (type_size < architecture_modulo_shift)
+               return architecture_modulo_shift;
+       return type_size;
+}
+
 static ir_mode *init_atomic_ir_mode(atomic_type_kind_t kind)
 {
        unsigned flags = get_atomic_type_flags(kind);
@@ -191,7 +200,7 @@ static ir_mode *init_atomic_ir_mode(atomic_type_kind_t kind)
                ir_mode_sort    sort;
                unsigned        bit_size     = size * 8;
                bool            is_signed    = (flags & ATOMIC_TYPE_FLAG_SIGNED) != 0;
-               unsigned        modulo_shift;
+               unsigned        modulo_shift = 0;
                ir_mode_arithmetic arithmetic;
 
                if (flags & ATOMIC_TYPE_FLAG_INTEGER) {
@@ -200,13 +209,12 @@ static ir_mode *init_atomic_ir_mode(atomic_type_kind_t kind)
                                 bit_size);
                        sort         = irms_int_number;
                        arithmetic   = irma_twos_complement;
-                       modulo_shift = bit_size < machine_size ? machine_size : bit_size;
+                       modulo_shift = decide_modulo_shift(bit_size);
                } else {
                        assert(flags & ATOMIC_TYPE_FLAG_FLOAT);
                        snprintf(name, sizeof(name), "F%u", bit_size);
                        sort         = irms_float_number;
                        arithmetic   = irma_ieee754;
-                       modulo_shift = 0;
                }
                return new_ir_mode(name, sort, bit_size, is_signed, arithmetic,
                                   modulo_shift);
@@ -228,26 +236,6 @@ static void init_atomic_modes(void)
 
        /* there's no real void type in firm */
        atomic_modes[ATOMIC_TYPE_VOID] = atomic_modes[ATOMIC_TYPE_CHAR];
-
-       /* initialize pointer modes */
-       char            name[64];
-       ir_mode_sort    sort         = irms_reference;
-       unsigned        bit_size     = machine_size;
-       bool            is_signed    = 0;
-       ir_mode_arithmetic arithmetic   = irma_twos_complement;
-       unsigned        modulo_shift
-               = bit_size < machine_size ? machine_size : bit_size;
-
-       snprintf(name, sizeof(name), "p%u", machine_size);
-       ir_mode *ptr_mode = new_ir_mode(name, sort, bit_size, is_signed, arithmetic,
-                                       modulo_shift);
-
-       set_reference_mode_signed_eq(ptr_mode, atomic_modes[get_intptr_kind()]);
-       set_reference_mode_unsigned_eq(ptr_mode, atomic_modes[get_uintptr_kind()]);
-
-       /* Hmm, pointers should be machine size */
-       set_modeP_data(ptr_mode);
-       set_modeP_code(ptr_mode);
 }
 
 ir_mode *get_atomic_mode(atomic_type_kind_t kind)
@@ -1296,6 +1284,8 @@ static ir_node *literal_to_firm(const literal_expression_t *literal)
        }
        case EXPR_LITERAL_CHARACTER: {
                long long int v;
+               bool char_is_signed
+                       = get_atomic_type_flags(ATOMIC_TYPE_CHAR) & ATOMIC_TYPE_FLAG_SIGNED;
                if (size == 1 && char_is_signed) {
                        v = (signed char)string[0];
                } else {
@@ -2189,10 +2179,14 @@ static ir_node *bitfield_extract_to_firm(const select_expression_t *expression,
        ir_node  *load_mem  = new_d_Proj(dbgi, load, mode_M, pn_Load_M);
        ir_node  *load_res  = new_d_Proj(dbgi, load, mode, pn_Load_res);
 
-       type_t   *type     = expression->base.type;
-       ir_mode  *resmode  = get_ir_mode_arithmetic(type);
-       unsigned  res_size = get_mode_size_bits(resmode);
-       load_res = create_conv(dbgi, load_res, resmode);
+       ir_mode  *amode     = mode;
+       /* optimisation, since shifting in modes < machine_size is usually
+        * less efficient */
+       if (get_mode_size_bits(amode) < get_mode_size_bits(mode_uint)) {
+               amode = mode_uint;
+       }
+       unsigned amode_size = get_mode_size_bits(amode);
+       load_res = create_conv(dbgi, load_res, amode);
 
        set_store(load_mem);
 
@@ -2200,22 +2194,24 @@ static ir_node *bitfield_extract_to_firm(const select_expression_t *expression,
        assert(expression->compound_entry->kind == ENTITY_COMPOUND_MEMBER);
        int        bitoffset   = entity->compound_member.bit_offset;
        int        bitsize     = entity->compound_member.bit_size;
-       unsigned   shift_bitsl = res_size - bitoffset - bitsize;
+       unsigned   shift_bitsl = amode_size - bitoffset - bitsize;
        ir_tarval *tvl         = new_tarval_from_long((long)shift_bitsl, mode_uint);
        ir_node   *countl      = new_d_Const(dbgi, tvl);
-       ir_node   *shiftl      = new_d_Shl(dbgi, load_res, countl, resmode);
+       ir_node   *shiftl      = new_d_Shl(dbgi, load_res, countl, amode);
 
        unsigned   shift_bitsr = bitoffset + shift_bitsl;
-       assert(shift_bitsr <= res_size);
+       assert(shift_bitsr <= amode_size);
        ir_tarval *tvr         = new_tarval_from_long((long)shift_bitsr, mode_uint);
        ir_node   *countr      = new_d_Const(dbgi, tvr);
        ir_node   *shiftr;
        if (mode_is_signed(mode)) {
-               shiftr = new_d_Shrs(dbgi, shiftl, countr, resmode);
+               shiftr = new_d_Shrs(dbgi, shiftl, countr, amode);
        } else {
-               shiftr = new_d_Shr(dbgi, shiftl, countr, resmode);
+               shiftr = new_d_Shr(dbgi, shiftl, countr, amode);
        }
 
+       type_t  *type    = expression->base.type;
+       ir_mode *resmode = get_ir_mode_arithmetic(type);
        return create_conv(dbgi, shiftr, resmode);
 }
 
index 56d47d6..7c851d4 100644 (file)
@@ -218,14 +218,5 @@ void create_microsoft_intrinsics(void)
        MS_BUILTIN(_BitScanReverse,        make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
        MS_BUILTIN(_InterlockedExchange,   make_function_2_type(type_long, type_long_ptr, type_long));
        MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64));
-
-       if (machine_size <= 32) {
-               MS_BUILTIN(__readeflags,           make_function_0_type(type_unsigned_int));
-               MS_BUILTIN(__writeeflags,          make_function_1_type(type_void, type_unsigned_int));
-       } else {
-               MS_BUILTIN(__readeflags,           make_function_0_type(type_unsigned_int64));
-               MS_BUILTIN(__writeeflags,          make_function_1_type(type_void, type_unsigned_int64));
-       }
-
 #undef MS_BUILTIN
 }
index 0db7cb7..5dc670e 100644 (file)
@@ -98,9 +98,7 @@ typedef enum builtin_kind_t {
        bk_ms__outdword,
        bk_ms__outword,
        bk_ms__popcount,
-       bk_ms__readeflags,
        bk_ms__ud2,
-       bk_ms__writeeflags,
        bk_ms_byteswap_uint64,
        bk_ms_byteswap_ulong,
        bk_ms_byteswap_ushort,
index 95e8a3f..cbcfad2 100644 (file)
@@ -37,25 +37,18 @@ typedef enum lang_features_t {
 /** the current C mode/dialect */
 extern unsigned int c_mode;
 
-/** the 'machine size', 16, 32 or 64 bit */
-extern unsigned int machine_size;
+/**
+ * whether architecture shift instructions usually perform modulo bit_size
+ * on the shift amount, if yes this equals to the machine_size.
+ */
+extern unsigned int architecture_modulo_shift;
 
 /** byte-order: true = big-endian, false = little-endian */
 extern bool byte_order_big_endian;
 
-/** true if the char type is signed */
-extern bool char_is_signed;
-
 /** true for strict language checking. */
 extern bool strict_mode;
 
-/** atomic type of wchar_t */
-extern atomic_type_kind_t wchar_atomic_kind;
-
-/** size of long double in bits (this is the size stored to memory, not
- * necessary the precision of the arithmetic) */
-extern unsigned long_double_size;
-
 /** a hack that adds a call to __main into the main function, necessary on
  * mingw */
 extern bool enable_main_collect2_hack;
diff --git a/main.c b/main.c
index dc75056..916f84e 100644 (file)
--- a/main.c
+++ b/main.c
 #define ASSEMBLER "gcc -c -xassembler"
 #endif
 
-unsigned int       c_mode                    = _C89 | _ANSI | _C99 | _GNUC;
-unsigned int       machine_size              = 32;
-bool               byte_order_big_endian     = false;
-bool               char_is_signed            = true;
-bool               strict_mode               = false;
-atomic_type_kind_t wchar_atomic_kind         = ATOMIC_TYPE_INT;
-unsigned           long_double_size          = 0;
-bool               enable_main_collect2_hack = false;
-bool               freestanding              = false;
+unsigned int        c_mode                    = _C89 | _ANSI | _C99 | _GNUC;
+bool                byte_order_big_endian     = false;
+bool                strict_mode               = false;
+bool                enable_main_collect2_hack = false;
+bool                freestanding              = false;
+unsigned            architecture_modulo_shift = 0;
+
+static bool               char_is_signed      = true;
+static atomic_type_kind_t wchar_atomic_kind   = ATOMIC_TYPE_INT;
 
 static machine_triple_t *target_machine;
 static const char       *target_triple;
@@ -798,6 +798,22 @@ static filetype_t get_filetype_from_string(const char *string)
        return FILETYPE_UNKNOWN;
 }
 
+static bool is_windows_os(const char *os)
+{
+       return strstr(os, "mingw") != NULL || streq(os, "win32");
+}
+
+static bool is_unixish_os(const char *os)
+{
+       return strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
+              || streq(os, "solaris");
+}
+
+static bool is_darwin_os(const char *os)
+{
+       return streq(os, "darwin");
+}
+
 static bool init_os_support(void)
 {
        const char *os = target_machine->operating_system;
@@ -805,14 +821,12 @@ static bool init_os_support(void)
        enable_main_collect2_hack = false;
        define_intmax_types       = false;
 
-       if (strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
-                       || streq(os, "solaris")) {
+       if (is_unixish_os(os)) {
                set_create_ld_ident(create_name_linux_elf);
-       } else if (streq(os, "darwin")) {
-               long_double_size = 16;
+       } else if (is_darwin_os(os)) {
                set_create_ld_ident(create_name_macho);
                define_intmax_types = true;
-       } else if (strstr(os, "mingw") != NULL || streq(os, "win32")) {
+       } else if (is_windows_os(os)) {
                wchar_atomic_kind         = ATOMIC_TYPE_USHORT;
                enable_main_collect2_hack = true;
                set_create_ld_ident(create_name_win32);
@@ -834,22 +848,137 @@ static bool parse_target_triple(const char *arg)
        return true;
 }
 
+static unsigned decide_modulo_shift(unsigned type_size)
+{
+       if (architecture_modulo_shift == 0)
+               return 0;
+       if (type_size < architecture_modulo_shift)
+               return architecture_modulo_shift;
+       return type_size;
+}
+
 static void setup_target_machine(void)
 {
        if (!setup_firm_for_machine(target_machine))
                exit(1);
 
+       init_os_support();
+}
+
+/**
+ * initialize cparser type properties based on a firm type
+ */
+static void set_typeprops_type(atomic_type_properties_t* props, ir_type *type)
+{
+       props->size             = get_type_size_bytes(type);
+       props->alignment        = get_type_alignment_bytes(type);
+       props->struct_alignment = props->alignment;
+}
+
+static void init_types_and_adjust(void)
+{
        const backend_params *be_params = be_get_backend_param();
-       if (be_params->long_double_size % 8 != 0) {
-               fprintf(stderr, "firm-target long double size is not a multiple of 8, cannot handle this\n");
-               exit(1);
+       unsigned machine_size = be_params->machine_size;
+       init_types(machine_size);
+
+       atomic_type_properties_t *props = atomic_type_properties;
+
+       /* adjust types as requested by target architecture */
+       ir_type *type_long_double = be_params->type_long_double;
+       if (type_long_double != NULL)
+               set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_long_double);
+
+       ir_type *type_long_long = be_params->type_long_long;
+       if (type_long_long != NULL)
+               set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_long_long);
+
+       ir_type *type_unsigned_long_long = be_params->type_unsigned_long_long;
+       if (type_long_long != NULL)
+               set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_unsigned_long_long);
+
+       /* operating system ABI specifics */
+       const char *os = target_machine->operating_system;
+       if (is_darwin_os(os)) {
+               if (machine_size == 32) {
+                       props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
+                       props[ATOMIC_TYPE_LONG_DOUBLE].size        = 16;
+                       props[ATOMIC_TYPE_LONG_DOUBLE].alignment   = 16;
+               }
+       } else if (is_windows_os(os)) {
+               if (machine_size == 64) {
+                       /* to ease porting of old c-code microsoft decided to use 32bits
+                        * even for long */
+                       props[ATOMIC_TYPE_LONG]  = props[ATOMIC_TYPE_INT];
+                       props[ATOMIC_TYPE_ULONG] = props[ATOMIC_TYPE_UINT];
+               }
+
+               /* on windows long double is not supported */
+               props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
+       } else if (is_unixish_os(os)) {
+               if (machine_size == 32) {
+                       /* System V has a broken alignment for double so we have to add
+                        * a hack here */
+                       props[ATOMIC_TYPE_DOUBLE].struct_alignment    = 4;
+                       props[ATOMIC_TYPE_LONGLONG].struct_alignment  = 4;
+                       props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
+               }
        }
 
-       byte_order_big_endian = be_params->byte_order_big_endian;
-       machine_size          = be_params->machine_size;
-       long_double_size      = be_params->long_double_size / 8;
+       /* stuff decided after processing operating system specifics and
+        * commandline flags */
+       props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
+       if (char_is_signed) {
+               props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
+       } else {
+               props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
+       }
 
-       init_os_support();
+       /* initialize defaults for unsupported types */
+       if (type_long_long == NULL) {
+               props[ATOMIC_TYPE_LONGLONG] = props[ATOMIC_TYPE_LONG];
+       }
+       if (type_long_double == NULL) {
+               props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
+       }
+       if (type_unsigned_long_long == NULL) {
+               props[ATOMIC_TYPE_ULONGLONG] = props[ATOMIC_TYPE_ULONG];
+       }
+
+       /* initialize firm pointer modes */
+       char               name[64];
+       ir_mode_sort       sort         = irms_reference;
+       unsigned           bit_size     = machine_size;
+       bool               is_signed    = 0;
+       ir_mode_arithmetic arithmetic   = irma_twos_complement;
+       unsigned           modulo_shift = decide_modulo_shift(bit_size);
+
+       snprintf(name, sizeof(name), "p%u", machine_size);
+       ir_mode *ptr_mode = new_ir_mode(name, sort, bit_size, is_signed, arithmetic,
+                                       modulo_shift);
+
+       if (machine_size == 16) {
+               set_reference_mode_signed_eq(ptr_mode, mode_Hs);
+               set_reference_mode_unsigned_eq(ptr_mode, mode_Hu);
+       } else if (machine_size == 32) {
+               set_reference_mode_signed_eq(ptr_mode, mode_Is);
+               set_reference_mode_unsigned_eq(ptr_mode, mode_Iu);
+       } else if (machine_size == 64) {
+               set_reference_mode_signed_eq(ptr_mode, mode_Ls);
+               set_reference_mode_unsigned_eq(ptr_mode, mode_Lu);
+       } else {
+               panic("strange machine_size when determining pointer modes");
+       }
+
+       /* Hmm, pointers should be machine size */
+       set_modeP_data(ptr_mode);
+       set_modeP_code(ptr_mode);
+
+       byte_order_big_endian = be_params->byte_order_big_endian;
+       if (be_params->modulo_shift_efficient) {
+               architecture_modulo_shift = machine_size;
+       } else {
+               architecture_modulo_shift = 0;
+       }
 }
 
 int main(int argc, char **argv)
@@ -1243,10 +1372,11 @@ int main(int argc, char **argv)
                                                fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
                                                argument_errors = true;
                                        } else {
+                                               unsigned machine_size = (unsigned)value;
+                                               /* TODO: choose/change backend based on this */
                                                add_flag(&cppflags_obst, "-m%u", machine_size);
                                                add_flag(&asflags_obst, "-m%u", machine_size);
                                                add_flag(&ldflags_obst, "-m%u", machine_size);
-                                               /* TODO: choose/change backend based on this */
                                        }
                                }
                        } else if (streq(option, "pg")) {
@@ -1451,9 +1581,15 @@ int main(int argc, char **argv)
 
        gen_firm_init();
        init_symbol_table();
-       init_types();
+       init_types_and_adjust();
        init_typehash();
        init_basic_types();
+       if (wchar_atomic_kind == ATOMIC_TYPE_INT)
+               init_wchar_types(type_int);
+       else if (wchar_atomic_kind == ATOMIC_TYPE_SHORT)
+               init_wchar_types(type_short);
+       else
+               panic("unexpected wchar type");
        init_lexer();
        init_ast();
        init_parser();
index 0f40e75..68e36c3 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -8904,7 +8904,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                                size  = get_atomic_type_size(akind);
                                        } else {
                                                flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                               size  = get_atomic_type_size(get_intptr_kind());
+                                               size  = get_type_size(type_void_ptr);
                                        }
 
                                        do {
@@ -8920,7 +8920,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                                        value_size  = get_atomic_type_size(value_akind);
                                                } else if (value_kind == TYPE_POINTER) {
                                                        value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                                       value_size  = get_atomic_type_size(get_intptr_kind());
+                                                       value_size  = get_type_size(type_void_ptr);
                                                } else {
                                                        break;
                                                }
diff --git a/type.c b/type.c
index 3ca2071..c2484b8 100644 (file)
--- a/type.c
+++ b/type.c
@@ -43,13 +43,6 @@ static bool           print_implicit_array_size = false;
 static void intern_print_type_pre(const type_t *type);
 static void intern_print_type_post(const type_t *type);
 
-typedef struct atomic_type_properties_t atomic_type_properties_t;
-struct atomic_type_properties_t {
-       unsigned   size;              /**< type size in bytes */
-       unsigned   alignment;         /**< type alignment in bytes */
-       unsigned   flags;             /**< type flags from atomic_type_flag_t */
-};
-
 /**
  * Returns the size of a type node.
  *
@@ -90,35 +83,32 @@ type_t *allocate_type_zero(type_kind_t kind)
 /**
  * Properties of atomic types.
  */
-static atomic_type_properties_t atomic_type_properties[ATOMIC_TYPE_LAST+1] = {
-       //ATOMIC_TYPE_INVALID = 0,
+atomic_type_properties_t atomic_type_properties[ATOMIC_TYPE_LAST+1] = {
        [ATOMIC_TYPE_VOID] = {
-               .size       = 0,
-               .alignment  = 0,
-               .flags      = ATOMIC_TYPE_FLAG_NONE
+               .size      = 0,
+               .alignment = 0,
+               .flags     = ATOMIC_TYPE_FLAG_NONE
        },
        [ATOMIC_TYPE_WCHAR_T] = {
-               .size       = (unsigned)-1,
-               .alignment  = (unsigned)-1,
-               /* signed flag will be set when known */
-               .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
+               .size      = (unsigned)-1,
+               .alignment = (unsigned)-1,
+               .flags     = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
        },
        [ATOMIC_TYPE_CHAR] = {
-               .size       = 1,
-               .alignment  = 1,
-               /* signed flag will be set when known */
-               .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
+               .size      = 1,
+               .alignment = 1,
+               .flags     = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
        },
        [ATOMIC_TYPE_SCHAR] = {
-               .size       = 1,
-               .alignment  = 1,
-               .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC
-                             | ATOMIC_TYPE_FLAG_SIGNED,
+               .size      = 1,
+               .alignment = 1,
+               .flags     = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC
+                          | ATOMIC_TYPE_FLAG_SIGNED,
        },
        [ATOMIC_TYPE_UCHAR] = {
-               .size       = 1,
-               .alignment  = 1,
-               .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
+               .size      = 1,
+               .alignment = 1,
+               .flags     = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
        },
        [ATOMIC_TYPE_SHORT] = {
                .size       = 2,
@@ -153,41 +143,28 @@ static atomic_type_properties_t atomic_type_properties[ATOMIC_TYPE_LAST+1] = {
                .alignment  = (unsigned) -1,
                .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
        },
-       [ATOMIC_TYPE_LONGLONG] = {
-               .size       = (unsigned) -1,
-               .alignment  = (unsigned) -1,
-               .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC
-                             | ATOMIC_TYPE_FLAG_SIGNED,
-       },
-       [ATOMIC_TYPE_ULONGLONG] = {
-               .size       = (unsigned) -1,
-               .alignment  = (unsigned) -1,
-               .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
-       },
        [ATOMIC_TYPE_BOOL] = {
-               .size       = (unsigned) -1,
-               .alignment  = (unsigned) -1,
+               .size       = 1,
+               .alignment  = 1,
                .flags      = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC,
        },
        [ATOMIC_TYPE_FLOAT] = {
                .size       = 4,
-               .alignment  = (unsigned) -1,
+               .alignment  = 4,
                .flags      = ATOMIC_TYPE_FLAG_FLOAT | ATOMIC_TYPE_FLAG_ARITHMETIC
                              | ATOMIC_TYPE_FLAG_SIGNED,
        },
        [ATOMIC_TYPE_DOUBLE] = {
                .size       = 8,
-               .alignment  = (unsigned) -1,
-               .flags      = ATOMIC_TYPE_FLAG_FLOAT | ATOMIC_TYPE_FLAG_ARITHMETIC
-                             | ATOMIC_TYPE_FLAG_SIGNED,
-       },
-       [ATOMIC_TYPE_LONG_DOUBLE] = {
-               .size       = (unsigned) -1, /* will be filled in later */
-               .alignment  = (unsigned) -1,
+               .alignment  = 8,
                .flags      = ATOMIC_TYPE_FLAG_FLOAT | ATOMIC_TYPE_FLAG_ARITHMETIC
                              | ATOMIC_TYPE_FLAG_SIGNED,
        },
-       /* complex and imaginary types are set in init_types */
+};
+atomic_type_properties_t pointer_properties = {
+       .size      = 4,
+       .alignment = 4,
+       .flags     = ATOMIC_TYPE_FLAG_NONE,
 };
 
 static inline bool is_po2(unsigned x)
@@ -195,64 +172,41 @@ static inline bool is_po2(unsigned x)
        return (x & (x-1)) == 0;
 }
 
-void init_types(void)
+void init_types(unsigned machine_size)
 {
        obstack_init(&type_obst);
 
        atomic_type_properties_t *props = atomic_type_properties;
 
-       if (char_is_signed) {
-               props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
-       }
+       /* atempt to set some sane defaults based on machine size */
 
        unsigned int_size   = machine_size < 32 ? 2 : 4;
-       /* long is always 32bit on windows */
-       unsigned long_size  = c_mode & _MS ? 4 : (machine_size < 64 ? 4 : 8);
-       unsigned llong_size = machine_size < 32 ? 4 : 8;
-
-       props[ATOMIC_TYPE_INT].size            = int_size;
-       props[ATOMIC_TYPE_INT].alignment       = int_size;
-       props[ATOMIC_TYPE_UINT].size           = int_size;
-       props[ATOMIC_TYPE_UINT].alignment      = int_size;
-       props[ATOMIC_TYPE_LONG].size           = long_size;
-       props[ATOMIC_TYPE_LONG].alignment      = long_size;
-       props[ATOMIC_TYPE_ULONG].size          = long_size;
-       props[ATOMIC_TYPE_ULONG].alignment     = long_size;
-       props[ATOMIC_TYPE_LONGLONG].size       = llong_size;
-       props[ATOMIC_TYPE_LONGLONG].alignment  = llong_size;
-       props[ATOMIC_TYPE_ULONGLONG].size      = llong_size;
-       props[ATOMIC_TYPE_ULONGLONG].alignment = llong_size;
-
-       /* TODO: backend specific, need a way to query the backend for this.
-        * The following are good settings for x86 */
-       if (machine_size <= 32) {
-               props[ATOMIC_TYPE_FLOAT].alignment       = 4;
-               props[ATOMIC_TYPE_DOUBLE].alignment      = 4;
-               props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 4;
-               props[ATOMIC_TYPE_LONGLONG].alignment    = 4;
-               props[ATOMIC_TYPE_ULONGLONG].alignment   = 4;
-       } else {
-               props[ATOMIC_TYPE_FLOAT].alignment       = 4;
-               props[ATOMIC_TYPE_DOUBLE].alignment      = 8;
-               props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 8;
-               props[ATOMIC_TYPE_LONGLONG].alignment    = 8;
-               props[ATOMIC_TYPE_ULONGLONG].alignment   = 8;
+       unsigned long_size  = machine_size < 64 ? 4 : 8;
+
+       props[ATOMIC_TYPE_INT].size        = int_size;
+       props[ATOMIC_TYPE_INT].alignment   = int_size;
+       props[ATOMIC_TYPE_UINT].size       = int_size;
+       props[ATOMIC_TYPE_UINT].alignment  = int_size;
+       props[ATOMIC_TYPE_LONG].size       = long_size;
+       props[ATOMIC_TYPE_LONG].alignment  = long_size;
+       props[ATOMIC_TYPE_ULONG].size      = long_size;
+       props[ATOMIC_TYPE_ULONG].alignment = long_size;
+
+       pointer_properties.size             = long_size;
+       pointer_properties.alignment        = long_size;
+       pointer_properties.struct_alignment = long_size;
+
+       props[ATOMIC_TYPE_LONGLONG]    = props[ATOMIC_TYPE_LONG];
+       props[ATOMIC_TYPE_ULONGLONG]   = props[ATOMIC_TYPE_ULONG];
+       props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
+       props[ATOMIC_TYPE_WCHAR_T]     = props[ATOMIC_TYPE_INT];
+
+       /* set struct alignments to the same value as alignment */
+       for (size_t i = 0;
+            i < sizeof(atomic_type_properties)/sizeof(atomic_type_properties[0]);
+            ++i) {
+               props[i].struct_alignment = props[i].alignment;
        }
-
-       if (long_double_size > 0) {
-               props[ATOMIC_TYPE_LONG_DOUBLE].size      = long_double_size;
-               if (is_po2(long_double_size)) {
-                       props[ATOMIC_TYPE_LONG_DOUBLE].alignment = long_double_size;
-               }
-       } else {
-               props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
-       }
-
-       /* TODO: make this configurable for platforms which do not use byte sized
-        * bools. */
-       props[ATOMIC_TYPE_BOOL] = props[ATOMIC_TYPE_UCHAR];
-
-       props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
 }
 
 void exit_types(void)
@@ -1183,7 +1137,6 @@ bool types_compatible(const type_t *type1, const type_t *type2)
                panic("typerefs not skipped in compatible types?!?");
        }
 
-       /* TODO: incomplete */
        return false;
 }
 
@@ -1264,8 +1217,7 @@ unsigned get_type_size(type_t *type)
                return 0; /* non-const (but "address-const") */
        case TYPE_REFERENCE:
        case TYPE_POINTER:
-               /* TODO: make configurable by backend */
-               return 4;
+               return pointer_properties.size;
        case TYPE_ARRAY: {
                /* TODO: correct if element_type is aligned? */
                il_size_t element_size = get_type_size(type->array.element_type);
@@ -1305,12 +1257,11 @@ unsigned get_type_alignment(type_t *type)
        case TYPE_ENUM:
                return get_atomic_type_alignment(type->enumt.akind);
        case TYPE_FUNCTION:
-               /* what is correct here? */
-               return 4;
+               /* gcc says 1 here... */
+               return 1;
        case TYPE_REFERENCE:
        case TYPE_POINTER:
-               /* TODO: make configurable by backend */
-               return 4;
+               return pointer_properties.alignment;
        case TYPE_ARRAY:
                return get_type_alignment(type->array.element_type);
        case TYPE_TYPEDEF: {
@@ -1331,6 +1282,13 @@ unsigned get_type_alignment(type_t *type)
        panic("invalid type in get_type_alignment");
 }
 
+unsigned get_type_alignment_compound(type_t *type)
+{
+       if (type->kind == TYPE_ATOMIC)
+               return atomic_type_properties[type->atomic.akind].struct_alignment;
+       return get_type_alignment(type);
+}
+
 decl_modifiers_t get_type_modifiers(const type_t *type)
 {
        switch(type->kind) {
@@ -1416,26 +1374,6 @@ unsigned get_atomic_type_flags(atomic_type_kind_t kind)
        return atomic_type_properties[kind].flags;
 }
 
-atomic_type_kind_t get_intptr_kind(void)
-{
-       if (machine_size <= 32)
-               return ATOMIC_TYPE_INT;
-       else if (machine_size <= 64)
-               return ATOMIC_TYPE_LONG;
-       else
-               return ATOMIC_TYPE_LONGLONG;
-}
-
-atomic_type_kind_t get_uintptr_kind(void)
-{
-       if (machine_size <= 32)
-               return ATOMIC_TYPE_UINT;
-       else if (machine_size <= 64)
-               return ATOMIC_TYPE_ULONG;
-       else
-               return ATOMIC_TYPE_ULONGLONG;
-}
-
 /**
  * Find the atomic type kind representing a given size (signed).
  */
@@ -1627,7 +1565,7 @@ static entity_t *pack_bitfield_members(il_size_t *struct_offset,
                        break;
 
                type_t *base_type = member->declaration.type;
-               il_alignment_t base_alignment = get_type_alignment(base_type);
+               il_alignment_t base_alignment = get_type_alignment_compound(base_type);
                il_alignment_t alignment_mask = base_alignment-1;
                if (base_alignment > alignment)
                        alignment = base_alignment;
@@ -1701,7 +1639,7 @@ void layout_struct_type(compound_type_t *type)
                        continue;
                }
 
-               il_alignment_t m_alignment = get_type_alignment(m_type);
+               il_alignment_t m_alignment = get_type_alignment_compound(m_type);
                if (m_alignment > alignment)
                        alignment = m_alignment;
 
@@ -1764,7 +1702,7 @@ void layout_union_type(compound_type_t *type)
                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);
+               il_alignment_t m_alignment = get_type_alignment_compound(m_type);
                if (m_alignment > alignment)
                        alignment = m_alignment;
        }
diff --git a/type.h b/type.h
index 1f84787..41bbada 100644 (file)
--- a/type.h
+++ b/type.h
@@ -94,7 +94,14 @@ typedef struct bitfield_type_t       bitfield_type_t;
 typedef struct typeof_type_t         typeof_type_t;
 typedef union  type_t                type_t;
 
-void init_types(void);
+/**
+ * Initializes the type system. Attempts to set some defaults on the atomic
+ * types based on a given machine size.
+ * These type properties are not final but you should adapt them to your system
+ * as your architecture and operating systems application binary interface (ABI)
+ * requires.
+ */
+void init_types(unsigned machine_size);
 void exit_types(void);
 
 void print_type(const type_t *type);
@@ -192,14 +199,18 @@ unsigned         get_type_alignment(type_t *type);
 unsigned         get_type_size(type_t *type);
 decl_modifiers_t get_type_modifiers(const type_t *type);
 
+/**
+ * get alignment of a type when used inside a compound.
+ * Some ABIs are broken and alignment inside a compound is different from
+ * recommended alignment of a type
+ */
+unsigned         get_type_alignment_compound(type_t *type);
+
 /**
  * returns flags of an atomic type kind
  */
 unsigned get_atomic_type_flags(atomic_type_kind_t kind);
 
-atomic_type_kind_t get_intptr_kind(void);
-atomic_type_kind_t get_uintptr_kind(void);
-
 /**
  * Find the atomic type kind representing a given size (signed).
  */
index f1e2332..1d3ab4c 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -182,6 +182,22 @@ union type_t {
        typeof_type_t    typeoft;
 };
 
+typedef struct atomic_type_properties_t atomic_type_properties_t;
+struct atomic_type_properties_t {
+       unsigned   size;              /**< type size in bytes */
+       unsigned   alignment;         /**< type alignment in bytes */
+       /** some ABIs are broken and require an alignment different from the
+        * recommended/best alignment inside structs. Fixing ABIs is difficult
+        * so people rather stick with the wrong values for compatibility.
+        * (double type on x86 System V ABI)
+        */
+       unsigned   struct_alignment;
+       unsigned   flags;             /**< type flags from atomic_type_flag_t */
+};
+
+extern atomic_type_properties_t atomic_type_properties[ATOMIC_TYPE_LAST+1];
+extern atomic_type_properties_t pointer_properties;
+
 /** The default calling convention for functions. */
 extern cc_kind_t default_calling_convention;
 
diff --git a/types.c b/types.c
index a9ef574..ab6e423 100644 (file)
--- a/types.c
+++ b/types.c
@@ -178,14 +178,19 @@ void init_basic_types(void)
        type_ptrdiff_t   = type_long;
        type_uintmax_t   = type_unsigned_long_long;
        type_uptrdiff_t  = type_unsigned_long;
-       type_wchar_t     = make_atomic_type(wchar_atomic_kind, TYPE_QUALIFIER_NONE);
        type_wint_t      = type_int;
-       type_const_wchar_t
-               = make_atomic_type(wchar_atomic_kind, TYPE_QUALIFIER_CONST);
 
        type_intmax_t_ptr  = make_pointer_type(type_intmax_t,  TYPE_QUALIFIER_NONE);
        type_ptrdiff_t_ptr = make_pointer_type(type_ptrdiff_t, TYPE_QUALIFIER_NONE);
        type_ssize_t_ptr   = make_pointer_type(type_ssize_t,   TYPE_QUALIFIER_NONE);
+}
+
+void init_wchar_types(type_t *base)
+{
+       assert(base->kind == TYPE_ATOMIC);
+       type_wchar_t = base;
+       type_const_wchar_t
+               = make_atomic_type(base->atomic.akind, TYPE_QUALIFIER_CONST);
        type_wchar_t_ptr   = make_pointer_type(type_wchar_t,   TYPE_QUALIFIER_NONE);
        type_const_wchar_t_ptr
                = make_pointer_type(type_const_wchar_t, TYPE_QUALIFIER_NONE);
diff --git a/types.h b/types.h
index cb03f88..282a067 100644 (file)
--- a/types.h
+++ b/types.h
@@ -104,6 +104,6 @@ extern type_t *type_unsigned_int64;
 extern type_t *type_unsigned_int128;
 
 void init_basic_types(void);
-void init_builtin_types(void);
+void init_wchar_types(type_t *base);
 
 #endif