X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fbearch_ia32.c;h=684d51a1b2bd0da32adfea6669c555c3b980ee94;hb=92e34bb016d10b1fc8c36aeb97bdc1bdd13be103;hp=83e43ed9a2749f02a537a2a2468964a3c10a6b13;hpb=214fc94d05a876c4f593d7cc54530fd4092ca359;p=libfirm diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 83e43ed9a..684d51a1b 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -76,6 +76,7 @@ #include "ia32_new_nodes.h" #include "gen_ia32_regalloc_if.h" #include "gen_ia32_machine.h" +#include "ia32_common_transform.h" #include "ia32_transform.h" #include "ia32_emitter.h" #include "ia32_map_regs.h" @@ -502,7 +503,7 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ /* the old SP is not needed anymore (kill the proj) */ assert(is_Proj(curr_sp)); - be_kill_node(curr_sp); + kill_node(curr_sp); /* copy ebp to esp */ curr_sp = be_new_Copy(&ia32_reg_classes[CLASS_ia32_gp], irg, bl, curr_bp); @@ -926,6 +927,8 @@ static void ia32_before_abi(void *self) { } } +transformer_t be_transformer = TRANSFORMER_DEFAULT; + /** * Transforms the standard firm graph into * an ia32 firm graph @@ -933,7 +936,7 @@ static void ia32_before_abi(void *self) { static void ia32_prepare_graph(void *self) { ia32_code_gen_t *cg = self; - /* do local optimisations */ + /* do local optimizations */ optimize_graph_df(cg->irg); /* TODO: we often have dead code reachable through out-edges here. So for @@ -947,23 +950,30 @@ static void ia32_prepare_graph(void *self) { if (cg->dump) be_dump(cg->irg, "-pre_transform", dump_ir_block_graph_sched); -#ifdef FIRM_GRGEN_BE - // disable CSE, because of two-step node-construction - set_opt_cse(0); + switch (be_transformer) { + case TRANSFORMER_DEFAULT: + /* transform remaining nodes into assembler instructions */ + ia32_transform_graph(cg); + break; - /* transform nodes into assembler instructions by PBQP magic */ - ia32_transform_graph_by_pbqp(cg); +#ifdef FIRM_GRGEN_BE + case TRANSFORMER_PBQP: + // disable CSE, because of two-step node-construction + set_opt_cse(0); - if (cg->dump) - be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched); - set_opt_cse(1); -#else + /* transform nodes into assembler instructions by PBQP magic */ + ia32_transform_graph_by_pbqp(cg); - /* transform remaining nodes into assembler instructions */ - ia32_transform_graph(cg); + if (cg->dump) + be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched); + set_opt_cse(1); + break; #endif - /* do local optimisations (mainly CSE) */ + default: panic("invalid transformer"); + } + + /* do local optimizations (mainly CSE) */ optimize_graph_df(cg->irg); if (cg->dump) @@ -1651,12 +1661,60 @@ static ia32_isa_t ia32_isa_template = { #endif }; +static void init_asm_constraints(void) +{ + be_init_default_asm_constraint_flags(); + + asm_constraint_flags['a'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['b'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['c'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['d'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['D'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['S'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['Q'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['q'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['A'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['l'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['R'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['r'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['p'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['f'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['t'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['u'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['Y'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER; + asm_constraint_flags['n'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE; + asm_constraint_flags['g'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE; + + /* no support for autodecrement/autoincrement */ + asm_constraint_flags['<'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + asm_constraint_flags['>'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + /* no float consts */ + asm_constraint_flags['E'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + asm_constraint_flags['F'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + /* makes no sense on x86 */ + asm_constraint_flags['s'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + /* no support for sse consts yet */ + asm_constraint_flags['C'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + /* no support for x87 consts yet */ + asm_constraint_flags['G'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + /* no support for mmx registers yet */ + asm_constraint_flags['y'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + /* not available in 32bit mode */ + asm_constraint_flags['Z'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + asm_constraint_flags['e'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; + + /* no code yet to determine register class needed... */ + asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; +} + /** * Initializes the backend ISA. */ static arch_env_t *ia32_init(FILE *file_handle) { static int inited = 0; ia32_isa_t *isa; + int i, n; if (inited) return NULL; @@ -1695,6 +1753,14 @@ static arch_env_t *ia32_init(FILE *file_handle) { intrinsic_env.isa = isa; ia32_handle_intrinsics(); + /* emit asm includes */ + n = get_irp_n_asms(); + for (i = 0; i < n; ++i) { + be_emit_cstring("#APP\n"); + be_emit_ident(get_irp_asm(i)); + be_emit_cstring("\n#NO_APP\n"); + } + /* needed for the debug support */ be_gas_emit_switch_section(GAS_SECTION_TEXT); be_emit_cstring(".Ltext0:\n"); @@ -1791,7 +1857,9 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, ir_mode *mode; unsigned cc; int n, i, regnum; + int pop_amount = 0; be_abi_call_flags_t call_flags = be_abi_call_get_flags(abi); + (void) self; /* set abi flags for calls */ @@ -1799,7 +1867,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, call_flags.bits.store_args_sequential = 0; /* call_flags.bits.try_omit_fp not changed: can handle both settings */ call_flags.bits.fp_free = 0; /* the frame pointer is fixed in IA32 */ - call_flags.bits.call_has_imm = 1; /* IA32 calls can have immediate address */ + call_flags.bits.call_has_imm = 1; /* No call immediates, we handle this by ourselves */ /* set parameter passing style */ be_abi_call_set_flags(abi, call_flags, &ia32_abi_callbacks); @@ -1809,8 +1877,9 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, cc = cc_cdecl_set; } else { cc = get_method_calling_convention(method_type); - if (get_method_additional_properties(method_type) & mtp_property_private - && (ia32_cg_config.optimize_cc)) { + if (!(cc & cc_fixed) && + get_method_additional_properties(method_type) & mtp_property_private && + ia32_cg_config.optimize_cc) { /* set the calling conventions to register parameter */ cc = (cc & ~cc_bits) | cc_reg_param; } @@ -1819,7 +1888,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, /* we have to pop the shadow parameter ourself for compound calls */ if( (get_method_calling_convention(method_type) & cc_compound_ret) && !(cc & cc_reg_param)) { - be_abi_call_set_pop(abi, get_mode_size_bytes(mode_P_data)); + pop_amount += get_mode_size_bytes(mode_P_data); } n = get_method_n_params(method_type); @@ -1839,11 +1908,23 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, /* Micro optimisation: if the mode is shorter than 4 bytes, load 4 bytes. * movl has a shorter opcode than mov[sz][bw]l */ ir_mode *load_mode = mode; - if (mode != NULL && get_mode_size_bytes(mode) < 4) load_mode = mode_Iu; + + if (mode != NULL) { + unsigned size = get_mode_size_bytes(mode); + + if (cc & cc_callee_clear_stk) { + pop_amount += (size + 3U) & ~3U; + } + + if (size < 4) load_mode = mode_Iu; + } + be_abi_call_param_stack(abi, i, load_mode, 4, 0, 0); } } + be_abi_call_set_pop(abi, pop_amount); + /* set return registers */ n = get_method_n_ress(method_type); @@ -2157,6 +2238,23 @@ static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j) return 0; } +static asm_constraint_flags_t ia32_parse_asm_constraint(const void *self, const char **c) +{ + (void) self; + (void) c; + + /* we already added all our simple flags to the flags modifier list in + * init, so this flag we don't know. */ + return ASM_CONSTRAINT_FLAG_INVALID; +} + +static int ia32_is_valid_clobber(const void *self, const char *clobber) +{ + (void) self; + + return ia32_get_clobber_register(clobber) != NULL; +} + /** * Returns the libFirm configuration parameter for this backend. */ @@ -2189,6 +2287,10 @@ static const backend_params *ia32_get_libfirm_params(void) { ia32_setup_cg_config(); + /* doesn't really belong here, but this is the earliest place the backend + * is called... */ + init_asm_constraints(); + p.dep_param = &ad; p.if_conv_info = &ifconv; return &p; @@ -2206,8 +2308,21 @@ static lc_opt_enum_int_var_t gas_var = { (int*) &be_gas_flavour, gas_items }; +static const lc_opt_enum_int_items_t transformer_items[] = { + { "default", TRANSFORMER_DEFAULT }, +#ifdef FIRM_GRGEN_BE + { "pbqp", TRANSFORMER_PBQP }, +#endif + { NULL, 0 } +}; + +static lc_opt_enum_int_var_t transformer_var = { + (int*)&be_transformer, transformer_items +}; + static const lc_opt_table_entry_t ia32_options[] = { LC_OPT_ENT_ENUM_INT("gasmode", "set the GAS compatibility mode", &gas_var), + LC_OPT_ENT_ENUM_INT("transformer", "the transformer used for code selection", &transformer_var), LC_OPT_ENT_INT("stackalign", "set power of two stack alignment for calls", &ia32_isa_template.arch_env.stack_alignment), LC_OPT_LAST @@ -2228,6 +2343,8 @@ const arch_isa_if_t ia32_isa_if = { ia32_get_allowed_execution_units, ia32_get_machine, ia32_get_irg_list, + ia32_parse_asm_constraint, + ia32_is_valid_clobber }; void ia32_init_emitter(void);