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;
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);
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) {
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);
/* 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)
}
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 {
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);
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);
}
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
}
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,
/** 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;
#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;
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;
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);
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)
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")) {
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();
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 {
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;
}
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.
*
/**
* 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,
.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)
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)
panic("typerefs not skipped in compatible types?!?");
}
- /* TODO: incomplete */
return false;
}
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);
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: {
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) {
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).
*/
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;
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;
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;
}
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);
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).
*/
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;
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);
extern type_t *type_unsigned_int128;
void init_basic_types(void);
-void init_builtin_types(void);
+void init_wchar_types(type_t *base);
#endif