From 99ba6c297269d17b31574fedc5618dd0a7ae8b0c Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 20 Sep 2007 14:18:41 +0000 Subject: [PATCH 1/1] - use flags handling code for ia32 Compares (including Cmov, Set, Jcc) - Allow Source/DestAM with 8/16bit modes where this is profitable [r15906] --- ir/be/ia32/bearch_ia32.c | 31 +- ir/be/ia32/ia32_emitter.c | 458 ++++++++++-------------- ir/be/ia32/ia32_emitter.h | 5 +- ir/be/ia32/ia32_finish.c | 30 +- ir/be/ia32/ia32_new_nodes.c | 21 +- ir/be/ia32/ia32_nodes_attr.h | 6 +- ir/be/ia32/ia32_spec.pl | 414 ++++++++++------------ ir/be/ia32/ia32_transform.c | 664 +++++++++++++++++------------------ ir/be/ia32/ia32_x87.c | 62 ++-- 9 files changed, 794 insertions(+), 897 deletions(-) diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 1e11e2d27..598a0fbea 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -497,12 +497,11 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ ir_mode *mode_bp = env->isa->bp->reg_class->mode; ir_graph *irg = current_ir_graph; - /* gcc always emits a leave at the end of a routine */ if (ARCH_AMD(isa->opt_arch)) { ir_node *leave; /* leave */ - leave = new_rd_ia32_Leave(NULL, env->irg, bl, curr_sp, curr_bp); + leave = new_rd_ia32_Leave(NULL, irg, bl, curr_sp, curr_bp); set_ia32_flags(leave, arch_irn_flags_ignore); curr_bp = new_r_Proj(irg, bl, leave, mode_bp, pn_ia32_Leave_frame); curr_sp = new_r_Proj(irg, bl, leave, get_irn_mode(curr_sp), pn_ia32_Leave_stack); @@ -968,7 +967,7 @@ static void ia32_prepare_graph(void *self) { if (cg->dump) be_dump(cg->irg, "-am", dump_ir_block_graph_sched); - /* do code placement, (optimize position of constants and argument loads) */ + /* do code placement, to optimize the position of constants */ place_code(cg->irg); if (cg->dump) @@ -990,6 +989,7 @@ static void turn_back_am(ir_node *node) ir_node *base = get_irn_n(node, n_ia32_base); ir_node *index = get_irn_n(node, n_ia32_index); ir_node *mem = get_irn_n(node, n_ia32_mem); + ir_node *noreg = ia32_new_NoReg_gp(ia32_current_cg); ir_node *load; ir_node *load_res; ir_node *mem_proj; @@ -1006,10 +1006,22 @@ static void turn_back_am(ir_node *node) if(get_ia32_am_arity(node) == ia32_am_unary) { set_irn_n(node, n_ia32_unary_op, load_res); } else if(get_ia32_am_arity(node) == ia32_am_binary) { - set_irn_n(node, n_ia32_binary_right, load_res); + if(is_ia32_Immediate(get_irn_n(node, n_ia32_Cmp_right))) { + assert(is_ia32_Cmp(node) || is_ia32_Cmp8Bit(node) + || is_ia32_Test(node) || is_ia32_Test8Bit(node)); + set_irn_n(node, n_ia32_binary_left, load_res); + } else { + set_irn_n(node, n_ia32_binary_right, load_res); + } } else if(get_ia32_am_arity(node) == ia32_am_ternary) { set_irn_n(node, n_ia32_binary_right, load_res); } + set_irn_n(node, n_ia32_base, noreg); + set_irn_n(node, n_ia32_index, noreg); + set_ia32_am_offs_int(node, 0); + set_ia32_am_sc(node, NULL); + set_ia32_am_scale(node, 0); + clear_ia32_am_sc_sign(node); /* rewire mem-proj */ if(get_irn_mode(node) == mode_T) { @@ -1036,9 +1048,16 @@ static void turn_back_am(ir_node *node) static ir_node *flags_remat(ir_node *node, ir_node *after) { /* we should turn back source address mode when rematerializing nodes */ - ia32_op_type_t type = get_ia32_op_type(node); + ia32_op_type_t type = get_ia32_op_type(node); + ir_node *block; ir_node *copy; + if(is_Block(after)) { + block = after; + } else { + block = get_nodes_block(after); + } + if (type == ia32_AddrModeS) { turn_back_am(node); } else if (type == ia32_AddrModeD) { @@ -1049,6 +1068,8 @@ static ir_node *flags_remat(ir_node *node, ir_node *after) } copy = exact_copy(node); + ir_fprintf(stderr, "Remated: %+F\n", copy); + set_nodes_block(copy, block); sched_add_after(after, copy); return copy; diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 77fde0842..7c356ecf1 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -177,27 +177,6 @@ char get_mode_suffix(const ir_mode *mode) { panic("Can't output mode_suffix for %+F\n", mode); } -static -int produces_result(const ir_node *node) { - return - !is_ia32_CmpSet(node) && - !is_ia32_CmpSet8Bit(node) && - !is_ia32_CmpJmp(node) && - !is_ia32_CmpJmp8Bit(node) && - !is_ia32_St(node) && - !is_ia32_SwitchJmp(node) && - !is_ia32_TestJmp(node) && - !is_ia32_TestJmp8Bit(node) && - !is_ia32_xCmpSet(node) && - !is_ia32_xCmpJmp(node) && - !is_ia32_CmpCMov(node) && - !is_ia32_CmpCMov8Bit(node) && - !is_ia32_TestCMov(node) && - !is_ia32_TestCMov8Bit(node) && - !is_ia32_CmpSet(node) && - !is_ia32_TestSet(node); -} - static const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) { @@ -427,6 +406,17 @@ void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, be_emit_char(env, 'x'); } +void ia32_emit_8bit_dest_register(ia32_emit_env_t *env, const ir_node *node, + int pos) +{ + const arch_register_t *reg = get_out_reg(env, node, pos); + const char *reg_name = arch_register_get_name(reg); + + be_emit_char(env, '%'); + be_emit_char(env, reg_name[1]); + be_emit_char(env, 'l'); +} + void ia32_emit_source_register_or_immediate(ia32_emit_env_t *env, const ir_node *node, int pos) { @@ -441,7 +431,7 @@ void ia32_emit_source_register_or_immediate(ia32_emit_env_t *env, /** * Emits registers and/or address mode of a binary operation. */ -void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { +void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node, int produces_result) { const ir_node *right_op = get_irn_n(node, n_ia32_binary_right); switch(get_ia32_op_type(node)) { @@ -454,7 +444,7 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { } else { const arch_register_t *in1 = get_in_reg(env, node, n_ia32_binary_left); const arch_register_t *in2 = get_in_reg(env, node, n_ia32_binary_right); - const arch_register_t *out = produces_result(node) ? get_out_reg(env, node, 0) : NULL; + const arch_register_t *out = produces_result ? get_out_reg(env, node, 0) : NULL; const arch_register_t *in; const char *in_name; @@ -470,13 +460,12 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { break; case ia32_AddrModeS: if(is_ia32_Immediate(right_op)) { - assert(!produces_result(node) && - "Source AM with Const must not produce result"); + assert(!produces_result && "Source AM with Const must not produce result"); emit_ia32_Immediate(env, right_op); be_emit_cstring(env, ", "); ia32_emit_am(env, node); - } else if (produces_result(node)) { + } else if (produces_result) { ia32_emit_am(env, node); be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); @@ -517,9 +506,9 @@ void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) { } break; case ia32_AddrModeS: - case ia32_AddrModeD: ia32_emit_am(env, node); break; + case ia32_AddrModeD: default: assert(0 && "unsupported op type"); } @@ -646,14 +635,13 @@ void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node) { */ struct cmp2conditon_t { const char *name; - pn_Cmp num; + int num; }; /* * positive conditions for signed compares */ -static -const struct cmp2conditon_t cmp2condition_s[] = { +static const struct cmp2conditon_t cmp2condition_s[] = { { NULL, pn_Cmp_False }, /* always false */ { "e", pn_Cmp_Eq }, /* == */ { "l", pn_Cmp_Lt }, /* < */ @@ -661,14 +649,13 @@ const struct cmp2conditon_t cmp2condition_s[] = { { "g", pn_Cmp_Gt }, /* > */ { "ge", pn_Cmp_Ge }, /* >= */ { "ne", pn_Cmp_Lg }, /* != */ - { NULL, pn_Cmp_Leg}, /* Floating point: ordered */ + { NULL, pn_Cmp_Leg}, /* always true */ }; /* * positive conditions for unsigned compares */ -static -const struct cmp2conditon_t cmp2condition_u[] = { +static const struct cmp2conditon_t cmp2condition_u[] = { { NULL, pn_Cmp_False }, /* always false */ { "e", pn_Cmp_Eq }, /* == */ { "b", pn_Cmp_Lt }, /* < */ @@ -676,30 +663,122 @@ const struct cmp2conditon_t cmp2condition_u[] = { { "a", pn_Cmp_Gt }, /* > */ { "ae", pn_Cmp_Ge }, /* >= */ { "ne", pn_Cmp_Lg }, /* != */ - { NULL, pn_Cmp_True }, /* always true */ + { NULL, pn_Cmp_Leg }, /* always true */ }; -/* - * returns the condition code +enum { + ia32_pn_Cmp_unsigned = 0x1000, + ia32_pn_Cmp_float = 0x2000, +}; + +/** + * walks up a tree of copies/perms/spills/reloads to find the original value + * that is moved around */ -static -const char *get_cmp_suffix(pn_Cmp cmp_code) +static ir_node *find_original_value(ir_node *node) +{ + inc_irg_visited(current_ir_graph); + while(1) { + mark_irn_visited(node); + if(be_is_Copy(node)) { + node = be_get_Copy_op(node); + } else if(be_is_CopyKeep(node)) { + node = be_get_CopyKeep_op(node); + } else if(is_Proj(node)) { + ir_node *pred = get_Proj_pred(node); + if(be_is_Perm(pred)) { + node = get_irn_n(pred, get_Proj_proj(node)); + } else if(be_is_MemPerm(pred)) { + node = get_irn_n(pred, get_Proj_proj(node) + 1); + } else if(is_ia32_Load(pred)) { + node = get_irn_n(pred, n_ia32_Load_mem); + } else { + return node; + } + } else if(is_Store(node)) { + node = get_irn_n(node, n_ia32_Store_val); + } else if(is_Phi(node)) { + int i, arity; + arity = get_irn_arity(node); + for(i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + if(irn_visited(in)) + continue; + node = in; + break; + } + assert(i < arity); + } else { + return node; + } + } +} + +static int determine_final_pnc(const ir_node *node, int flags_pos, + int pnc) { - assert( (cmp2condition_s[cmp_code & 7].num) == (cmp_code & 7)); - assert( (cmp2condition_u[cmp_code & 7].num) == (cmp_code & 7)); + ir_node *flags = get_irn_n(node, flags_pos); + const ia32_attr_t *flags_attr; + flags = skip_Proj(flags); + + if(is_ia32_Sahf(flags)) { + ir_node *cmp = get_irn_n(flags, n_ia32_Sahf_val); + if(!is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp) + || is_ia32_FucomppFnstsw(cmp)) { + cmp = find_original_value(cmp); + assert(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp) + || is_ia32_FucomppFnstsw(cmp)); + } - if((cmp_code & ia32_pn_Cmp_Unsigned)) { - return cmp2condition_u[cmp_code & 7].name; + flags_attr = get_ia32_attr_const(cmp); + if(flags_attr->data.cmp_flipped) + pnc = get_mirrored_pnc(pnc); + pnc |= ia32_pn_Cmp_float; + } else if(is_ia32_Ucomi(flags)) { + flags_attr = get_ia32_attr_const(flags); + + if(flags_attr->data.cmp_flipped) + pnc = get_mirrored_pnc(pnc); + pnc |= ia32_pn_Cmp_float; } else { - return cmp2condition_s[cmp_code & 7].name; + assert(is_ia32_Cmp(flags) || is_ia32_Test(flags) + || is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags)); + flags_attr = get_ia32_attr_const(flags); + + if(flags_attr->data.cmp_flipped) + pnc = get_mirrored_pnc(pnc); + if(flags_attr->data.cmp_unsigned) + pnc |= ia32_pn_Cmp_unsigned; } + + return pnc; } -void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc) +static void ia32_emit_cmp_suffix(ia32_emit_env_t *env, int pnc) { - be_emit_string(env, get_cmp_suffix(pnc)); + const char *str; + + if((pnc & ia32_pn_Cmp_float) || (pnc & ia32_pn_Cmp_unsigned)) { + pnc = pnc & 7; + assert(cmp2condition_u[pnc].num == pnc); + str = cmp2condition_u[pnc].name; + } else { + pnc = pnc & 7; + assert(cmp2condition_s[pnc].num == pnc); + str = cmp2condition_s[pnc].name; + } + + be_emit_string(env, str); } +void ia32_emit_cmp_suffix_node(ia32_emit_env_t *env, const ir_node *node, + int flags_pos) +{ + pn_Cmp pnc = get_ia32_pncode(node); + + pnc = determine_final_pnc(node, flags_pos, pnc); + ia32_emit_cmp_suffix(env, pnc); +} /** * Returns the target block for a control flow node. @@ -742,8 +821,7 @@ static ir_node *next_blk_sched(const ir_node *block) { /** * Returns the Proj with projection number proj and NOT mode_M */ -static -ir_node *get_proj(const ir_node *node, long proj) { +static ir_node *get_proj(const ir_node *node, long proj) { const ir_edge_t *edge; ir_node *src; @@ -765,26 +843,24 @@ ir_node *get_proj(const ir_node *node, long proj) { /** * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false) */ -static -void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode, - long pnc) { +static void emit_ia32_Jcc(ia32_emit_env_t *env, const ir_node *node) +{ const ir_node *proj_true; const ir_node *proj_false; const ir_node *block; const ir_node *next_block; - int flipped = 0; + pn_Cmp pnc = get_ia32_pncode(node); - /* get both Proj's */ - proj_true = get_proj(node, pn_Cond_true); - assert(proj_true && "CondJmp without true Proj"); + pnc = determine_final_pnc(node, 0, pnc); - proj_false = get_proj(node, pn_Cond_false); - assert(proj_false && "CondJmp without false Proj"); + /* get both Projs */ + proj_true = get_proj(node, pn_ia32_Jcc_true); + assert(proj_true && "Jcc without true Proj"); - /* for now, the code works for scheduled and non-schedules blocks */ - block = get_nodes_block(node); + proj_false = get_proj(node, pn_ia32_Jcc_false); + assert(proj_false && "Jcc without false Proj"); - /* we have a block schedule */ + block = get_nodes_block(node); next_block = next_blk_sched(block); if (get_cfop_target_block(proj_true) == next_block) { @@ -793,14 +869,17 @@ void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode, proj_true = proj_false; proj_false = t; - flipped = 1; - pnc = get_negated_pnc(pnc, mode); + if(pnc & ia32_pn_Cmp_float) { + pnc = get_negated_pnc(pnc, mode_F); + } else { + pnc = get_negated_pnc(pnc, mode_Iu); + } } - if (mode_is_float(mode)) { - /* Some floating point comparisons require a test of the parity flag, which - * indicates that the result is unordered */ - switch (pnc & ~ia32_pn_Cmp_Unsigned) { + if (pnc & ia32_pn_Cmp_float) { + /* Some floating point comparisons require a test of the parity flag, + * which indicates that the result is unordered */ + switch (pnc & 15) { case pn_Cmp_Uo: be_emit_cstring(env, "\tjp "); ia32_emit_cfop_target(env, proj_true); @@ -819,7 +898,7 @@ void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode, be_emit_cstring(env, "\tjp "); ia32_emit_cfop_target(env, proj_false); be_emit_finish_line_gas(env, proj_false); - goto float_jcc; + goto emit_jcc; case pn_Cmp_Ug: case pn_Cmp_Uge: @@ -827,13 +906,9 @@ void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode, be_emit_cstring(env, "\tjp "); ia32_emit_cfop_target(env, proj_true); be_emit_finish_line_gas(env, proj_true); - goto float_jcc; + goto emit_jcc; default: - float_jcc: - /* The bits set by floating point compares correspond to unsigned - * comparisons */ - pnc |= ia32_pn_Cmp_Unsigned; goto emit_jcc; } } else { @@ -858,51 +933,7 @@ emit_jcc: } } -/** - * Emits code for conditional jump. - */ -static -void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { - be_emit_cstring(env, "\tcmp"); - ia32_emit_mode_suffix(env, node); - be_emit_char(env, ' '); - ia32_emit_binop(env, node); - be_emit_finish_line_gas(env, node); - - finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); -} - -/** - * Emits code for conditional jump with two variables. - */ -static -void emit_ia32_CmpJmp(ia32_emit_env_t *env, const ir_node *node) { - CondJmp_emitter(env, node); -} - -/** - * Emits code for conditional test and jump. - */ -static -void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { - be_emit_cstring(env, "\ttest"); - ia32_emit_mode_suffix(env, node); - be_emit_char(env, ' '); - - ia32_emit_binop(env, node); - be_emit_finish_line_gas(env, node); - - finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); -} - -/** - * Emits code for conditional test and jump with two variables. - */ -static -void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) { - TestJmp_emitter(env, node); -} - +#if 0 /** * Emits code for conditional SSE floating point jump with two variables. */ @@ -911,7 +942,7 @@ void emit_ia32_xCmpJmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tucomi"); ia32_emit_xmm_mode_suffix(env, node); be_emit_char(env, ' '); - ia32_emit_binop(env, node); + ia32_emit_binop(env, node, 0); be_emit_finish_line_gas(env, node); finish_CondJmp(env, node, mode_F, get_ia32_pncode(node)); @@ -961,140 +992,57 @@ void emit_ia32_x87CmpJmp(ia32_emit_env_t *env, const ir_node *node) { finish_CondJmp(env, node, mode_E, pnc); } +#endif -static -void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) +static void emit_ia32_CMov(ia32_emit_env_t *env, const ir_node *node) { - const arch_register_t *in1, *in2, *out; - long pnc = get_ia32_pncode(node); - - out = arch_get_irn_register(env->arch_env, node); - - /* we have to emit the cmp first, because the destination register */ - /* could be one of the compare registers */ - if (is_ia32_xCmpCMov(node)) { - be_emit_cstring(env, "\tucomis"); - ia32_emit_mode_suffix_mode(env, get_irn_mode(node)); - be_emit_char(env, ' '); - ia32_emit_source_register(env, node, 1); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 0); - - in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 2)); - in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 3)); + const arch_register_t *out = arch_get_irn_register(env->arch_env, node); + const arch_register_t *in_true; + const arch_register_t *in_false; + pn_Cmp pnc = get_ia32_pncode(node); + + pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc); + + in_true = arch_get_irn_register(env->arch_env, + get_irn_n(node, n_ia32_CMov_val_true)); + in_false = arch_get_irn_register(env->arch_env, + get_irn_n(node, n_ia32_CMov_val_false)); + + /* should be same constraint fullfilled? */ + if(out == in_false) { + /* yes -> nothing to do */ + } else if(out == in_true) { + const arch_register_t *tmp; + + /* swap left/right and negate pnc */ + pnc = get_negated_pnc(pnc, mode_Iu); + + tmp = in_true; + in_true = in_false; + in_false = tmp; } else { - if (is_ia32_CmpCMov(node) || is_ia32_CmpCMov8Bit(node)) { - be_emit_cstring(env, "\tcmp "); - } else { - assert(is_ia32_TestCMov(node) || is_ia32_TestCMov8Bit(node)); - be_emit_cstring(env, "\ttest "); - } - ia32_emit_binop(env, node); - - in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 5)); - in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 6)); - } - be_emit_finish_line_gas(env, node); - - if (out == in2) { - /* best case: default in == out -> do nothing */ - } else if(in2 == &ia32_gp_regs[REG_GP_UKNWN]) { - /* also nothign to do for unknown regs */ - } else if (out == in1) { - const arch_register_t *t; - /* true in == out -> need complement compare and exchange true and - * default in */ - t = in1; - in1 = in2; - in2 = t; - pnc = get_negated_pnc(pnc, get_irn_mode(node)); - } else { - /* out is different from both ins: need copy default -> out */ + /* we need a mov */ be_emit_cstring(env, "\tmovl "); - ia32_emit_register(env, in2); + ia32_emit_register(env, in_false); be_emit_cstring(env, ", "); ia32_emit_register(env, out); be_emit_finish_line_gas(env, node); } be_emit_cstring(env, "\tcmov"); - ia32_emit_cmp_suffix(env, pnc ); - be_emit_cstring(env, "l "); - ia32_emit_register(env, in1); - be_emit_cstring(env, ", "); - ia32_emit_register(env, out); - - be_emit_finish_line_gas(env, node); -} - -static -void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) -{ - CMov_emitter(env, node); -} - -static -void emit_ia32_TestCMov(ia32_emit_env_t *env, const ir_node *node) -{ - CMov_emitter(env, node); -} - -static -void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) -{ - CMov_emitter(env, node); -} - -static -void Set_emitter(ia32_emit_env_t *env, const ir_node *node) -{ - long pnc = get_ia32_pncode(node); - const char *reg8bit; - const arch_register_t *out; - - out = arch_get_irn_register(env->arch_env, node); - reg8bit = ia32_get_mapped_reg_name(env->isa->regs_8bit, out); - - if(is_ia32_xCmpSet(node)) { - be_emit_cstring(env, "\tucomis"); - ia32_emit_mode_suffix_mode(env, get_irn_mode(get_irn_n(node, n_ia32_binary_left))); - be_emit_char(env, ' '); - ia32_emit_binop(env, node); + ia32_emit_cmp_suffix(env, pnc); + be_emit_char(env, ' '); + if(get_ia32_op_type(node) == ia32_AddrModeS) { + ia32_emit_am(env, node); } else { - if (is_ia32_CmpSet(node) || is_ia32_CmpSet8Bit(node)) { - be_emit_cstring(env, "\tcmp"); - } else { - assert(is_ia32_TestSet(node) || is_ia32_TestSet8Bit(node)); - be_emit_cstring(env, "\ttest"); - } - ia32_emit_mode_suffix(env, node); - be_emit_char(env, ' '); - ia32_emit_binop(env, node); + ia32_emit_register(env, in_true); } + be_emit_cstring(env, ", "); + ia32_emit_register(env, out); be_emit_finish_line_gas(env, node); - - be_emit_cstring(env, "\tset"); - ia32_emit_cmp_suffix(env, pnc); - be_emit_cstring(env, " %"); - be_emit_string(env, reg8bit); - be_emit_finish_line_gas(env, node); -} - -static -void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) { - Set_emitter(env, node); -} - -static -void emit_ia32_TestSet(ia32_emit_env_t *env, const ir_node *node) { - Set_emitter(env, node); -} - -static -void emit_ia32_xCmpSet(ia32_emit_env_t *env, const ir_node *node) { - Set_emitter(env, node); } +#if 0 static void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { int sse_pnc = -1; @@ -1153,7 +1101,7 @@ void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_finish_line_gas(env, node); be_emit_cstring(env, "\tcmpsd $3, "); - ia32_emit_binop(env, node); + ia32_emit_binop(env, node, 0); be_emit_finish_line_gas(env, node); be_emit_cstring(env, "\tmovsd "); @@ -1164,7 +1112,7 @@ void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tcmpsd "); be_emit_irprintf(env->emit, "%d, ", sse_pnc); - ia32_emit_binop(env, node); + ia32_emit_binop(env, node, 0); be_emit_finish_line_gas(env, node); if (unord && sse_pnc != 3) { @@ -1176,6 +1124,7 @@ void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_finish_line_gas(env, node); } } +#endif /********************************************************* * _ _ _ @@ -1879,12 +1828,8 @@ void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { /* a zero? */ if(attr->symconst == NULL && attr->offset == 0) { - if (env->isa->opt_arch == arch_pentium_4) { - /* P4 prefers sub r, r, others xor r, r */ - be_emit_cstring(env, "\tsubl "); - } else { - be_emit_cstring(env, "\txorl "); - } + assert(get_ia32_flags(node) & arch_irn_flags_modify_flags); + be_emit_cstring(env, "\txorl "); ia32_emit_dest_register(env, node, 0); be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); @@ -1957,12 +1902,7 @@ static void emit_xchg(ia32_emit_env_t *env, const ir_node* node, const arch_regi /* helper function for emit_ia32_Minus64Bit */ static void emit_zero(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *reg) { - if (env->isa->opt_arch == arch_pentium_4) { - /* P4 prefers sub r, r, others xor r, r */ - be_emit_cstring(env, "\tsubl "); - } else { - be_emit_cstring(env, "\txorl "); - } + be_emit_cstring(env, "\txorl "); ia32_emit_register(env, reg); be_emit_cstring(env, ", "); ia32_emit_register(env, reg); @@ -2070,18 +2010,7 @@ void ia32_register_emitters(void) { /* other ia32 emitter functions */ IA32_EMIT(Asm); - IA32_EMIT(CmpJmp); - IA32_EMIT2(CmpJmp8Bit, CmpJmp); - IA32_EMIT(TestJmp); - IA32_EMIT2(TestJmp8Bit, TestJmp); - IA32_EMIT(CmpCMov); - IA32_EMIT2(CmpCMov8Bit, CmpCMov); - IA32_EMIT(TestCMov); - IA32_EMIT2(TestCMov8Bit, TestCMov); - IA32_EMIT(CmpSet); - IA32_EMIT2(CmpSet8Bit, CmpSet); - IA32_EMIT(TestSet); - IA32_EMIT2(TestSet8Bit, TestSet); + IA32_EMIT(CMov); IA32_EMIT(SwitchJmp); IA32_EMIT(CopyB); IA32_EMIT(CopyB_i); @@ -2093,9 +2022,9 @@ void ia32_register_emitters(void) { IA32_EMIT(Const); IA32_EMIT(LdTls); IA32_EMIT(Minus64Bit); + IA32_EMIT(Jcc); +#if 0 IA32_EMIT(xCmp); - IA32_EMIT(xCmpSet); - IA32_EMIT(xCmpCMov); IA32_EMIT(xCmpJmp); IA32_EMIT2(fcomJmp, x87CmpJmp); IA32_EMIT2(fcompJmp, x87CmpJmp); @@ -2103,6 +2032,7 @@ void ia32_register_emitters(void) { IA32_EMIT2(fcomrJmp, x87CmpJmp); IA32_EMIT2(fcomrpJmp, x87CmpJmp); IA32_EMIT2(fcomrppJmp, x87CmpJmp); +#endif /* benode emitter */ BE_EMIT(Call); diff --git a/ir/be/ia32/ia32_emitter.h b/ir/be/ia32/ia32_emitter.h index b4ec84176..3c4a0ebd9 100644 --- a/ir/be/ia32/ia32_emitter.h +++ b/ir/be/ia32/ia32_emitter.h @@ -45,6 +45,7 @@ struct ia32_emit_env_t { void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_8bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos); +void ia32_emit_8bit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node); @@ -55,7 +56,9 @@ void ia32_emit_x87_mode_suffix(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_xmm_mode_suffix_s(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode); -void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node); +void ia32_emit_cmp_suffix_node(ia32_emit_env_t *env, const ir_node *node, + int flags_pos); +void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node, int produces_result); void ia32_emit_am_or_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node, int pos); diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index 03d38021c..884024f97 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -353,8 +353,7 @@ static INLINE int need_constraint_copy(ir_node *irn) { return ! is_ia32_Lea(irn) && ! is_ia32_Conv_I2I(irn) && ! is_ia32_Conv_I2I8Bit(irn) && - ! is_ia32_TestCMov(irn) && - ! is_ia32_CmpCMov(irn); + ! is_ia32_CMov(irn); } /** @@ -501,33 +500,6 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg, } } } - - /* check xCmp: try to avoid unordered cmp */ - if ((is_ia32_xCmp(node) || is_ia32_xCmpCMov(node) || is_ia32_xCmpSet(node)) && - op_tp == ia32_Normal) - { - long pnc = get_ia32_pncode(node); - - if (pnc & pn_Cmp_Uo) { - ir_node *tmp; - int idx1 = n_ia32_binary_left; - int idx2 = n_ia32_binary_right; - - if (is_ia32_xCmpCMov(node)) { - idx1 = 0; - idx2 = 1; - } - - /** Matze: TODO this looks wrong, I assume we should exchange - * the proj numbers and not the inputs... */ - - tmp = get_irn_n(node, idx1); - set_irn_n(node, idx1, get_irn_n(node, idx2)); - set_irn_n(node, idx2, tmp); - - set_ia32_pncode(node, get_negated_pnc(pnc, mode_E)); - } - } } /** diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 8f6381c57..dbc495f1f 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -279,14 +279,8 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { if(is_ia32_SwitchJmp(n) || is_ia32_CopyB(n) || is_ia32_CopyB_i(n)) { fprintf(F, "pn_code = %ld\n", get_ia32_pncode(n)); } else { - if(get_ia32_pncode(n) & ia32_pn_Cmp_Unsigned) { - long pnc = get_ia32_pncode(n); - fprintf(F, "pn_code = %ld (%s, unsigned)\n", - pnc, get_pnc_string(pnc & ~ia32_pn_Cmp_Unsigned)); - } else { - fprintf(F, "pn_code = %ld (%s)\n", get_ia32_pncode(n), - get_pnc_string(get_ia32_pncode(n))); - } + fprintf(F, "pn_code = %ld (%s)\n", get_ia32_pncode(n), + get_pnc_string(get_ia32_pncode(n))); } /* dump n_res */ @@ -986,8 +980,11 @@ int get_ia32_out_regnr(const ir_node *node, int pos) { void ia32_swap_left_right(ir_node *node) { - ir_node *left = get_irn_n(node, n_ia32_binary_left); - ir_node *right = get_irn_n(node, n_ia32_binary_right); + ia32_attr_t *attr = get_ia32_attr(node); + ir_node *left = get_irn_n(node, n_ia32_binary_left); + ir_node *right = get_irn_n(node, n_ia32_binary_right); + + attr->data.cmp_flipped = !attr->data.cmp_flipped; assert(is_ia32_commutative(node)); set_irn_n(node, n_ia32_binary_left, right); set_irn_n(node, n_ia32_binary_right, left); @@ -1126,6 +1123,10 @@ int ia32_compare_attr(const ia32_attr_t *a, const ia32_attr_t *b) { if (a->data.except_label != b->data.except_label) return 1; + if (a->data.cmp_flipped != b->data.cmp_flipped + || a->data.cmp_unsigned != b->data.cmp_unsigned) + return 1; + return 0; } diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index 6e41e8b02..372df0a61 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -70,10 +70,6 @@ enum { ia32_S = (1 << 3) /**< S - Scale is set */ }; -enum { - ia32_pn_Cmp_Unsigned = 0x100 /**< set this flag in a pnc to indicate an unsigned compare operation */ -}; - #ifndef NDEBUG typedef enum { IA32_ATTR_INVALID = 0, @@ -107,6 +103,8 @@ struct ia32_attr_t { unsigned need_stackent:1; /**< Set to 1 if node need space on stack. */ unsigned need_64bit_stackent:1; /**< needs a 64bit stack entity (see double->unsigned int conv) */ unsigned need_32bit_stackent:1; /**< needs a 32bit stack entity */ + unsigned cmp_flipped : 1; + unsigned cmp_unsigned : 1; } data; int *out_flags; /**< flags for each produced value */ diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 2ad471a96..f67bcb1a3 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -131,7 +131,7 @@ $arch = "ia32"; { name => "mm5", type => 4 }, { name => "mm6", type => 4 }, { name => "mm7", type => 4 }, - { mode => "mode_E", flags => "manual_ra" } + { mode => "mode_E", flags => "manual_ra" } ], xmm => [ { name => "xmm0", type => 1 }, @@ -168,15 +168,15 @@ $arch = "ia32"; { name => "st5", realname => "st(5)", type => 4 }, { name => "st6", realname => "st(6)", type => 4 }, { name => "st7", realname => "st(7)", type => 4 }, - { mode => "mode_E", flags => "manual_ra" } + { mode => "mode_E", flags => "manual_ra" } ], fp_cw => [ # the floating point control word - { name => "fpcw", type => 4 | 32}, - { mode => "mode_fpcw", flags => "manual_ra|state" } + { name => "fpcw", type => 4|32 }, + { mode => "mode_fpcw", flags => "manual_ra|state" } ], flags => [ - { name => "eflags", type => 4 }, - { mode => "mode_Iu", flags => "manual_ra" } + { name => "eflags", type => 0 }, + { mode => "mode_Iu", flags => "manual_ra" } ], ); # %reg_classes @@ -213,6 +213,7 @@ $arch = "ia32"; D3 => "${arch}_emit_dest_register(env, node, 3);", D4 => "${arch}_emit_dest_register(env, node, 4);", D5 => "${arch}_emit_dest_register(env, node, 5);", + DB0 => "${arch}_emit_8bit_dest_register(env, node, 0);", X0 => "${arch}_emit_x87_name(env, node, 0);", X1 => "${arch}_emit_x87_name(env, node, 1);", X2 => "${arch}_emit_x87_name(env, node, 2);", @@ -232,8 +233,10 @@ $arch = "ia32"; unop5 => "${arch}_emit_unop(env, node, 5);", DAM0 => "${arch}_emit_am_or_dest_register(env, node, 0);", DAM1 => "${arch}_emit_am_or_dest_register(env, node, 1);", - binop => "${arch}_emit_binop(env, node);", + binop => "${arch}_emit_binop(env, node, 1);", + binop_nores => "${arch}_emit_binop(env, node, 0);", x87_binop => "${arch}_emit_x87_binop(env, node);", + CMP0 => "${arch}_emit_cmp_suffix_node(env, node, 0);", ); #--------------------------------------------------# @@ -309,6 +312,7 @@ $custom_init_attr_func = \&ia32_custom_init_attr; $mode_xmm = "mode_E"; $mode_gp = "mode_Iu"; +$mode_flags = "mode_Iu"; $mode_fpcw = "mode_fpcw"; $status_flags = [ "CF", "PF", "AF", "ZF", "SF", "OF" ]; $fpcw_flags = [ "FP_IM", "FP_DM", "FP_ZM", "FP_OM", "FP_UM", "FP_PM", @@ -380,6 +384,16 @@ AddMem => { modified_flags => $status_flags }, +AddMem8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => ". add%M %SB3, %AM", + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Adc => { reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], out => [ "in_r4" ] }, ins => [ "base", "index", "mem", "left", "right", "eflags" ], @@ -492,6 +506,16 @@ AndMem => { modified_flags => $status_flags }, +AndMem8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. and%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Or => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4" ] }, @@ -513,6 +537,16 @@ OrMem => { modified_flags => $status_flags }, +OrMem8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. or%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + Xor => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4" ] }, @@ -534,6 +568,16 @@ XorMem => { modified_flags => $status_flags }, +XorMem8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. xor%M %SB3, %AM', + units => [ "GP" ], + mode => "mode_M", + modified_flags => $status_flags +}, + # not commutative operations Sub => { @@ -557,6 +601,16 @@ SubMem => { modified_flags => $status_flags }, +SubMem8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] }, + ins => [ "base", "index", "mem", "val" ], + emit => '. sub%M %SB3, %AM', + units => [ "GP" ], + mode => 'mode_M', + modified_flags => $status_flags +}, + Sbb => { reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 !in_r5" ] }, ins => [ "base", "index", "mem", "left", "right" ], @@ -897,55 +951,106 @@ NotMem => { # other operations -CmpJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "none", "none"] }, +Cmp => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "false", "true" ], - attr => "long pnc", + outs => [ "eflags" ], am => "source,binary", - init_attr => "attr->pn_code = pnc;", - latency => 3, - units => [ "BRANCH" ], + emit => '. cmp%M %binop_nores', + attr => "int flipped, int cmp_unsigned", + init_attr => "attr->data.cmp_flipped = flipped;\n". + "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags }, -CmpJmp8Bit => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "none", "none"] }, +Cmp8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "false", "true" ], - attr => "long pnc", + outs => [ "eflags" ], am => "source,binary", - init_attr => "attr->pn_code = pnc;", - latency => 3, - units => [ "BRANCH" ], + emit => '. cmpb %binop_nores', + attr => "int flipped, int cmp_unsigned", + init_attr => "attr->data.cmp_flipped = flipped;\n". + "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags }, -TestJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "none", "none" ] }, +Test => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] }, ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "false", "true" ], - attr => "long pnc", + outs => [ "eflags" ], am => "source,binary", + emit => '. test%M %binop_nores', + attr => "int flipped, int cmp_unsigned", + init_attr => "attr->data.cmp_flipped = flipped;\n". + "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags +}, + +Test8Bit => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] }, + ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "eflags" ], + am => "source,binary", + emit => '. testb %binop_nores', + attr => "int flipped, int cmp_unsigned", + init_attr => "attr->data.cmp_flipped = flipped;\n". + "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + latency => 1, + units => [ "GP" ], + mode => $mode_flags, + modified_flags => $status_flags +}, + +Set => { + #irn_flags => "R", + reg_req => { in => [ "eflags" ], out => [ "eax ebx ecx edx" ] }, + ins => [ "eflags" ], + am => "dest,unary", + attr => "pn_Cmp pnc", init_attr => "attr->pn_code = pnc;", - latency => 3, - units => [ "BRANCH" ], + emit => '. set%CMP0 %DB0', + latency => 1, + units => [ "GP" ], + mode => $mode_gp, +}, + +CMov => { + #irn_flags => "R", + # (note: leave the false,true order intact to make it compatible with other + # ia32_binary ops) + reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "eflags" ], out => [ "in_r4" ] }, + ins => [ "base", "index", "mem", "val_false", "val_true", "eflags" ], + am => "source,binary", + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", + latency => 1, + units => [ "GP" ], + mode => $mode_gp, }, -TestJmp8Bit => { +Jcc => { state => "pinned", op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "none", "none" ] }, - ins => [ "base", "index", "mem", "left", "right" ], + reg_req => { in => [ "eflags" ], out => [ "none", "none" ] }, + ins => [ "eflags" ], outs => [ "false", "true" ], - attr => "long pnc", - am => "source,binary", + attr => "pn_Cmp pnc", init_attr => "attr->pn_code = pnc;", - latency => 3, + latency => 2, units => [ "BRANCH" ], }, @@ -956,6 +1061,7 @@ SwitchJmp => { latency => 3, units => [ "BRANCH" ], mode => "mode_T", + modified_flags => $status_flags }, IJmp => { @@ -975,6 +1081,8 @@ Const => { attr => "ir_entity *symconst, int symconst_sign, long offset", attr_type => "ia32_immediate_attr_t", mode => $mode_gp, +# depends on the const and is set in ia32_transform +# modified_flags => $status_flags }, Unknown_GP => { @@ -1144,6 +1252,9 @@ Lea => { latency => 2, units => [ "GP" ], mode => $mode_gp, +# well this isn't true for Lea, but we often transform Lea back to Add, Inc +# or Dec, so we set the flag + modified_flags => 1, }, Push => { @@ -1346,25 +1457,19 @@ xDiv => { # other operations -xCmp => { +Ucomi => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 !in_r5" ] }, + reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "eflags" ] }, ins => [ "base", "index", "mem", "left", "right" ], + outs => [ "flags" ], + am => "source,binary", + attr => "int flipped", + init_attr => "attr->data.cmp_flipped = flipped;", + emit => ' .ucomi%XXM %binop_nores', latency => 3, units => [ "SSE" ], - mode => "mode_E", -}, - -xCmpJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "none", "none" ] }, - ins => [ "base", "index", "mem", "left", "right" ], - outs => [ "false", "true" ], - attr => "long pnc", - init_attr => "attr->pn_code = pnc;", - latency => 5, - units => [ "SSE" ], + mode => $mode_flags, + modified_flags => 1, }, # Load / Store @@ -1469,7 +1574,6 @@ Conv_I2I => { attr => "ir_mode *smaller_mode", init_attr => "attr->ls_mode = smaller_mode;", mode => $mode_gp, - modified_flags => $status_flags }, Conv_I2I8Bit => { @@ -1480,7 +1584,6 @@ Conv_I2I8Bit => { attr => "ir_mode *smaller_mode", init_attr => "attr->ls_mode = smaller_mode;", mode => $mode_gp, - modified_flags => $status_flags }, Conv_I2FP => { @@ -1507,140 +1610,6 @@ Conv_FP2FP => { mode => "mode_E", }, -CmpCMov => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -CmpCMov8Bit => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -TestCMov => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -TestCMov8Bit => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -xCmpCMov => { - irn_flags => "R", - reg_req => { in => [ "xmm", "xmm", "gp", "gp" ], out => [ "in_r4" ] }, - latency => 5, - units => [ "SSE" ], - mode => $mode_gp, -}, - -vfCmpCMov => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "gp", "gp" ], out => [ "in_r7" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ], - latency => 10, - units => [ "VFP", "GP" ], - mode => $mode_gp, - attr_type => "ia32_x87_attr_t", -}, - -CmpSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -CmpSet8Bit => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -TestSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -TestSet8Bit => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ], - attr => "pn_Cmp pn_code", - init_attr => "attr->pn_code = pn_code;", - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -xCmpSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ], - latency => 5, - units => [ "SSE" ], - mode => $mode_gp, -}, - -vfCmpSet => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp" ], out => [ "eax ebx ecx edx" ] }, - ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ], - latency => 10, - units => [ "VFP" ], - mode => $mode_gp, - attr_type => "ia32_x87_attr_t", -}, - -vfCMov => { - irn_flags => "R", - reg_req => { in => [ "vfp", "vfp", "vfp", "vfp" ], out => [ "vfp" ] }, - latency => 10, - units => [ "VFP" ], - mode => "mode_E", - attr_type => "ia32_x87_attr_t", -}, - #----------------------------------------------------------# # _ _ _ __ _ _ # # (_) | | | | / _| | | | # @@ -1876,17 +1845,30 @@ vfldl2e => { # other -vfCmpJmp => { - state => "pinned", - op_flags => "L|X|Y", - reg_req => { in => [ "vfp", "vfp" ], out => [ "none", "none", "eax" ] }, +vFucomFnstsw => { +# we can't allow to rematerialize this node so we don't have +# accidently produce Phi(Fucom, Fucom(flipped)) +# irn_flags => "R", + reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] }, ins => [ "left", "right" ], - outs => [ "false", "true", "temp_reg_eax" ], - attr => "long pnc", - init_attr => "attr->attr.pn_code = pnc;", - latency => 10, + outs => [ "flags" ], + am => "source,binary", + attr => "int flipped", + init_attr => "attr->attr.data.cmp_flipped = flipped;", + latency => 3, units => [ "VFP" ], attr_type => "ia32_x87_attr_t", + mode => $mode_gp +}, + +Sahf => { + irn_flags => "R", + reg_req => { in => [ "eax" ], out => [ "eflags" ] }, + ins => [ "val" ], + outs => [ "flags" ], + emit => '. sahf', + units => [ "GP" ], + mode => $mode_flags, }, #------------------------------------------------------------------------# @@ -2217,39 +2199,27 @@ femms => { # compare -fcomJmp => { - op_flags => "L|X|Y", - reg_req => { }, - attr_type => "ia32_x87_attr_t", -}, - -fcompJmp => { - op_flags => "L|X|Y", - reg_req => { }, - attr_type => "ia32_x87_attr_t", -}, - -fcomppJmp => { - op_flags => "L|X|Y", - reg_req => { }, - attr_type => "ia32_x87_attr_t", -}, - -fcomrJmp => { - op_flags => "L|X|Y", +FucomFnstsw => { + op_flags => "R", reg_req => { }, + emit => ". fucom %X1\n". + ". fnstsw", attr_type => "ia32_x87_attr_t", }, -fcomrpJmp => { - op_flags => "L|X|Y", +FucompFnstsw => { + op_flags => "R", reg_req => { }, + emit => ". fucomp %X1\n". + ". fnstsw", attr_type => "ia32_x87_attr_t", }, -fcomrppJmp => { - op_flags => "L|X|Y", +FucomppFnstsw => { + op_flags => "R", reg_req => { }, + emit => ". fucompp\n". + ". fnstsw", attr_type => "ia32_x87_attr_t", }, diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 3ff3dc733..8144253bd 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -145,6 +145,8 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, static INLINE int mode_needs_gp_reg(ir_mode *mode) { if(mode == mode_fpcw) return 0; + if(get_mode_size_bits(mode) > 32) + return 0; return mode_is_int(mode) || mode_is_reference(mode) || mode == mode_b; } @@ -312,6 +314,10 @@ static ir_node *gen_Const(ir_node *node) { cnst = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, val); SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node)); + if(val == 0) { + set_ia32_flags(cnst, + get_ia32_flags(cnst) | arch_irn_flags_modify_flags); + } /* see above */ if (get_irg_start_block(irg) == block) { @@ -543,19 +549,31 @@ static void set_am_attributes(ir_node *node, ia32_address_mode_t *am) set_ia32_commutative(node); } +typedef enum { + match_commutative = 1 << 0, + match_am_and_immediates = 1 << 1, + match_no_am = 1 << 2, + match_8_16_bit_am = 1 << 3 +} match_flags_t; + static void match_arguments(ia32_address_mode_t *am, ir_node *block, - ir_node *op1, ir_node *op2, int commutative, - int use_am_and_immediates, int use_am, - int use_8_16_bit_am) + ir_node *op1, ir_node *op2, match_flags_t flags) { ia32_address_t *addr = &am->addr; ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg); ir_node *new_op1; ir_node *new_op2; + int use_am; + int commutative; + int use_am_and_immediates; memset(am, 0, sizeof(am[0])); - if(!use_8_16_bit_am && get_mode_size_bits(get_irn_mode(op1)) < 32) + commutative = (flags & match_commutative) != 0; + use_am_and_immediates = (flags & match_am_and_immediates) != 0; + use_am = ! (flags & match_no_am); + if(!(flags & match_8_16_bit_am) + && get_mode_size_bits(get_irn_mode(op1)) < 32) use_am = 0; new_op2 = try_create_Immediate(op2, 0); @@ -635,8 +653,12 @@ static ir_node *gen_binop(ir_node *node, ir_node *op1, ir_node *op2, ir_node *new_node; ia32_address_mode_t am; ia32_address_t *addr = &am.addr; + match_flags_t flags = 0; - match_arguments(&am, src_block, op1, op2, commutative, 0, 1, 0); + if(commutative) + flags |= match_commutative; + + match_arguments(&am, src_block, op1, op2, flags); new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem, am.new_op1, am.new_op2); @@ -1131,6 +1153,7 @@ static ir_node *generate_DivMod(ir_node *node, ir_node *dividend, produceval); } else { sign_extension = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, 0); + set_ia32_flags(sign_extension, get_ia32_flags(sign_extension) | arch_irn_flags_modify_flags); add_irn_dep(sign_extension, get_irg_frame(irg)); } @@ -1660,7 +1683,9 @@ static int use_dest_am(ir_node *block, ir_node *node, ir_node *mem, static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2, ir_node *mem, ir_node *ptr, ir_mode *mode, - construct_binop_dest_func *func, int commutative) + construct_binop_dest_func *func, + construct_binop_dest_func *func8bit, + int commutative) { ir_node *src_block = get_nodes_block(node); ir_node *block; @@ -1692,7 +1717,13 @@ static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2, dbgi = get_irn_dbg_info(node); block = be_transform_node(src_block); - new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem, new_op); + if(get_mode_size_bits(mode) == 8) { + new_node = func8bit(dbgi, irg, block, addr->base, addr->index, + addr->mem, new_op); + } else { + new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem, + new_op); + } set_address(new_node, addr); set_ia32_op_type(new_node, ia32_AddrModeD); set_ia32_ls_mode(new_node, mode); @@ -1751,10 +1782,6 @@ static ir_node *try_create_dest_am(ir_node *node) { if(!mode_needs_gp_reg(mode)) return NULL; - /* TODO0000 8bit operations have stricter constraints. This is not handled yet */ - if (get_mode_size_bits(mode) < 16) - return NULL; - /* store must be the only user of the val node */ if(get_irn_n_edges(val) > 1) return NULL; @@ -1773,55 +1800,59 @@ static ir_node *try_create_dest_am(ir_node *node) { break; } new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_AddMem, 1); + new_rd_ia32_AddMem, new_rd_ia32_AddMem8Bit, 1); break; case iro_Sub: op1 = get_Sub_left(val); op2 = get_Sub_right(val); + if(is_Const(op2)) { + ir_fprintf(stderr, "Optimisation warning: not-normalize sub ,C" + "found\n"); + } new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_SubMem, 0); + new_rd_ia32_SubMem, new_rd_ia32_SubMem8Bit, 0); break; case iro_And: op1 = get_And_left(val); op2 = get_And_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_AndMem, 1); + new_rd_ia32_AndMem, new_rd_ia32_AndMem8Bit, 1); break; case iro_Or: op1 = get_Or_left(val); op2 = get_Or_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_OrMem, 1); + new_rd_ia32_OrMem, new_rd_ia32_OrMem8Bit, 1); break; case iro_Eor: op1 = get_Eor_left(val); op2 = get_Eor_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_XorMem, 1); + new_rd_ia32_XorMem, new_rd_ia32_XorMem8Bit, 1); break; case iro_Shl: op1 = get_Shl_left(val); op2 = get_Shl_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_ShlMem, 0); + new_rd_ia32_ShlMem, new_rd_ia32_ShlMem, 0); break; case iro_Shr: op1 = get_Shr_left(val); op2 = get_Shr_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_ShrMem, 0); + new_rd_ia32_ShrMem, new_rd_ia32_ShrMem, 0); break; case iro_Shrs: op1 = get_Shrs_left(val); op2 = get_Shrs_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_SarMem, 0); + new_rd_ia32_SarMem, new_rd_ia32_SarMem, 0); break; case iro_Rot: op1 = get_Rot_left(val); op2 = get_Rot_right(val); new_node = dest_am_binop(val, op1, op2, mem, ptr, mode, - new_rd_ia32_RolMem, 0); + new_rd_ia32_RolMem, new_rd_ia32_RolMem, 0); break; /* TODO: match ROR patterns... */ case iro_Minus: @@ -1829,9 +1860,8 @@ static ir_node *try_create_dest_am(ir_node *node) { new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NegMem); break; case iro_Not: - /* TODO this would be ^ 1 with DestAM */ - if(mode == mode_b) - return NULL; + /* should be lowered already */ + assert(mode != mode_b); op1 = get_Not_op(val); new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NotMem); break; @@ -1920,56 +1950,6 @@ static ir_node *gen_Store(ir_node *node) { return new_op; } -static ir_node *try_create_TestJmp(ir_node *block, dbg_info *dbgi, long pnc, - ir_node *cmp_left, ir_node *cmp_right, - int use_am) -{ - ir_node *arg_left; - ir_node *arg_right; - ir_node *res; - ir_mode *mode; - long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned; - ia32_address_mode_t am; - ia32_address_t *addr = &am.addr; - - if(cmp_right != NULL && !is_Const_0(cmp_right)) - return NULL; - - if(is_And(cmp_left) && (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) { - mode = get_irn_mode(cmp_left); - arg_left = get_And_left(cmp_left); - arg_right = get_And_right(cmp_left); - } else { - mode = get_irn_mode(cmp_left); - arg_left = cmp_left; - arg_right = cmp_left; - } - - if(mode == mode_b) - mode = mode_Iu; - - assert(get_mode_size_bits(mode) <= 32); - match_arguments(&am, block, arg_left, arg_right, 1, 1, use_am, 1); - if(am.flipped) - pnc = get_inversed_pnc(pnc); - - if(get_mode_size_bits(mode) == 8) { - res = new_rd_ia32_TestJmp8Bit(dbgi, current_ir_graph, block, addr->base, - addr->index, addr->mem, am.new_op1, - am.new_op2, pnc); - } else { - res = new_rd_ia32_TestJmp(dbgi, current_ir_graph, block, addr->base, - addr->index, addr->mem, am.new_op1, am.new_op2, - pnc); - } - set_am_attributes(res, &am); - set_ia32_ls_mode(res, mode); - - res = fix_mem_proj(res, &am); - - return res; -} - static ir_node *create_Switch(ir_node *node) { ir_graph *irg = current_ir_graph; @@ -2010,95 +1990,57 @@ static ir_node *create_Switch(ir_node *node) return res; } -/** - * Transforms a Cond -> Proj[b] -> Cmp into a CondJmp, CondJmp_i or TestJmp - * - * @return The transformed node. - */ +static ir_node *get_flags_node(ir_node *node, pn_Cmp *pnc_out) +{ + ir_graph *irg = current_ir_graph; + ir_node *flags; + ir_node *new_op; + ir_node *noreg; + ir_node *nomem; + ir_node *new_block; + dbg_info *dbgi; + + /* we have a Cmp as input */ + if(is_Proj(node)) { + ir_node *pred = get_Proj_pred(node); + if(is_Cmp(pred)) { + flags = be_transform_node(pred); + *pnc_out = get_Proj_proj(node); + return flags; + } + } + + /* a mode_b value, we have to compare it against 0 */ + dbgi = get_irn_dbg_info(node); + new_block = be_transform_node(get_nodes_block(node)); + new_op = be_transform_node(node); + noreg = ia32_new_NoReg_gp(env_cg); + nomem = new_NoMem(); + flags = new_rd_ia32_Test(dbgi, irg, new_block, noreg, noreg, nomem, + new_op, new_op, 0, 0); + *pnc_out = pn_Cmp_Lg; + return flags; +} + static ir_node *gen_Cond(ir_node *node) { - ir_node *src_block = get_nodes_block(node); - ir_node *block = be_transform_node(src_block); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); ir_node *sel = get_Cond_selector(node); ir_mode *sel_mode = get_irn_mode(sel); - ir_node *res = NULL; - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - ir_node *cmp; - ir_node *cmp_a; - ir_node *cmp_b; - ir_node *new_cmp_a; - ir_node *new_cmp_b; - ir_mode *cmp_mode; - long pnc; - int use_am; + ir_node *res; + ir_node *flags = NULL; + pn_Cmp pnc; if (sel_mode != mode_b) { return create_Switch(node); } - if(!is_Proj(sel) || !is_Cmp(get_Proj_pred(sel))) { - /* it's some mode_b value but not a direct comparison -> create a - * testjmp */ - res = try_create_TestJmp(block, dbgi, pn_Cmp_Lg, sel, NULL, 1); - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); - return res; - } - - /* address mode makes only sense when we're the only user of the cmp */ - use_am = get_irn_n_edges(node) <= 1; - - cmp = get_Proj_pred(sel); - cmp_a = get_Cmp_left(cmp); - cmp_b = get_Cmp_right(cmp); - cmp_mode = get_irn_mode(cmp_a); - pnc = get_Proj_proj(sel); - if(mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) { - pnc |= ia32_pn_Cmp_Unsigned; - } - - if(mode_needs_gp_reg(cmp_mode)) { - res = try_create_TestJmp(block, dbgi, pnc, cmp_a, cmp_b, use_am); - if(res != NULL) { - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); - return res; - } - } - - if (mode_is_float(cmp_mode)) { - new_cmp_a = be_transform_node(cmp_a); - new_cmp_b = create_immediate_or_transform(cmp_b, 0); - if (USE_SSE2(env_cg)) { - res = new_rd_ia32_xCmpJmp(dbgi, irg, block, noreg, noreg, nomem, cmp_a, - cmp_b, pnc); - set_ia32_commutative(res); - set_ia32_ls_mode(res, cmp_mode); - } else { - res = new_rd_ia32_vfCmpJmp(dbgi, irg, block, cmp_a, cmp_b, pnc); - set_ia32_commutative(res); - } - } else { - ia32_address_mode_t am; - ia32_address_t *addr = &am.addr; - match_arguments(&am, src_block, cmp_a, cmp_b, 1, 1, use_am, 1); - if(am.flipped) - pnc = get_inversed_pnc(pnc); - - if(get_mode_size_bits(cmp_mode) == 8) { - res = new_rd_ia32_CmpJmp8Bit(dbgi, irg, block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, pnc); - } else { - res = new_rd_ia32_CmpJmp(dbgi, irg, block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, pnc); - } - set_am_attributes(res, &am); - assert(cmp_mode != NULL); - set_ia32_ls_mode(res, cmp_mode); - - res = fix_mem_proj(res, &am); - } + /* we get flags from a cmp */ + flags = get_flags_node(sel, &pnc); + res = new_rd_ia32_Jcc(dbgi, irg, new_block, flags, pnc); SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); return res; @@ -2132,6 +2074,11 @@ static ir_node *gen_CopyB(ir_node *node) { size >>= 2; res = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, size); + if(size == 0) { + ir_fprintf(stderr, "Optimisation warning copyb %+F with size <4\n", + node); + set_ia32_flags(res, get_ia32_flags(res) | arch_irn_flags_modify_flags); + } add_irn_dep(res, get_irg_frame(irg)); res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem); @@ -2147,8 +2094,7 @@ static ir_node *gen_CopyB(ir_node *node) { return res; } -static -ir_node *gen_be_Copy(ir_node *node) +static ir_node *gen_be_Copy(ir_node *node) { ir_node *result = be_duplicate_node(node); ir_mode *mode = get_irn_mode(result); @@ -2160,226 +2106,266 @@ ir_node *gen_be_Copy(ir_node *node) return result; } +/** + * helper function: checks wether all Cmp projs are Lg or Eq which is needed + * to fold an and into a test node + */ +static int can_fold_test_and(ir_node *node) +{ + const ir_edge_t *edge; -static ir_node *create_set(long pnc, ir_node *cmp_left, ir_node *cmp_right, - dbg_info *dbgi, ir_node *block, int use_am) + /** we can only have eq and lg projs */ + foreach_out_edge(node, edge) { + ir_node *proj = get_edge_src_irn(edge); + pn_Cmp pnc = get_Proj_proj(proj); + if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) + return 0; + } + + return 1; +} + +static ir_node *try_create_Test(ir_node *node) { ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); ir_node *new_block = be_transform_node(block); - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_rd_NoMem(irg); + ir_node *cmp_left = get_Cmp_left(node); + ir_node *cmp_right = get_Cmp_right(node); ir_mode *mode; - ir_node *arg_left; - ir_node *arg_right; + ir_node *left; + ir_node *right; ir_node *res; ia32_address_mode_t am; ia32_address_t *addr = &am.addr; + int cmp_unsigned; /* can we use a test instruction? */ - if(cmp_right == NULL || is_Const_0(cmp_right)) { - long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned; - if(is_And(cmp_left) && - (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) { - ir_node *and_left = get_And_left(cmp_left); - ir_node *and_right = get_And_right(cmp_left); - - mode = get_irn_mode(and_left); - arg_left = and_left; - arg_right = and_right; - } else { - mode = get_irn_mode(cmp_left); - arg_left = cmp_left; - arg_right = cmp_left; - } - - assert(get_mode_size_bits(mode) <= 32); - - match_arguments(&am, block, arg_left, arg_right, 1, 1, use_am, 1); - if(am.flipped) - pnc = get_inversed_pnc(pnc); - - if(get_mode_size_bits(mode) == 8) { - res = new_rd_ia32_TestSet8Bit(dbgi, irg, new_block, addr->base, - addr->index, addr->mem, am.new_op1, - am.new_op2, pnc); - } else { - res = new_rd_ia32_TestSet(dbgi, irg, new_block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, pnc); - } - set_am_attributes(res, &am); - set_ia32_ls_mode(res, mode); - - res = fix_mem_proj(res, &am); + if(!is_Const_0(cmp_right)) + return NULL; - res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, nomem, - res, mode_Bu); + if(is_And(cmp_left) && can_fold_test_and(node)) { + ir_node *and_left = get_And_left(cmp_left); + ir_node *and_right = get_And_right(cmp_left); - return res; + mode = get_irn_mode(and_left); + left = and_left; + right = and_right; + } else { + mode = get_irn_mode(cmp_left); + left = cmp_left; + right = cmp_left; } - mode = get_irn_mode(cmp_left); assert(get_mode_size_bits(mode) <= 32); - match_arguments(&am, block, cmp_left, cmp_right, 1, 1, use_am, 1); - if(am.flipped) - pnc = get_inversed_pnc(pnc); + match_arguments(&am, block, left, right, match_commutative | + match_8_16_bit_am | match_am_and_immediates); + cmp_unsigned = !mode_is_signed(mode); if(get_mode_size_bits(mode) == 8) { - res = new_rd_ia32_CmpSet8Bit(dbgi, irg, new_block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, pnc); + res = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base, + addr->index, addr->mem, am.new_op1, + am.new_op2, am.flipped, cmp_unsigned); } else { - res = new_rd_ia32_CmpSet(dbgi, irg, new_block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, pnc); + res = new_rd_ia32_Test(dbgi, irg, new_block, addr->base, addr->index, + addr->mem, am.new_op1, am.new_op2, am.flipped, + cmp_unsigned); } set_am_attributes(res, &am); + assert(mode != NULL); set_ia32_ls_mode(res, mode); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + res = fix_mem_proj(res, &am); + return res; +} - res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, nomem, res, - mode_Bu); +static ir_node *create_Fucom(ir_node *node) +{ + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_node *left = get_Cmp_left(node); + ir_node *new_left = be_transform_node(left); + ir_node *right = get_Cmp_right(node); + ir_node *new_right = be_transform_node(right); + ir_node *res; + + res = new_rd_ia32_vFucomFnstsw(dbgi, irg, new_block, new_left, new_right, + 0); + set_ia32_commutative(res); + + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + + res = new_rd_ia32_Sahf(dbgi, irg, new_block, res); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); return res; } -static ir_node *create_cmov(long pnc, ir_node *cmp_left, ir_node *cmp_right, - ir_node *val_true, ir_node *val_false, - dbg_info *dbgi, ir_node *block) +static ir_node *create_Ucomi(ir_node *node) { - ir_graph *irg = current_ir_graph; - ir_node *new_block = be_transform_node(block); - ir_node *new_val_true = be_transform_node(val_true); - ir_node *new_val_false = be_transform_node(val_false); - ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *nomem = new_NoMem(); - ir_node *new_cmp_left; - ir_node *new_cmp_right; + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_node *left = get_Cmp_left(node); + ir_node *new_left = be_transform_node(left); + ir_node *right = get_Cmp_right(node); + ir_node *new_right = be_transform_node(right); + ir_mode *mode = get_irn_mode(left); + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_NoMem(); ir_node *res; - ir_mode *mode; - /* cmovs with unknowns are pointless... */ - if(is_Unknown(val_true)) { -#ifdef DEBUG_libfirm - ir_fprintf(stderr, "Optimisation warning: psi with unknown operand\n"); -#endif - return new_val_false; - } - if(is_Unknown(val_false)) { -#ifdef DEBUG_libfirm - ir_fprintf(stderr, "Optimisation warning: psi with unknown operand\n"); -#endif - return new_val_true; - } + res = new_rd_ia32_Ucomi(dbgi, irg, new_block, noreg, noreg, nomem, new_left, + new_right, 0); + set_ia32_commutative(res); + set_ia32_ls_mode(res, mode); - /* can we use a test instruction? */ - if(is_Const_0(cmp_right)) { - long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned; - if(is_And(cmp_left) && - (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) { - ir_node *and_left = get_And_left(cmp_left); - ir_node *and_right = get_And_right(cmp_left); - - mode = get_irn_mode(and_left); - new_cmp_left = be_transform_node(and_left); - new_cmp_right = create_immediate_or_transform(and_right, 0); - } else { - mode = get_irn_mode(cmp_left); - new_cmp_left = be_transform_node(cmp_left); - new_cmp_right = be_transform_node(cmp_left); - } + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); - assert(get_mode_size_bits(mode) <= 32); + return res; +} - if(get_mode_size_bits(mode) == 8) { - res = new_rd_ia32_TestCMov8Bit(dbgi, current_ir_graph, new_block, noreg, - noreg, nomem, new_cmp_left, new_cmp_right, - new_val_true, new_val_false, pnc); +static ir_node *gen_Cmp(ir_node *node) +{ + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_node *left = get_Cmp_left(node); + ir_node *right = get_Cmp_right(node); + ir_mode *cmp_mode = get_irn_mode(left); + ir_node *res; + ia32_address_mode_t am; + ia32_address_t *addr = &am.addr; + int cmp_unsigned; + + if(mode_is_float(cmp_mode)) { + if (USE_SSE2(env_cg)) { + return create_Ucomi(node); } else { - res = new_rd_ia32_TestCMov(dbgi, current_ir_graph, new_block, noreg, - noreg, nomem, new_cmp_left, new_cmp_right, - new_val_true, new_val_false, pnc); + return create_Fucom(node); } - set_ia32_ls_mode(res, mode); - - return res; } - mode = get_irn_mode(cmp_left); - new_cmp_left = be_transform_node(cmp_left); - new_cmp_right = create_immediate_or_transform(cmp_right, 0); + assert(mode_needs_gp_reg(cmp_mode)); - /* no support for 8,16 bit modes yet */ - assert(get_mode_size_bits(mode) <= 32); + /* we prefer the Test instruction where possible except cases where + * we can use SourceAM */ + if(!use_source_address_mode(block, left, right) && + !use_source_address_mode(block, right, left)) { + res = try_create_Test(node); + if(res != NULL) + return res; + } - if(get_mode_size_bits(mode) == 8) { - res = new_rd_ia32_CmpCMov8Bit(dbgi, irg, new_block, noreg, noreg, nomem, - new_cmp_left, new_cmp_right, new_val_true, - new_val_false, pnc); + match_arguments(&am, block, left, right, + match_commutative | match_8_16_bit_am | + match_am_and_immediates); + + cmp_unsigned = !mode_is_signed(get_irn_mode(left)); + if(get_mode_size_bits(cmp_mode) == 8) { + res = new_rd_ia32_Cmp8Bit(dbgi, irg, new_block, addr->base, addr->index, + addr->mem, am.new_op1, am.new_op2, + am.flipped, cmp_unsigned); } else { - res = new_rd_ia32_CmpCMov(dbgi, irg, new_block, noreg, noreg, nomem, - new_cmp_left, new_cmp_right, new_val_true, - new_val_false, pnc); + res = new_rd_ia32_Cmp(dbgi, irg, new_block, addr->base, addr->index, + addr->mem, am.new_op1, am.new_op2, am.flipped, + cmp_unsigned); } - set_ia32_ls_mode(res, mode); + set_am_attributes(res, &am); + assert(cmp_mode != NULL); + set_ia32_ls_mode(res, cmp_mode); + + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + + res = fix_mem_proj(res, &am); return res; } +static ir_node *create_CMov(ir_node *node, ir_node *new_flags, pn_Cmp pnc) +{ + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_node *val_true = get_Psi_val(node, 0); + ir_node *new_val_true = be_transform_node(val_true); + ir_node *val_false = get_Psi_default(node); + ir_node *new_val_false = be_transform_node(val_false); + ir_mode *mode = get_irn_mode(node); + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_NoMem(); + ir_node *res; + + assert(mode_needs_gp_reg(mode)); + + res = new_rd_ia32_CMov(dbgi, irg, new_block, noreg, noreg, nomem, + new_val_false, new_val_true, new_flags, pnc); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + + return res; +} + + + +static ir_node *create_set_32bit(dbg_info *dbgi, ir_node *new_block, + ir_node *flags, pn_Cmp pnc, ir_node *orig_node) +{ + ir_graph *irg = current_ir_graph; + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_NoMem(); + ir_node *res; + + res = new_rd_ia32_Set(dbgi, irg, new_block, flags, pnc); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, orig_node)); + res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, + nomem, res, mode_Bu); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, orig_node)); + + return res; +} /** * Transforms a Psi node into CMov. * * @return The transformed node. */ -static ir_node *gen_Psi(ir_node *node) { +static ir_node *gen_Psi(ir_node *node) +{ + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); ir_node *psi_true = get_Psi_val(node, 0); ir_node *psi_default = get_Psi_default(node); - ia32_code_gen_t *cg = env_cg; ir_node *cond = get_Psi_cond(node, 0); - ir_node *block = get_nodes_block(node); - dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *new_op; - ir_node *cmp_left; - ir_node *cmp_right; + ir_node *flags = NULL; + ir_node *res; ir_mode *cmp_mode; - long pnc; + pn_Cmp pnc; assert(get_Psi_n_conds(node) == 1); assert(get_irn_mode(cond) == mode_b); assert(mode_needs_gp_reg(get_irn_mode(node))); - if(!is_Proj(cond) || !is_Cmp(get_Proj_pred(cond))) { - /* a mode_b value, we have to compare it against 0 */ - cmp_left = cond; - cmp_right = new_Const_long(mode_Iu, 0); - pnc = pn_Cmp_Lg; - cmp_mode = mode_Iu; - } else { - ir_node *cmp = get_Proj_pred(cond); - - cmp_left = get_Cmp_left(cmp); - cmp_right = get_Cmp_right(cmp); - cmp_mode = get_irn_mode(cmp_left); - pnc = get_Proj_proj(cond); - - assert(!mode_is_float(cmp_mode)); - - if (!mode_is_signed(cmp_mode)) { - pnc |= ia32_pn_Cmp_Unsigned; - } - } + flags = get_flags_node(cond, &pnc); if(is_Const_1(psi_true) && is_Const_0(psi_default)) { - new_op = create_set(pnc, cmp_left, cmp_right, dbgi, block, 1); + res = create_set_32bit(dbgi, new_block, flags, pnc, node); } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) { pnc = get_negated_pnc(pnc, cmp_mode); - new_op = create_set(pnc, cmp_left, cmp_right, dbgi, block, 1); + res = create_set_32bit(dbgi, new_block, flags, pnc, node); } else { - new_op = create_cmov(pnc, cmp_left, cmp_right, psi_true, psi_default, - dbgi, block); + res = create_CMov(node, flags, pnc); } - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node)); - return new_op; + return res; } @@ -2720,8 +2706,7 @@ static ir_node *gen_Conv(ir_node *node) { return res; } -static -int check_immediate_constraint(long val, char immediate_constraint_type) +static int check_immediate_constraint(long val, char immediate_constraint_type) { switch (immediate_constraint_type) { case 0: @@ -2747,8 +2732,8 @@ int check_immediate_constraint(long val, char immediate_constraint_type) return 0; } -static -ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type) +static ir_node *try_create_Immediate(ir_node *node, + char immediate_constraint_type) { int minus = 0; tarval *offset = NULL; @@ -2833,6 +2818,10 @@ ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type) return NULL; } + /* unfortunately the assembler/linker doesn't support -symconst */ + if(symconst_sign) + return NULL; + if(get_SymConst_kind(symconst) != symconst_addr_ent) return NULL; symconst_ent = get_SymConst_entity(symconst); @@ -2854,8 +2843,8 @@ ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type) return res; } -static -ir_node *create_immediate_or_transform(ir_node *node, char immediate_constraint_type) +static ir_node *create_immediate_or_transform(ir_node *node, + char immediate_constraint_type) { ir_node *new_node = try_create_Immediate(node, immediate_constraint_type); if (new_node == NULL) { @@ -3108,9 +3097,8 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) constraint->immediate_type = immediate_type; } -static -void parse_clobber(ir_node *node, int pos, constraint_t *constraint, - const char *c) +static void parse_clobber(ir_node *node, int pos, constraint_t *constraint, + const char *c) { (void) node; (void) pos; @@ -3626,7 +3614,7 @@ static ir_node *gen_ia32_l_Adc(ir_node *node) { ia32_address_mode_t am; ia32_address_t *addr = &am.addr; - match_arguments(&am, src_block, op1, op2, 1, 0, 1, 0); + match_arguments(&am, src_block, op1, op2, match_commutative); new_node = new_rd_ia32_Adc(dbgi, irg, block, addr->base, addr->index, addr->mem, am.new_op1, am.new_op2, new_flags); @@ -4273,6 +4261,20 @@ static ir_node *gen_Proj_tls(ir_node *node) { return res; } +static ir_node *gen_be_Call(ir_node *node) { + ir_node *res = be_duplicate_node(node); + be_node_add_flags(res, -1, arch_irn_flags_modify_flags); + + return res; +} + +static ir_node *gen_be_IncSP(ir_node *node) { + ir_node *res = be_duplicate_node(node); + be_node_add_flags(res, -1, arch_irn_flags_modify_flags); + + return res; +} + /** * Transform the Projs from a be_Call. */ @@ -4366,30 +4368,15 @@ static ir_node *gen_Proj_Cmp(ir_node *node) { /* normally Cmps are processed when looking at Cond nodes, but this case * can happen in complicated Psi conditions */ - + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); ir_node *cmp = get_Proj_pred(node); + ir_node *new_cmp = be_transform_node(cmp); long pnc = get_Proj_proj(node); - ir_node *cmp_left = get_Cmp_left(cmp); - ir_node *cmp_right = get_Cmp_right(cmp); - ir_mode *cmp_mode = get_irn_mode(cmp_left); - dbg_info *dbgi = get_irn_dbg_info(cmp); - ir_node *block = get_nodes_block(node); ir_node *res; - int use_am; - - assert(!mode_is_float(cmp_mode)); - - if(!mode_is_signed(cmp_mode)) { - pnc |= ia32_pn_Cmp_Unsigned; - } - - /** - * address mode makes only sense when we'll be the only node using the cmp - */ - use_am = get_irn_n_edges(cmp) <= 1; - res = create_set(pnc, cmp_left, cmp_right, dbgi, block, use_am); - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, cmp)); + res = create_set_32bit(dbgi, new_block, new_cmp, pnc, node); return res; } @@ -4502,6 +4489,7 @@ static void register_transformers(void) GEN(Store); GEN(Cond); + GEN(Cmp); GEN(ASM); GEN(CopyB); BAD(Mux); @@ -4556,7 +4544,8 @@ static void register_transformers(void) /* handle generic backend nodes */ GEN(be_FrameAddr); - //GEN(be_Call); + GEN(be_Call); + GEN(be_IncSP); GEN(be_Return); GEN(be_AddSP); GEN(be_SubSP); @@ -4589,8 +4578,7 @@ static void ia32_pretransform_node(void *arch_cg) { * Walker, checks if all ia32 nodes producing more than one result have * its Projs, other wise creates new projs and keep them using a be_Keep node. */ -static -void add_missing_keep_walker(ir_node *node, void *data) +static void add_missing_keep_walker(ir_node *node, void *data) { int n_outs, i; unsigned found_projs = 0; diff --git a/ir/be/ia32/ia32_x87.c b/ir/be/ia32/ia32_x87.c index 50ffd35d2..7e7565bb4 100644 --- a/ir/be/ia32/ia32_x87.c +++ b/ir/be/ia32/ia32_x87.c @@ -1330,27 +1330,27 @@ GEN_STORE(fst) GEN_STORE(fist) /** - * Simulate a fCondJmp. - * * @param state the x87 state * @param n the node that should be simulated (and patched) * * @return NO_NODE_ADDED */ -static int sim_fCmpJmp(x87_state *state, ir_node *n) { +static int sim_FucomFnstsw(x87_state *state, ir_node *n) { int op1_idx; int op2_idx = -1; int pop_cnt = 0; - ia32_x87_attr_t *attr; + ia32_x87_attr_t *attr = get_ia32_x87_attr(n); ir_op *dst; x87_simulator *sim = state->sim; - ir_node *op1_node = get_irn_n(n, n_ia32_vfCmpJmp_left); - ir_node *op2_node = get_irn_n(n, n_ia32_vfCmpJmp_right); + ir_node *op1_node = get_irn_n(n, n_ia32_vFucomFnstsw_left); + ir_node *op2_node = get_irn_n(n, n_ia32_vFucomFnstsw_right); const arch_register_t *op1 = x87_get_irn_register(sim, op1_node); const arch_register_t *op2 = x87_get_irn_register(sim, op2_node); int reg_index_1 = arch_register_get_index(op1); int reg_index_2 = arch_register_get_index(op2); unsigned live = vfp_live_args_after(sim, n, 0); + int flipped = attr->attr.data.cmp_flipped; + int xchg = 0; DB((dbg, LEVEL_1, ">>> %+F %s, %s\n", n, arch_register_get_name(op1), arch_register_get_name(op2))); @@ -1375,10 +1375,12 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { if (op1_idx == 0) { /* res = tos X op */ - dst = op_ia32_fcomJmp; + dst = op_ia32_FucomFnstsw; } else if (op2_idx == 0) { /* res = op X tos */ - dst = op_ia32_fcomrJmp; + dst = op_ia32_FucomFnstsw; + flipped = !flipped; + xchg = 1; } else { /* bring the first one to tos */ x87_create_fxch(state, n, op1_idx); @@ -1386,7 +1388,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { op2_idx = op1_idx; op1_idx = 0; /* res = tos X op */ - dst = op_ia32_fcomJmp; + dst = op_ia32_FucomFnstsw; } } else { /* second live, first operand is dead here, bring it to tos. @@ -1399,7 +1401,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { op1_idx = 0; } /* res = tos X op, pop */ - dst = op_ia32_fcompJmp; + dst = op_ia32_FucompFnstsw; pop_cnt = 1; } } else { @@ -1415,7 +1417,9 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { op2_idx = 0; } /* res = op X tos, pop */ - dst = op_ia32_fcomrpJmp; + dst = op_ia32_FucompFnstsw; + flipped = !flipped; + xchg = 1; pop_cnt = 1; } else { /* both operands are dead here, check first for identity. */ @@ -1427,7 +1431,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { op2_idx = 0; } /* res = tos X op, pop */ - dst = op_ia32_fcompJmp; + dst = op_ia32_FucompFnstsw; pop_cnt = 1; } /* different, move them to st and st(1) and pop both. @@ -1441,7 +1445,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { op1_idx = 0; } /* res = tos X op, pop, pop */ - dst = op_ia32_fcomppJmp; + dst = op_ia32_FucomppFnstsw; pop_cnt = 2; } else if (op1_idx == 1) { /* good, first operand is already in the right place, move the second */ @@ -1451,7 +1455,10 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { assert(op1_idx != 0); op2_idx = 0; } - dst = op_ia32_fcomrppJmp; + /* res = op X tos, pop, pop */ + dst = op_ia32_FucomppFnstsw; + flipped = !flipped; + xchg = 1; pop_cnt = 2; } else { /* if one is already the TOS, we need two fxch */ @@ -1463,7 +1470,9 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { x87_create_fxch(state, n, op2_idx); op2_idx = 0; /* res = op X tos, pop, pop */ - dst = op_ia32_fcomrppJmp; + dst = op_ia32_FucomppFnstsw; + flipped = !flipped; + xchg = 1; pop_cnt = 2; } else if (op2_idx == 0) { /* second one is TOS, move to st(1) */ @@ -1473,7 +1482,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { x87_create_fxch(state, n, op1_idx); op1_idx = 0; /* res = tos X op, pop, pop */ - dst = op_ia32_fcomppJmp; + dst = op_ia32_FucomppFnstsw; pop_cnt = 2; } else { /* none of them is either TOS or st(1), 3 fxch needed */ @@ -1484,7 +1493,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { x87_create_fxch(state, n, op1_idx); op1_idx = 0; /* res = tos X op, pop, pop */ - dst = op_ia32_fcomppJmp; + dst = op_ia32_FucomppFnstsw; pop_cnt = 2; } } @@ -1498,14 +1507,14 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { x87_create_fxch(state, n, op1_idx); op1_idx = 0; } - dst = op_ia32_fcomJmp; + dst = op_ia32_FucomFnstsw; } else { /* first operand is dead: bring it to tos */ if (op1_idx != 0) { x87_create_fxch(state, n, op1_idx); op1_idx = 0; } - dst = op_ia32_fcompJmp; + dst = op_ia32_FucompFnstsw; pop_cnt = 1; } } @@ -1517,8 +1526,13 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { if (pop_cnt >= 1) x87_pop(state); + if(xchg) { + int tmp = op1_idx; + op1_idx = op2_idx; + op2_idx = tmp; + } + /* patch the operation */ - attr = get_ia32_x87_attr(n); op1 = &ia32_st_regs[op1_idx]; attr->x87[0] = op1; if (op2_idx >= 0) { @@ -1526,6 +1540,7 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { attr->x87[1] = op2; } attr->x87[2] = NULL; + attr->attr.data.cmp_flipped = flipped; if (op2_idx >= 0) DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(n), @@ -1535,10 +1550,9 @@ static int sim_fCmpJmp(x87_state *state, ir_node *n) { arch_register_get_name(op1))); return NO_NODE_ADDED; -} /* sim_fCondJmp */ +} -static -int sim_Keep(x87_state *state, ir_node *node) +static int sim_Keep(x87_state *state, ir_node *node) { const ir_node *op; const arch_register_t *op_reg; @@ -2255,7 +2269,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, ASSOC_IA32(fchs); ASSOC_IA32(fist); ASSOC_IA32(fst); - ASSOC_IA32(fCmpJmp); + ASSOC_IA32(FucomFnstsw); ASSOC_BE(Copy); ASSOC_BE(Call); ASSOC_BE(Spill); -- 2.20.1