+static void copy_file(FILE *dest, FILE *input)
+{
+ char buf[16384];
+
+ while (!feof(input) && !ferror(dest)) {
+ size_t read = fread(buf, 1, sizeof(buf), input);
+ if (fwrite(buf, 1, read, dest) != read) {
+ perror("could not write output");
+ }
+ }
+}
+
+static FILE *open_file(const char *filename)
+{
+ if (streq(filename, "-")) {
+ return stdin;
+ }
+
+ FILE *in = fopen(filename, "r");
+ if (in == NULL) {
+ fprintf(stderr, "Could not open '%s': %s\n", filename,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ return in;
+}
+
+static filetype_t get_filetype_from_string(const char *string)
+{
+ if (streq(string, "c") || streq(string, "c-header"))
+ return FILETYPE_C;
+ if (streq(string, "c++") || streq(string, "c++-header"))
+ return FILETYPE_CXX;
+ if (streq(string, "assembler"))
+ return FILETYPE_PREPROCESSED_ASSEMBLER;
+ if (streq(string, "assembler-with-cpp"))
+ return FILETYPE_ASSEMBLER;
+ if (streq(string, "none"))
+ return FILETYPE_AUTODETECT;
+
+ return FILETYPE_UNKNOWN;
+}
+
+static bool init_os_support(void)
+{
+ wchar_atomic_kind = ATOMIC_TYPE_INT;
+ enable_main_collect2_hack = false;
+ define_intmax_types = false;
+
+ if (firm_is_unixish_os(target_machine)) {
+ set_create_ld_ident(create_name_linux_elf);
+ } else if (firm_is_darwin_os(target_machine)) {
+ set_create_ld_ident(create_name_macho);
+ define_intmax_types = true;
+ } else if (firm_is_windows_os(target_machine)) {
+ wchar_atomic_kind = ATOMIC_TYPE_USHORT;
+ enable_main_collect2_hack = true;
+ set_create_ld_ident(create_name_win32);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_target_triple(const char *arg)
+{
+ machine_triple_t *triple = firm_parse_machine_triple(arg);
+ if (triple == NULL) {
+ fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
+ return false;
+ }
+ target_machine = triple;
+ 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 bool is_ia32_cpu(const char *architecture)
+{
+ return streq(architecture, "i386")
+ || streq(architecture, "i486")
+ || streq(architecture, "i586")
+ || streq(architecture, "i686")
+ || streq(architecture, "i786");
+}
+
+static const char *setup_isa_from_tripel(const machine_triple_t *machine)
+{
+ const char *cpu = machine->cpu_type;
+
+ if (is_ia32_cpu(cpu)) {
+ return "ia32";
+ } else if (streq(cpu, "x86_64")) {
+ return "amd64";
+ } else if (streq(cpu, "sparc")) {
+ return "sparc";
+ } else if (streq(cpu, "arm")) {
+ return "arm";
+ } else {
+ fprintf(stderr, "Unknown cpu '%s' in target-triple\n", cpu);
+ return NULL;
+ }
+}
+
+static const char *setup_target_machine(void)
+{
+ if (!setup_firm_for_machine(target_machine))
+ exit(1);
+
+ const char *isa = setup_isa_from_tripel(target_machine);
+
+ if (isa == NULL)
+ exit(1);
+
+ init_os_support();
+
+ return isa;
+}
+
+/**
+ * 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;
+}
+
+/**
+ * Copy atomic type properties except the integer conversion rank
+ */
+static void copy_typeprops(atomic_type_properties_t *dest,
+ const atomic_type_properties_t *src)
+{
+ dest->size = src->size;
+ dest->alignment = src->alignment;
+ dest->struct_alignment = src->struct_alignment;
+ dest->flags = src->flags;
+}
+
+static void init_types_and_adjust(void)
+{
+ const backend_params *be_params = be_get_backend_param();
+ 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);
+ atomic_modes[ATOMIC_TYPE_LONG_DOUBLE] = get_type_mode(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_unsigned_long_long != NULL)
+ set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_unsigned_long_long);
+
+ /* operating system ABI specifics */
+ if (firm_is_darwin_os(target_machine)) {
+ if (machine_size == 32) {
+ props[ATOMIC_TYPE_LONGLONG].struct_alignment = 4;
+ props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
+ props[ATOMIC_TYPE_LONG_DOUBLE].size = 16;
+ props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 16;
+ props[ATOMIC_TYPE_LONG_DOUBLE].struct_alignment = 16;
+ }
+ } else if (firm_is_windows_os(target_machine)) {
+ 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 (firm_is_unixish_os(target_machine)) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
+ /* 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;
+ }
+ }
+
+ /* stuff decided after processing operating system specifics and
+ * commandline flags */
+ if (char_is_signed) {
+ props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
+ } else {
+ props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
+ }
+ /* copy over wchar_t properties (including rank) */
+ props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
+
+ /* initialize defaults for unsupported types */
+ if (type_long_long == NULL) {
+ copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
+ }
+ if (type_unsigned_long_long == NULL) {
+ copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
+ &props[ATOMIC_TYPE_ULONG]);
+ }
+ if (type_long_double == NULL) {
+ copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
+ &props[ATOMIC_TYPE_DOUBLE]);
+ }
+
+ /* initialize firm pointer modes */
+ char name[64];
+ unsigned bit_size = machine_size;
+ unsigned modulo_shift = decide_modulo_shift(bit_size);
+
+ snprintf(name, sizeof(name), "p%u", machine_size);
+ ir_mode *ptr_mode = new_reference_mode(name, irma_twos_complement, bit_size, 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;
+ }
+}
+