summaryrefslogtreecommitdiffhomepage
path: root/ir/be/platform.c
diff options
context:
space:
mode:
authorMatthias Braun <matze@braunis.de>2017-01-04 20:12:21 +0100
committerMatthias Braun <matze@braunis.de>2017-02-20 04:48:18 +0100
commit1ffc842f8bb13ed098eeaf2382ba473f9e154466 (patch)
treecd4c1c9ca57400975db74b7212ac237166359704 /ir/be/platform.c
parent845e655dac11bc5eba82b9fc6d36a6f4fec23eb6 (diff)
Rework target initialization and query
- Moves machine triple handling code form cparser into libfirm - Create new APIs to set the target and query information about it - Move backend_params into the new target API - Backends initialize ir_target instead of backend_params now - Add new API to get information about the target platform: - Mangle a name for the target platform (and remove compilerlib mangling callback) - Can query size and alignment of basic C types for the platform - Move some constant target information into arch_isa_if_t (we move it to target_info_t later when we realize it needs to be dynamic) - Redo backend initialization. Examples: Simple case: Initialize for host: ir_init(); Complex case: cross-compile to sparc with PIC enabled: ir_init_library(); ir_target_set("sparc-leon-linux-gnu"); ir_target_option("pic"); ir_target_init();
Diffstat (limited to 'ir/be/platform.c')
-rw-r--r--ir/be/platform.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/ir/be/platform.c b/ir/be/platform.c
new file mode 100644
index 0000000..b7f4586
--- /dev/null
+++ b/ir/be/platform.c
@@ -0,0 +1,479 @@
+/*
+ * This file is part of libFirm.
+ * Copyright (C) 2017 University of Karlsruhe.
+ */
+#include "platform_t.h"
+
+#include "be_t.h"
+#include "bearch.h"
+#include "bediagnostic.h"
+#include "ident_t.h"
+#include "irtools.h"
+#include "lc_opts.h"
+#include "panic.h"
+#include "target_t.h"
+#include "util.h"
+#include "xmalloc.h"
+#include <assert.h>
+
+static bool option_pic;
+static bool option_pic_noplt;
+
+struct ir_platform_define_t {
+ char const *name;
+ char const *value;
+ ir_platform_define_t *next;
+};
+
+platform_t ir_platform;
+
+static void init_lc_opts(void)
+{
+ static const lc_opt_table_entry_t platform_options[] = {
+ LC_OPT_ENT_BOOL("pic", "Generate position independent code",
+ &option_pic),
+ LC_OPT_ENT_BOOL("noplt", "Avoid using PLT in PIC code",
+ &option_pic_noplt),
+ LC_OPT_LAST
+ };
+ lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
+ lc_opt_add_table(be_grp, platform_options);
+}
+
+
+/** Add a target specific preprocessor define. */
+static void ppdef(const char *name, const char *value)
+{
+ ir_platform_define_t *define = XMALLOCZ(ir_platform_define_t);
+ define->name = name;
+ define->value = value;
+ define->next = ir_platform.defines;
+ ir_platform.defines = define;
+}
+
+static void ppdef1(const char *name)
+{
+ ppdef(name, "1");
+}
+
+static void ppdef_unix(void)
+{
+ ppdef1("__unix");
+ ppdef1("__unix__");
+ ppdef1("unix");
+}
+
+void ir_platform_set(ir_machine_triple_t const *machine,
+ unsigned const pointer_size)
+{
+ memset(&ir_platform, 0, sizeof(ir_platform));
+ assert(pointer_size >= 4 && "TODO: smaller sizes");
+ ir_platform.int_size = 4;
+ ir_platform.long_size = MIN(pointer_size, 8);
+ ir_platform.intptr_type = IR_TYPE_LONG;
+ ir_platform.wchar_is_signed = true;
+ ir_platform.wchar_type = IR_TYPE_INT;
+ ir_platform.ia32_po2_stackalign = 2;
+
+ const char *const cpu = ir_triple_get_cpu_type(machine);
+ const char *const manufacturer = ir_triple_get_manufacturer(machine);
+ const char *const os = ir_triple_get_operating_system(machine);
+ if (ir_is_cpu_x86_32(cpu)) {
+ ir_platform.supports_thread_local_storage = true;
+ ppdef1("i386");
+ ppdef1("__i386");
+ ppdef1("__i386__");
+ switch (cpu[1]) {
+ case '4':
+ ppdef1("__i486");
+ ppdef1("__i486__");
+ break;
+ case '5':
+ ppdef1("__i586");
+ ppdef1("__i586__");
+ ppdef1("__pentium");
+ ppdef1("__pentium__");
+ break;
+ case '6':
+ ppdef1("__pentiumpro");
+ ppdef1("__pentiumpro__");
+ ppdef1("__i686");
+ ppdef1("__i686__");
+ break;
+ case '7':
+ ppdef1("__pentium4");
+ ppdef1("__pentium4__");
+ break;
+ }
+
+ ir_platform.long_double_size = 12;
+ ir_platform.long_double_align = 4;
+ /* long long and double has a 4 byte alignment inside structs, this odd
+ * mode is everywhere except for windows OSes (they will revert it
+ * below) */
+ ir_platform.long_long_and_double_struct_align = 4;
+ ir_platform.x87_long_double = true;
+ } else if (streq(cpu, "arm")) {
+ /* TODO: what about those:
+ * ARM_FEATURE_UNALIGNED, ARMEL, ARM_ARCH_7A, ARM_FEATURE_DSP, ... */
+ ppdef1("__arm__");
+ if (strstr(os, "eabi") != NULL)
+ ppdef1("__ARM_EABI__");
+
+ ir_platform.long_double_size = 8;
+ ir_platform.long_double_align = 8;
+ } else if (streq(cpu, "sparc")) {
+ ir_platform.supports_thread_local_storage = true;
+ ppdef1("sparc");
+ ppdef1("__sparc");
+ ppdef1("__sparc__");
+ /* we always produce sparc V8 code at the moment */
+ ppdef1("__sparc_v8__");
+ if (strstr(manufacturer, "leon") != NULL
+ || streq(manufacturer, "invasic")) {
+ ppdef1("__leon__");
+ }
+ ir_platform.long_double_size = 16;
+ ir_platform.long_double_align = 8;
+ } else if (streq(cpu, "x86_64") || streq(cpu, "amd64")) {
+ ppdef1("__x86_64");
+ ppdef1("__x86_64__");
+ ppdef1("__amd64");
+ ppdef1("__amd64__");
+ ir_platform.long_double_size = 16;
+ ir_platform.long_double_align = 16;
+ ir_platform.x87_long_double = true;
+ } else if (streq(cpu, "mips")) {
+ ppdef1("__mips__");
+ ir_platform.long_double_size = 8;
+ ir_platform.long_double_align = 8;
+ } else if (streq(cpu, "TEMPLATE")) {
+ ir_platform.long_double_size = 8;
+ ir_platform.long_double_align = 8;
+ } else {
+ /** Everything that passes ir_init_target_from_triple()
+ * should work here as well. */
+ panic("Unexpected ABI");
+ }
+
+ object_format_t object_format;
+ if (strstr(os, "linux") != NULL) {
+ object_format = OBJECT_FORMAT_ELF;
+
+ ppdef_unix();
+ ppdef1("__linux");
+ ppdef1("__linux__");
+ ppdef1("linux");
+ if (strstr(os, "gnu") != NULL)
+ ppdef1("__gnu_linux__");
+ } else if (strstart(os, "freebsd")) {
+ ppdef("__FreeBSD__", "");
+ goto BSD;
+ } else if (strstr(os, "bsd") != NULL) {
+BSD:
+ object_format = OBJECT_FORMAT_ELF;
+ ir_platform.ia32_struct_in_regs = true;
+ ppdef_unix();
+ } else if (strstart(os, "darwin")) {
+ object_format = OBJECT_FORMAT_MACH_O;
+ ir_platform.is_darwin = true;
+ ir_platform.default_exe_name = "a.out";
+ ir_platform.user_label_prefix = '_';
+ ir_platform.long_double_size = 16;
+ ir_platform.long_double_align = 16;
+ ir_platform.pic_is_default = true;
+ ir_platform.ia32_po2_stackalign = 4;
+ ir_platform.ia32_struct_in_regs = true;
+ ir_platform.supports_thread_local_storage = false;
+
+ ppdef1("__MACH__");
+ ppdef1("__APPLE__");
+ ppdef1("__APPLE_CC__");
+ ppdef1("__CONSTANT_CFSTRINGS__");
+ ppdef1("__DYNAMIC__");
+ ppdef("__weak", "");
+ ppdef("__strong", "");
+ ppdef("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", "1050");
+ } else if (strstart(os, "mingw")) {
+ object_format = OBJECT_FORMAT_PE_COFF;
+ ir_platform.wchar_type = IR_TYPE_SHORT;
+ ir_platform.wchar_is_signed = false;
+ ir_platform.long_long_and_double_struct_align = 0;
+ ir_platform.supports_thread_local_storage = false;
+ ppdef1("__MINGW32__");
+ ppdef1("__MSVCRT__");
+ ppdef1("_WINNT");
+ ppdef1("__WINNT");
+ ppdef1("__WINNT__");
+ ppdef1("WINNT");
+ ppdef1("_WIN32");
+ ppdef1("__WIN32");
+ ppdef1("__WIN32__");
+ ppdef1("WIN32");
+ if (pointer_size == 8) {
+ ppdef1("_WIN64");
+ ppdef1("__WIN64");
+ ppdef1("__WIN64__");
+ ppdef1("WIN64");
+ ppdef1("__MINGW64__");
+ /* to ease porting of old c-code microsoft decided to use 32bits
+ * even for long */
+ ir_platform.long_size = 4;
+ ir_platform.intptr_type = IR_TYPE_LONG_LONG;
+ ir_platform.amd64_x64abi = true;
+ } else {
+ assert(pointer_size == 4);
+ ir_platform.user_label_prefix = '_';
+ ir_platform.intptr_type = IR_TYPE_INT;
+ }
+ } else if (strstart(os, "midipix")) {
+ object_format = OBJECT_FORMAT_PE_COFF;
+ ir_platform.long_long_and_double_struct_align = 0;
+ ir_platform.supports_thread_local_storage = false;
+ ppdef1("__midipix__");
+ if (pointer_size == 8) {
+ ir_platform.amd64_x64abi = true;
+ ppdef1("__NT64");
+ } else {
+ assert(pointer_size == 4);
+ ir_platform.user_label_prefix = '_';
+ ppdef1("__NT32");
+ }
+ } else if (streq(os, "elf") || streq(os, "octopos") || streq(os, "irtss")
+ || streq(os, "unknown")) {
+ object_format = OBJECT_FORMAT_ELF;
+ } else {
+ object_format = OBJECT_FORMAT_ELF;
+ be_warningf(NULL, "Unknown operating system '%s'", os);
+ }
+ ir_platform.object_format = object_format;
+
+ switch (object_format) {
+ case OBJECT_FORMAT_ELF:
+ ppdef1("__ELF__");
+ ir_platform.default_exe_name = "a.out";
+ break;
+ case OBJECT_FORMAT_PE_COFF:
+ ppdef1("__PE__");
+ ir_platform.default_exe_name = "a.exe";
+ break;
+ case OBJECT_FORMAT_MACH_O:
+ ir_platform.default_exe_name = "a.out";
+ break;
+ }
+
+ option_pic = ir_platform.pic_is_default;
+ option_pic_noplt = false;
+ init_lc_opts();
+}
+
+void ir_platform_init(void)
+{
+ /* Decide PIC style */
+ be_pic_style_t style;
+ if (!option_pic) {
+ style = BE_PIC_NONE;
+ } else {
+ ppdef("__PIC__", "2");
+ ppdef("__pic__", "2");
+ switch (ir_platform.object_format) {
+ case OBJECT_FORMAT_ELF:
+ style = option_pic_noplt ? BE_PIC_ELF_NO_PLT : BE_PIC_ELF_PLT;
+ break;
+ case OBJECT_FORMAT_MACH_O:
+ style = BE_PIC_MACH_O;
+ break;
+ case OBJECT_FORMAT_PE_COFF:
+ panic("Windows PIC not implemented");
+ }
+ }
+ ir_platform.pic_style = style;
+
+ if (ir_platform.is_darwin && !ir_target_big_endian())
+ ppdef1("__LITTLE_ENDIAN__");
+
+ ir_platform.initialized = true;
+}
+
+ir_platform_define_t const *ir_platform_define_first(void)
+{
+ assert(ir_platform.initialized);
+ return ir_platform.defines;
+}
+
+ir_platform_define_t const *ir_platform_define_next(
+ ir_platform_define_t const *const define)
+{
+ return define->next;
+}
+
+char const *ir_platform_define_name(ir_platform_define_t const *const define)
+{
+ return define->name;
+}
+
+char const *ir_platform_define_value(ir_platform_define_t const *const define)
+{
+ return define->value;
+}
+
+unsigned ir_platform_long_long_and_double_struct_align_override(void)
+{
+ assert(ir_platform.initialized);
+ return ir_platform.long_long_and_double_struct_align;
+}
+
+ir_platform_type_t ir_platform_wchar_type(void)
+{
+ assert(ir_platform.initialized);
+ return ir_platform.wchar_type;
+}
+
+int ir_platform_wchar_is_signed(void)
+{
+ assert(ir_platform.initialized);
+ return ir_platform.wchar_is_signed;
+}
+
+ir_platform_type_t ir_platform_intptr_type(void)
+{
+ assert(ir_platform.initialized);
+ return ir_platform.intptr_type;
+}
+
+int ir_platform_pic_is_default(void)
+{
+ assert(ir_platform.initialized);
+ return ir_platform.pic_is_default;
+}
+
+unsigned ir_platform_type_size(ir_platform_type_t type)
+{
+ switch (type) {
+ case IR_TYPE_BOOL: return 1;
+ case IR_TYPE_CHAR: return 1;
+ case IR_TYPE_SHORT: return 2;
+ case IR_TYPE_INT: return 4;
+ case IR_TYPE_LONG: return ir_platform.long_size;
+ case IR_TYPE_LONG_LONG: return 8;
+ case IR_TYPE_FLOAT: return 4;
+ case IR_TYPE_DOUBLE: return 8;
+ case IR_TYPE_LONG_DOUBLE: return ir_platform.long_double_size;
+ }
+ panic("Invalid object type");
+}
+
+unsigned ir_platform_type_align(ir_platform_type_t type)
+{
+ if (type == IR_TYPE_LONG_DOUBLE)
+ return ir_platform.long_double_align;
+ return ir_platform_type_size(type);
+}
+
+char ir_platform_user_label_prefix(void)
+{
+ return ir_platform.user_label_prefix;
+}
+
+char const *ir_platform_default_exe_name(void)
+{
+ return ir_platform.default_exe_name;
+}
+
+ir_type *ir_platform_va_list_type(void)
+{
+ return ir_platform.va_list_type;
+}
+
+int ir_platform_supports_thread_local_storage(void)
+{
+ return ir_platform.supports_thread_local_storage;
+}
+
+static ir_mode *make_int_mode(ir_platform_type_t type, bool is_signed)
+{
+ unsigned bitsize = ir_platform_type_size(type) * 8;
+ char name[16];
+ snprintf(name, sizeof(name), "%c%u", is_signed ? 'I' : 'U', bitsize);
+ unsigned modulo_shift = ir_target.isa->modulo_shift;
+ if (modulo_shift > 0)
+ modulo_shift = MAX(bitsize, modulo_shift);
+ return new_int_mode(name, bitsize, is_signed, modulo_shift);
+}
+
+static ir_mode *make_float_mode(ir_platform_type_t type)
+{
+ ir_mode_arithmetic arithmetic = irma_ieee754;
+ char const *name;
+ unsigned exponent_size;
+ unsigned mantissa_size;
+ if (type == IR_TYPE_FLOAT) {
+ name = "F32";
+ exponent_size = 8;
+ mantissa_size = 23;
+ } else if (type == IR_TYPE_DOUBLE) {
+ name = "F64";
+ exponent_size = 11;
+ mantissa_size = 52;
+ } else {
+ assert(type == IR_TYPE_LONG_DOUBLE);
+ if (ir_platform.x87_long_double) {
+ arithmetic = irma_x86_extended_float;
+ name = "F80";
+ exponent_size = 15;
+ mantissa_size = 64;
+ } else if (ir_platform.long_double_size == 8) {
+ return make_float_mode(IR_TYPE_DOUBLE);
+ } else {
+ assert(ir_platform.long_double_size == 16);
+ name = "F128";
+ exponent_size = 15;
+ mantissa_size = 112;
+ }
+ }
+ return new_float_mode(name, arithmetic, exponent_size, mantissa_size,
+ ir_target.float_int_overflow);
+}
+
+ir_mode *ir_platform_type_mode(ir_platform_type_t type, int is_signed)
+{
+ assert(ir_platform.initialized);
+ switch (type) {
+ case IR_TYPE_BOOL:
+ assert(!is_signed && "Bool type must be unsigned");
+ /* FALLTHROUGH */
+ case IR_TYPE_CHAR:
+ case IR_TYPE_SHORT:
+ case IR_TYPE_INT:
+ case IR_TYPE_LONG:
+ case IR_TYPE_LONG_LONG:
+ return make_int_mode(type, is_signed);
+ case IR_TYPE_FLOAT:
+ case IR_TYPE_DOUBLE:
+ case IR_TYPE_LONG_DOUBLE:
+ assert(is_signed && "Float type must be signed");
+ return make_float_mode(type);
+ }
+ panic("Invalid object type");
+}
+
+void ir_platform_finish(void)
+{
+ for (ir_platform_define_t *next, *define = ir_platform.defines;
+ define != NULL; define = next) {
+ next = define->next;
+ free(define);
+ }
+}
+
+void ir_platform_set_va_list_type_pointer(void)
+{
+ ir_platform.va_list_type = new_type_pointer(get_type_for_mode(mode_ANY));
+}
+
+ident *ir_platform_mangle_global(char const *const name)
+{
+ char user_label_prefix = ir_platform.user_label_prefix;
+ return user_label_prefix == 0 ? new_id_from_str(name)
+ : new_id_fmt("%c%s", user_label_prefix, name);
+}