From: Matthias Braun Date: Thu, 17 Feb 2011 00:13:53 +0000 (+0000) Subject: reworked ia32 condition code handling, remove backend Bound support (really someone... X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=ef7ac8eec7325a927785c27ab0224ba521b0ad81;p=libfirm reworked ia32 condition code handling, remove backend Bound support (really someone should lower it before the backend [r28386] --- diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 4667d3a34..009d0718a 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -24,12 +24,14 @@ * @version $Id$ * * Summary table for x86 floatingpoint compares: + * (remember effect of unordered on x86: ZF=1, PF=1, CF=1) + * * pnc_Eq => !P && E * pnc_Lt => !P && B * pnc_Le => !P && BE * pnc_Gt => A * pnc_Ge => AE - * pnc_Lg => P || NE + * pnc_Lg => NE * pnc_Leg => NP (ordered) * pnc_Uo => P * pnc_Ue => E @@ -37,7 +39,7 @@ * pnc_Ule => BE * pnc_Ug => P || A * pnc_Uge => P || AE - * pnc_Ne => NE + * pnc_Ne => P || NE */ #include "config.h" @@ -497,53 +499,43 @@ static void ia32_emit_cfop_target(const ir_node *node) be_gas_emit_block_name(block); } -/* - * positive conditions for signed compares - */ -static const char *const cmp2condition_s[] = { - NULL, /* always false */ - "e", /* == */ - "l", /* < */ - "le", /* <= */ - "g", /* > */ - "ge", /* >= */ - "ne", /* != */ - NULL /* always true */ -}; - -/* - * positive conditions for unsigned compares - */ -static const char *const cmp2condition_u[] = { - NULL, /* always false */ - "e", /* == */ - "b", /* < */ - "be", /* <= */ - "a", /* > */ - "ae", /* >= */ - "ne", /* != */ - NULL /* always true */ -}; - /** * Emit the suffix for a compare instruction. */ -static void ia32_emit_cmp_suffix(int pnc) -{ - const char *str; - - if (pnc == ia32_pn_Cmp_parity) { - be_emit_char('p'); - return; - } - - if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) { - str = cmp2condition_u[pnc & 7]; - } else { - str = cmp2condition_s[pnc & 7]; +static void ia32_emit_condition_code(ia32_condition_code_t cc) +{ + switch (cc) { + case ia32_cc_overflow: be_emit_cstring("o"); return; + case ia32_cc_not_overflow: be_emit_cstring("no"); return; + case ia32_cc_float_below: + case ia32_cc_float_unordered_below: + case ia32_cc_below: be_emit_cstring("b"); return; + case ia32_cc_float_above_equal: + case ia32_cc_float_unordered_above_equal: + case ia32_cc_above_equal: be_emit_cstring("ae"); return; + case ia32_cc_float_equal: + case ia32_cc_equal: be_emit_cstring("e"); return; + case ia32_cc_float_not_equal: + case ia32_cc_not_equal: be_emit_cstring("ne"); return; + case ia32_cc_float_below_equal: + case ia32_cc_float_unordered_below_equal: + case ia32_cc_below_equal: be_emit_cstring("be"); return; + case ia32_cc_float_above: + case ia32_cc_float_unordered_above: + case ia32_cc_above: be_emit_cstring("a"); return; + case ia32_cc_sign: be_emit_cstring("s"); return; + case ia32_cc_not_sign: be_emit_cstring("ns"); return; + case ia32_cc_parity: be_emit_cstring("p"); return; + case ia32_cc_not_parity: be_emit_cstring("np"); return; + case ia32_cc_less: be_emit_cstring("l"); return; + case ia32_cc_greater_equal: be_emit_cstring("ge"); return; + case ia32_cc_less_equal: be_emit_cstring("le"); return; + case ia32_cc_greater: be_emit_cstring("g"); return; + case ia32_cc_float_parity_cases: + case ia32_cc_additional_float_cases: + break; } - - be_emit_string(str); + panic("Invalid ia32 condition code"); } typedef enum ia32_emit_mod_t { @@ -749,8 +741,8 @@ emit_AM: } case 'P': { - int pnc = va_arg(ap, int); - ia32_emit_cmp_suffix(pnc); + ia32_condition_code_t cc = va_arg(ap, ia32_condition_code_t); + ia32_emit_condition_code(cc); break; } @@ -939,7 +931,7 @@ static ir_node *find_original_value(ir_node *node) } } -static int determine_final_pnc(const ir_node *node, int flags_pos, int pnc) +static int determine_final_cc(const ir_node *node, int flags_pos, int cc) { ir_node *flags = get_irn_n(node, flags_pos); const ia32_attr_t *flags_attr; @@ -957,40 +949,21 @@ static int determine_final_pnc(const ir_node *node, int flags_pos, int pnc) } flags_attr = get_ia32_attr_const(cmp); - if (flags_attr->data.ins_permuted) - pnc = get_mirrored_pnc(pnc); - pnc |= ia32_pn_Cmp_float; - } else if (is_ia32_Ucomi(flags) || is_ia32_Fucomi(flags) - || is_ia32_Fucompi(flags)) { - flags_attr = get_ia32_attr_const(flags); - - if (flags_attr->data.ins_permuted) - pnc = get_mirrored_pnc(pnc); - pnc |= ia32_pn_Cmp_float; } else { flags_attr = get_ia32_attr_const(flags); - - if (flags_attr->data.ins_permuted) - pnc = get_mirrored_pnc(pnc); - if (flags_attr->data.cmp_unsigned) - pnc |= ia32_pn_Cmp_unsigned; } - return pnc; -} - -static int ia32_get_negated_pnc(int pnc) -{ - ir_mode *mode = pnc & ia32_pn_Cmp_float ? mode_F : mode_Iu; - return get_negated_pnc(pnc, mode); + if (flags_attr->data.ins_permuted) + cc = ia32_invert_condition_code(cc); + return cc; } void ia32_emit_cmp_suffix_node(const ir_node *node, int flags_pos) { - int pnc = get_ia32_condcode(node); - pnc = determine_final_pnc(node, flags_pos, pnc); + ia32_condition_code_t cc = get_ia32_condcode(node); + cc = determine_final_cc(node, flags_pos, cc); - ia32_emit_cmp_suffix(pnc); + ia32_emit_condition_code(cc); } /** @@ -1037,12 +1010,12 @@ static int can_be_fallthrough(const ir_node *node) */ static void emit_ia32_Jcc(const ir_node *node) { - int need_parity_label = 0; - const ir_node *proj_true; - const ir_node *proj_false; - int pnc = get_ia32_condcode(node); + int need_parity_label = 0; + ia32_condition_code_t cc = get_ia32_condcode(node); + const ir_node *proj_true; + const ir_node *proj_false; - pnc = determine_final_pnc(node, 0, pnc); + cc = determine_final_cc(node, 0, cc); /* get both Projs */ proj_true = get_proj(node, pn_ia32_Jcc_true); @@ -1057,25 +1030,15 @@ static void emit_ia32_Jcc(const ir_node *node) proj_true = proj_false; proj_false = t; - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); } - if (pnc & ia32_pn_Cmp_float) { + if (cc & ia32_cc_float_parity_cases) { /* Some floating point comparisons require a test of the parity flag, * which indicates that the result is unordered */ - switch (pnc & 0x0f) { - case pn_Cmp_Uo: { + if (cc & ia32_cc_negated) { ia32_emitf(proj_true, "\tjp %L\n"); - break; - } - - case pn_Cmp_Leg: - ia32_emitf(proj_true, "\tjnp %L\n"); - break; - - case pn_Cmp_Eq: - case pn_Cmp_Lt: - case pn_Cmp_Le: + } else { /* we need a local label if the false proj is a fallthrough * as the falseblock might have no label emitted then */ if (can_be_fallthrough(proj_false)) { @@ -1084,22 +1047,9 @@ static void emit_ia32_Jcc(const ir_node *node) } else { ia32_emitf(proj_false, "\tjp %L\n"); } - goto emit_jcc; - - case pn_Cmp_Ug: - case pn_Cmp_Uge: - case pn_Cmp_Ne: - ia32_emitf(proj_true, "\tjp %L\n"); - goto emit_jcc; - - default: - goto emit_jcc; } - } else { -emit_jcc: - ia32_emitf(proj_true, "\tj%P %L\n", pnc); } - + ia32_emitf(proj_true, "\tj%P %L\n", cc); if (need_parity_label) { ia32_emitf(NULL, "1:\n"); } @@ -1120,56 +1070,38 @@ static void emit_ia32_Setcc(const ir_node *node) { const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res); - int pnc = get_ia32_condcode(node); - pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc); - if (pnc & ia32_pn_Cmp_float) { - switch (pnc & 0x0f) { - case pn_Cmp_Uo: - ia32_emitf(node, "\tsetp %#R\n", dreg); - return; - - case pn_Cmp_Leg: - ia32_emitf(node, "\tsetnp %#R\n", dreg); - return; - - case pn_Cmp_Eq: - case pn_Cmp_Lt: - case pn_Cmp_Le: - ia32_emitf(node, "\tset%P %R\n", dreg); - ia32_emitf(node, "\tandb %>R, %R\n", dreg); ia32_emitf(node, "\torb %>R, %R\n", dreg); + ia32_emitf(node, "\tandb %>R, %data.ins_permuted) - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true)); in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false)); @@ -1182,7 +1114,7 @@ static void emit_ia32_CMovcc(const ir_node *node) assert(get_ia32_op_type(node) == ia32_Normal); - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); tmp = in_true; in_true = in_false; @@ -1192,22 +1124,11 @@ static void emit_ia32_CMovcc(const ir_node *node) ia32_emitf(node, "\tmovl %R, %R\n", in_false, out); } - /* TODO: handling of Nans isn't correct yet */ - if (pnc & ia32_pn_Cmp_float) { - switch (pnc & 0x0f) { - case pn_Cmp_Uo: - case pn_Cmp_Leg: - case pn_Cmp_Eq: - case pn_Cmp_Lt: - case pn_Cmp_Le: - case pn_Cmp_Ug: - case pn_Cmp_Uge: - case pn_Cmp_Ne: - panic("CMov with floatingpoint compare/parity not supported yet"); - } + if (cc & ia32_cc_float_parity_cases) { + panic("CMov with floatingpoint compare/parity not supported yet"); } - ia32_emitf(node, "\tcmov%P %#AR, %#R\n", pnc, in_true, out); + ia32_emitf(node, "\tcmov%P %#AR, %#R\n", cc, in_true, out); } @@ -1244,8 +1165,7 @@ static int ia32_cmp_branch_t(const void *a, const void *b) static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node) { int i; - long pnc; - long default_pn; + long default_pn = get_ia32_default_pn(node); ir_node *proj; const ir_edge_t *edge; @@ -1257,26 +1177,26 @@ static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node) tbl->min_value = LONG_MAX; tbl->max_value = LONG_MIN; - default_pn = get_ia32_condcode(node); i = 0; /* go over all proj's and collect them */ foreach_out_edge(node, edge) { + long pn; proj = get_edge_src_irn(edge); assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); - pnc = get_Proj_proj(proj); + pn = get_Proj_proj(proj); /* check for default proj */ - if (pnc == default_pn) { + if (pn == default_pn) { assert(tbl->defProj == NULL && "found two default Projs at SwitchJmp"); tbl->defProj = proj; } else { - tbl->min_value = pnc < tbl->min_value ? pnc : tbl->min_value; - tbl->max_value = pnc > tbl->max_value ? pnc : tbl->max_value; + tbl->min_value = pn < tbl->min_value ? pn : tbl->min_value; + tbl->max_value = pn > tbl->max_value ? pn : tbl->max_value; /* create branch entry */ tbl->branches[i].target = proj; - tbl->branches[i].value = pnc; + tbl->branches[i].value = pn; ++i; } @@ -2222,8 +2142,6 @@ static const lc_opt_table_entry_t ia32_emitter_options[] = { static unsigned char reg_gp_map[N_ia32_gp_REGS]; //static unsigned char reg_mmx_map[N_ia32_mmx_REGS]; //static unsigned char reg_sse_map[N_ia32_xmm_REGS]; -static unsigned char pnc_map_signed[8]; -static unsigned char pnc_map_unsigned[8]; static void build_reg_map(void) { @@ -2235,35 +2153,12 @@ static void build_reg_map(void) reg_gp_map[REG_GP_EBP] = 0x5; reg_gp_map[REG_GP_ESI] = 0x6; reg_gp_map[REG_GP_EDI] = 0x7; - - pnc_map_signed[pn_Cmp_Eq] = 0x04; - pnc_map_signed[pn_Cmp_Lt] = 0x0C; - pnc_map_signed[pn_Cmp_Le] = 0x0E; - pnc_map_signed[pn_Cmp_Gt] = 0x0F; - pnc_map_signed[pn_Cmp_Ge] = 0x0D; - pnc_map_signed[pn_Cmp_Lg] = 0x05; - - pnc_map_unsigned[pn_Cmp_Eq] = 0x04; - pnc_map_unsigned[pn_Cmp_Lt] = 0x02; - pnc_map_unsigned[pn_Cmp_Le] = 0x06; - pnc_map_unsigned[pn_Cmp_Gt] = 0x07; - pnc_map_unsigned[pn_Cmp_Ge] = 0x03; - pnc_map_unsigned[pn_Cmp_Lg] = 0x05; } /** Returns the encoding for a pnc field. */ -static unsigned char pnc2cc(int pnc) +static unsigned char pnc2cc(ia32_condition_code_t cc) { - unsigned char cc; - if (pnc == ia32_pn_Cmp_parity) { - cc = 0x0A; - } else if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) { - cc = pnc_map_unsigned[pnc & 0x07]; - } else { - cc = pnc_map_signed[pnc & 0x07]; - } - assert(cc != 0); - return cc; + return cc & 0xf; } /** Sign extension bit values for binops */ @@ -2875,30 +2770,27 @@ static void bemit_setcc(const ir_node *node) { const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res); - int pnc = get_ia32_condcode(node); - pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc); - if (pnc & ia32_pn_Cmp_float) { - switch (pnc & 0x0f) { - case pn_Cmp_Uo: - /* setp dreg */ bemit8(0x0F); - bemit8(0x9B); - bemit_modrm8(REG_LOW, dreg); - return; + bemit8(0x9A); + bemit_modrm8(REG_HIGH, dreg); - case pn_Cmp_Eq: - case pn_Cmp_Lt: - case pn_Cmp_Le: + /* orb %>dreg, %dreg */ @@ -2909,34 +2801,13 @@ static void bemit_setcc(const ir_node *node) /* andb %>dreg, %dreg */ - bemit8(0x0F); - bemit8(0x9A); - bemit_modrm8(REG_HIGH, dreg); - - /* orb %>dreg, %data.ins_permuted; const arch_register_t *out = arch_irn_get_register(node, pn_ia32_res); - int pnc = get_ia32_condcode(node); + ia32_condition_code_t cc = get_ia32_condcode(node); const arch_register_t *in_true; const arch_register_t *in_false; - pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc); + cc = determine_final_cc(node, n_ia32_CMovcc_eflags, cc); in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true)); in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false)); @@ -2967,12 +2838,13 @@ static void bemit_cmovcc(const ir_node *node) } if (ins_permuted) - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); - /* TODO: handling of Nans isn't correct yet */ + if (cc & ia32_cc_float_parity_cases) + panic("cmov can't handle parity float cases"); bemit8(0x0F); - bemit8(0x40 | pnc2cc(pnc)); + bemit8(0x40 | pnc2cc(cc)); if (get_ia32_op_type(node) == ia32_Normal) { bemit_modrr(in_true, out); } else { @@ -3500,14 +3372,14 @@ static void bemit_jp(bool odd, const ir_node *dest_block) static void bemit_ia32_jcc(const ir_node *node) { - int pnc = get_ia32_condcode(node); - const ir_node *proj_true; - const ir_node *proj_false; - const ir_node *dest_true; - const ir_node *dest_false; - const ir_node *block; + ia32_condition_code_t cc = get_ia32_condcode(node); + const ir_node *proj_true; + const ir_node *proj_false; + const ir_node *dest_true; + const ir_node *dest_false; + const ir_node *block; - pnc = determine_final_pnc(node, 0, pnc); + cc = determine_final_cc(node, 0, cc); /* get both Projs */ proj_true = get_proj(node, pn_ia32_Jcc_true); @@ -3524,51 +3396,29 @@ static void bemit_ia32_jcc(const ir_node *node) proj_true = proj_false; proj_false = t; - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); } dest_true = get_cfop_target_block(proj_true); dest_false = get_cfop_target_block(proj_false); - if (pnc & ia32_pn_Cmp_float) { + if (cc & ia32_cc_float_parity_cases) { /* 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: { - bemit_jp(false, dest_true); - break; + if (cc & ia32_cc_negated) { + bemit_jp(false, dest_true); + } else { + /* we need a local label if the false proj is a fallthrough + * as the falseblock might have no label emitted then */ + if (can_be_fallthrough(proj_false)) { + bemit8(0x7A); + bemit8(0x06); // jp + 6 + } else { + bemit_jp(false, dest_false); } - - case pn_Cmp_Leg: - bemit_jp(true, dest_true); - break; - - case pn_Cmp_Eq: - case pn_Cmp_Lt: - case pn_Cmp_Le: - /* we need a local label if the false proj is a fallthrough - * as the falseblock might have no label emitted then */ - if (can_be_fallthrough(proj_false)) { - bemit8(0x7A); - bemit8(0x06); // jp + 6 - } else { - bemit_jp(false, dest_false); - } - goto emit_jcc; - - case pn_Cmp_Ug: - case pn_Cmp_Uge: - case pn_Cmp_Ne: - bemit_jp(false, dest_true); - goto emit_jcc; - - default: - goto emit_jcc; } - } else { -emit_jcc: - bemit_jcc(pnc, dest_true); } + bemit_jcc(cc, dest_true); /* the second Proj might be a fallthrough */ if (can_be_fallthrough(proj_false)) { diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 0c3805ad8..cf33b5e79 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -29,6 +29,7 @@ #include "config.h" #include +#include #include "irargs_t.h" #include "irprog_t.h" @@ -185,14 +186,11 @@ static void ia32_dump_node(FILE *F, ir_node *n, dump_reason_t reason) /* dump pn code */ if (is_ia32_SwitchJmp(n)) { - fprintf(F, "pn_code = %ld\n", get_ia32_condcode(n)); + fprintf(F, "default_pn = %ld\n", get_ia32_default_pn(n)); } else if (is_ia32_CMovcc(n) || is_ia32_Setcc(n) || is_ia32_Jcc(n)) { ia32_attr_t *attr = get_ia32_attr(n); - long pnc = get_ia32_condcode(n); - fprintf(F, "pn_code = 0x%X (%s)\n", (unsigned) pnc, - get_pnc_string(pnc & pn_Cmp_True)); + fprintf(F, "condition_code = 0x%X\n", get_ia32_condcode(n)); fprintf(F, "ins_permuted = %u \n", attr->data.ins_permuted); - fprintf(F, "cmp_unsigned = %u \n", attr->data.cmp_unsigned); } else if (is_ia32_CopyB(n) || is_ia32_CopyB_i(n)) { fprintf(F, "size = %u\n", get_ia32_copyb_size(n)); @@ -308,6 +306,20 @@ const ia32_condcode_attr_t *get_ia32_condcode_attr_const(const ir_node *node) return cc_attr; } +ia32_switch_attr_t *get_ia32_switch_attr(ir_node *node) +{ + ia32_attr_t *attr = get_ia32_attr(node); + ia32_switch_attr_t *switch_attr = CAST_IA32_ATTR(ia32_switch_attr_t, attr); + return switch_attr; +} + +const ia32_switch_attr_t *get_ia32_switch_attr_const(const ir_node *node) +{ + const ia32_attr_t *attr = get_ia32_attr_const(node); + const ia32_switch_attr_t *switch_attr = CONST_CAST_IA32_ATTR(ia32_switch_attr_t, attr); + return switch_attr; +} + ia32_call_attr_t *get_ia32_call_attr(ir_node *node) { ia32_attr_t *attr = get_ia32_attr(node); @@ -652,19 +664,25 @@ unsigned get_ia32_latency(const ir_node *node) /** * Returns the condition code of a node. */ -long get_ia32_condcode(const ir_node *node) +ia32_condition_code_t get_ia32_condcode(const ir_node *node) { const ia32_condcode_attr_t *attr = get_ia32_condcode_attr_const(node); - return attr->pn_code; + return attr->condition_code; } /** * Sets the condition code of a node */ -void set_ia32_condcode(ir_node *node, long code) +void set_ia32_condcode(ir_node *node, ia32_condition_code_t code) { ia32_condcode_attr_t *attr = get_ia32_condcode_attr(node); - attr->pn_code = code; + attr->condition_code = code; +} + +long get_ia32_default_pn(const ir_node *node) +{ + const ia32_switch_attr_t *attr = get_ia32_switch_attr_const(node); + return attr->default_pn; } /** @@ -874,14 +892,14 @@ void init_ia32_copyb_attributes(ir_node *res, unsigned size) attr->size = size; } -void init_ia32_condcode_attributes(ir_node *res, long pnc) +void init_ia32_condcode_attributes(ir_node *res, ia32_condition_code_t cc) { ia32_condcode_attr_t *attr = (ia32_condcode_attr_t*)get_irn_generic_attr(res); #ifndef NDEBUG attr->attr.attr_type |= IA32_ATTR_ia32_condcode_attr_t; #endif - attr->pn_code = pnc; + attr->condition_code = cc; } void init_ia32_climbframe_attributes(ir_node *res, unsigned count) @@ -894,6 +912,15 @@ void init_ia32_climbframe_attributes(ir_node *res, unsigned count) attr->count = count; } +void init_ia32_switch_attributes(ir_node *res, long default_pn) +{ + ia32_switch_attr_t *attr = (ia32_switch_attr_t*) get_irn_generic_attr(res); +#ifndef NDEBUG + attr->attr.attr_type |= IA32_ATTR_ia32_switch_attr_t; +#endif + attr->default_pn = default_pn; +} + /* default compare operation to compare attributes */ static int ia32_compare_attr(const ia32_attr_t *a, const ia32_attr_t *b) @@ -923,8 +950,7 @@ static int ia32_compare_attr(const ia32_attr_t *a, const ia32_attr_t *b) if (a->data.has_except_label != b->data.has_except_label) return 1; - if (a->data.ins_permuted != b->data.ins_permuted - || a->data.cmp_unsigned != b->data.cmp_unsigned) + if (a->data.ins_permuted != b->data.ins_permuted) return 1; return 0; @@ -951,7 +977,25 @@ static int ia32_compare_condcode_attr(ir_node *a, ir_node *b) attr_a = get_ia32_condcode_attr_const(a); attr_b = get_ia32_condcode_attr_const(b); - if (attr_a->pn_code != attr_b->pn_code) + if (attr_a->condition_code != attr_b->condition_code) + return 1; + + return 0; +} + +/** Compare node attributes for nodes with condition code. */ +static int ia32_compare_switch_attr(ir_node *a, ir_node *b) +{ + const ia32_switch_attr_t *attr_a; + const ia32_switch_attr_t *attr_b; + + if (ia32_compare_nodes_attr(a, b)) + return 1; + + attr_a = get_ia32_switch_attr_const(a); + attr_b = get_ia32_switch_attr_const(b); + + if (attr_a->default_pn != attr_b->default_pn) return 1; return 0; diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index 81b6d0c53..ad0ce4877 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -244,16 +244,15 @@ void set_ia32_frame_ent(ir_node *node, ir_entity *ent); /** * Returns the condition code of a node. */ -long get_ia32_condcode(const ir_node *node); +ia32_condition_code_t get_ia32_condcode(const ir_node *node); /** * Sets the condition code of a node */ -void set_ia32_condcode(ir_node *node, long code); +void set_ia32_condcode(ir_node *node, ia32_condition_code_t code); + +long get_ia32_default_pn(const ir_node *node); -/** - * Returns the condition code of a node. - */ unsigned get_ia32_copyb_size(const ir_node *node); /** @@ -327,7 +326,7 @@ int is_ia32_AddrModeS(const ir_node *node); int is_ia32_AddrModeD(const ir_node *node); /** - * Swaps left/right input of a node (and adjusts pnc if needed) + * Swaps left/right input of a node (and sets ins_permuted accordingly) */ void ia32_swap_left_right(ir_node *node); @@ -346,7 +345,7 @@ void init_ia32_immediate_attributes(ir_node *node, ir_entity *symconst, long offset); void init_ia32_call_attributes(ir_node *res, unsigned pop, ir_type *call_tp); void init_ia32_copyb_attributes(ir_node *res, unsigned size); -void init_ia32_condcode_attributes(ir_node *res, long pnc); +void init_ia32_condcode_attributes(ir_node *res, ia32_condition_code_t cc); void init_ia32_climbframe_attributes(ir_node *res, unsigned count); /* Include the generated headers */ diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index 5df9484d9..4d80a881c 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -31,14 +31,87 @@ #include "../bemachine.h" #include "irnode_t.h" -enum { - ia32_pn_Cmp_unsigned = 0x1000, - ia32_pn_Cmp_float = 0x2000, - ia32_pn_Cmp_parity = 0x4000, - /* The unsigned Lt/Ge comparisons test the carry bit. */ - ia32_pn_Cmp_carry = pn_Cmp_Lt | ia32_pn_Cmp_unsigned, - ia32_pn_Cmp_not_carry = pn_Cmp_Ge | ia32_pn_Cmp_unsigned -}; +/** ia32 condition codes (the numbers correspond to the real encoding order) */ +typedef enum ia32_condition_code_t { + ia32_cc_negated = 0x01, /**< negates condition */ + + ia32_cc_overflow = 0x00, /**< OF=1 */ + ia32_cc_below = 0x02, /**< CF=1 */ + ia32_cc_equal = 0x04, /**< ZF=1 */ + ia32_cc_below_equal = 0x06, /**< ZF=1 or CF=1 */ + ia32_cc_sign = 0x08, /**< SF=1 */ + ia32_cc_parity = 0x0A, /**< PF=1 */ + ia32_cc_less = 0x0C, /**< SF!=OF */ + ia32_cc_less_equal = 0x0E, /**< ZF=1 or SF!=OF */ + ia32_cc_not_overflow = ia32_cc_negated|ia32_cc_overflow, /**< OF=0 */ + ia32_cc_above_equal = ia32_cc_negated|ia32_cc_below, /**< CF=0 */ + ia32_cc_not_equal = ia32_cc_negated|ia32_cc_equal, /**< ZF=0 */ + ia32_cc_above = ia32_cc_negated|ia32_cc_below_equal, /**< ZF=0 and CF=0 */ + ia32_cc_not_sign = ia32_cc_negated|ia32_cc_sign, /**< SF=0 */ + ia32_cc_not_parity = ia32_cc_negated|ia32_cc_parity, /**< PF=0 */ + ia32_cc_greater_equal = ia32_cc_negated|ia32_cc_less, /**< SF=OF */ + ia32_cc_greater = ia32_cc_negated|ia32_cc_less_equal, /**< ZF=0 and SF=OF */ + + /* the following codes are (unfortunately) NOT real hardware codes but + * simplify our backend as you need these combinations for some + * floatingpoint compares (the emitter will split them into multiple + * instructions) */ + ia32_cc_float_parity_cases = 0x20, + /* we need even more cases as inversing the cc is different for float + * comparisons (though for the following we need no special + * parity+x combinations) */ + ia32_cc_additional_float_cases = 0x10, + + /* make sure that the lower 4 bit correspond to the real encoding + * (of the comparison not involving the parity special) */ + ia32_cc_float_equal = 0x34, /**< PF=0 and ZF=1 */ + ia32_cc_float_below = 0x32, /**< PF=0 and CF=1 */ + ia32_cc_float_below_equal = 0x36, /**< PF=0 and (ZF=1 or CF=1) */ + ia32_cc_float_not_equal = ia32_cc_negated|ia32_cc_float_equal, /**< PF=1 or ZF=0 */ + ia32_cc_float_unordered_above_equal + = ia32_cc_negated|ia32_cc_float_below, /**< PF=1 or CF=0 */ + ia32_cc_float_unordered_above + = ia32_cc_negated|ia32_cc_float_below_equal, /**< PF=1 or (ZF=0 and CF=0) */ + + ia32_cc_float_unordered_below_equal = 0x16, /**< ZF=1 or CF=1 */ + ia32_cc_float_unordered_below = 0x12, /**< CF=1 */ + ia32_cc_float_above = + ia32_cc_negated|ia32_cc_float_unordered_below_equal, /**< ZF=0 and CF=0 */ + ia32_cc_float_above_equal + = ia32_cc_negated|ia32_cc_float_unordered_below, /**< CF=0 */ +} ia32_condition_code_t; +ENUM_BITSET(ia32_condition_code_t) + +static inline ia32_condition_code_t ia32_negate_condition_code( + ia32_condition_code_t code) +{ + return code ^ ia32_cc_negated; +} + +static inline ia32_condition_code_t ia32_invert_condition_code( + ia32_condition_code_t code) +{ + /* doesn't appear to have any systematic, so use a table */ + switch (code) { + case ia32_cc_below: return ia32_cc_above; + case ia32_cc_below_equal: return ia32_cc_above_equal; + case ia32_cc_above: return ia32_cc_below; + case ia32_cc_above_equal: return ia32_cc_below_equal; + case ia32_cc_less: return ia32_cc_greater; + case ia32_cc_less_equal: return ia32_cc_greater_equal; + case ia32_cc_greater: return ia32_cc_less; + case ia32_cc_greater_equal: return ia32_cc_less_equal; + case ia32_cc_float_below: return ia32_cc_float_above; + case ia32_cc_float_below_equal: return ia32_cc_float_above_equal; + case ia32_cc_float_above: return ia32_cc_float_below; + case ia32_cc_float_above_equal: return ia32_cc_float_below_equal; + case ia32_cc_float_unordered_below: return ia32_cc_float_unordered_above; + case ia32_cc_float_unordered_below_equal: return ia32_cc_float_unordered_above_equal; + case ia32_cc_float_unordered_above: return ia32_cc_float_unordered_below; + case ia32_cc_float_unordered_above_equal: return ia32_cc_float_unordered_below_equal; + default: return code; + } +} typedef enum { ia32_Normal, @@ -87,6 +160,7 @@ typedef enum { IA32_ATTR_ia32_copyb_attr_t = 1 << 5, IA32_ATTR_ia32_call_attr_t = 1 << 6, IA32_ATTR_ia32_climbframe_attr_t = 1 << 7, + IA32_ATTR_ia32_switch_attr_t = 1 << 8, } ia32_attr_type_t; #endif @@ -113,7 +187,6 @@ struct ia32_attr_t { unsigned need_32bit_stackent:1; /**< needs a 32bit stack entity */ unsigned ins_permuted : 1; /**< inputs of node have been permuted (for commutative nodes) */ - unsigned cmp_unsigned : 1; /**< compare should be unsigned */ unsigned is_reload : 1; /**< node performs a reload */ unsigned is_spill : 1; unsigned is_remat : 1; @@ -152,8 +225,17 @@ struct ia32_call_attr_t { */ typedef struct ia32_condcode_attr_t ia32_condcode_attr_t; struct ia32_condcode_attr_t { - ia32_attr_t attr; /**< generic attribute */ - long pn_code; /**< projnum "types" (e.g. indicate compare operators */ + ia32_attr_t attr; /**< generic attribute */ + ia32_condition_code_t condition_code; /**< condition code*/ +}; + +/** + * The attributes for Switches + */ +typedef struct ia32_switch_attr_t ia32_switch_attr_t; +struct ia32_switch_attr_t { + ia32_attr_t attr; /**< generic attribute */ + long default_pn; }; /** @@ -227,6 +309,7 @@ union allow_casts_attr_t_ { ia32_asm_attr_t asm_attr; ia32_immediate_attr_t immediate_attr; ia32_climbframe_attr_t climbframe_attr; + ia32_switch_attr_t switch_attr; }; #ifndef NDEBUG diff --git a/ir/be/ia32/ia32_optimize.c b/ir/be/ia32/ia32_optimize.c index 963d9b129..71ce6f7d0 100644 --- a/ir/be/ia32/ia32_optimize.c +++ b/ir/be/ia32/ia32_optimize.c @@ -153,7 +153,6 @@ static void peephole_ia32_Cmp(ir_node *const node) ir_node *op; ia32_attr_t const *attr; int ins_permuted; - int cmp_unsigned; ir_node *test; arch_register_t const *reg; ir_edge_t const *edge; @@ -178,14 +177,13 @@ static void peephole_ia32_Cmp(ir_node *const node) op = get_irn_n(node, n_ia32_Cmp_left); attr = get_ia32_attr(node); ins_permuted = attr->data.ins_permuted; - cmp_unsigned = attr->data.cmp_unsigned; if (is_ia32_Cmp(node)) { test = new_bd_ia32_Test(dbgi, block, noreg, noreg, nomem, - op, op, ins_permuted, cmp_unsigned); + op, op, ins_permuted); } else { test = new_bd_ia32_Test8Bit(dbgi, block, noreg, noreg, nomem, - op, op, ins_permuted, cmp_unsigned); + op, op, ins_permuted); } set_ia32_ls_mode(test, get_ia32_ls_mode(node)); @@ -248,10 +246,10 @@ static void peephole_ia32_Test(ir_node *node) /* make sure only Lg/Eq tests are used */ foreach_out_edge(node, edge) { - ir_node *user = get_edge_src_irn(edge); - int pnc = get_ia32_condcode(user); + ir_node *user = get_edge_src_irn(edge); + ia32_condition_code_t cc = get_ia32_condcode(user); - if (pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) { + if (cc != ia32_cc_equal && cc != ia32_cc_not_equal) { return; } } @@ -262,15 +260,15 @@ static void peephole_ia32_Test(ir_node *node) case produces_flag_carry: foreach_out_edge(node, edge) { - ir_node *user = get_edge_src_irn(edge); - int pnc = get_ia32_condcode(user); + ir_node *user = get_edge_src_irn(edge); + ia32_condition_code_t cc = get_ia32_condcode(user); - switch (pnc) { - case pn_Cmp_Eq: pnc = ia32_pn_Cmp_not_carry; break; - case pn_Cmp_Lg: pnc = ia32_pn_Cmp_carry; break; - default: panic("unexpected pn"); + switch (cc) { + case ia32_cc_equal: cc = ia32_cc_above_equal; break; /* CF = 0 */ + case ia32_cc_not_equal: cc = ia32_cc_below; break; /* CF = 1 */ + default: panic("unexpected pn"); } - set_ia32_condcode(user, pnc); + set_ia32_condcode(user, cc); } break; diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index a08ec26ab..fddc1bbd3 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -177,7 +177,10 @@ $custom_init_attr_func = \&ia32_custom_init_attr; "\tinit_ia32_call_attributes(res, pop, call_tp);", ia32_condcode_attr_t => "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". - "\tinit_ia32_condcode_attributes(res, pnc);", + "\tinit_ia32_condcode_attributes(res, condition_code);", + ia32_switch_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_ia32_switch_attributes(res, default_pn);", ia32_copyb_attr_t => "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n". "\tinit_ia32_copyb_attributes(res, size);", @@ -193,10 +196,11 @@ $custom_init_attr_func = \&ia32_custom_init_attr; ); %compare_attr = ( - ia32_asm_attr_t => "ia32_compare_asm_attr", + ia32_asm_attr_t => "ia32_compare_asm_attr", ia32_attr_t => "ia32_compare_nodes_attr", ia32_call_attr_t => "ia32_compare_call_attr", ia32_condcode_attr_t => "ia32_compare_condcode_attr", + ia32_switch_attr_t => "ia32_compare_switch_attr", ia32_copyb_attr_t => "ia32_compare_copyb_attr", ia32_immediate_attr_t => "ia32_compare_immediate_attr", ia32_x87_attr_t => "ia32_compare_x87_attr", @@ -932,9 +936,8 @@ Cmp => { outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. cmp%M %binop', - attr => "int ins_permuted, int cmp_unsigned", - init_attr => "attr->data.ins_permuted = ins_permuted;\n". - "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", latency => 1, units => [ "GP" ], mode => $mode_flags, @@ -950,9 +953,8 @@ Cmp8Bit => { outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. cmpb %binop', - attr => "int ins_permuted, int cmp_unsigned", - init_attr => "attr->data.ins_permuted = ins_permuted;\n". - "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", latency => 1, units => [ "GP" ], mode => $mode_flags, @@ -968,9 +970,8 @@ Test => { outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. test%M %binop', - attr => "int ins_permuted, int cmp_unsigned", - init_attr => "attr->data.ins_permuted = ins_permuted;\n". - "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", latency => 1, units => [ "GP" ], mode => $mode_flags, @@ -986,9 +987,8 @@ Test8Bit => { outs => [ "eflags", "unused", "M" ], am => "source,binary", emit => '. testb %binop', - attr => "int ins_permuted, int cmp_unsigned", - init_attr => "attr->data.ins_permuted = ins_permuted;\n". - "\tattr->data.cmp_unsigned = cmp_unsigned;\n", + attr => "bool ins_permuted", + init_attr => "attr->data.ins_permuted = ins_permuted;", latency => 1, units => [ "GP" ], mode => $mode_flags, @@ -1001,11 +1001,11 @@ Setcc => { ins => [ "eflags" ], outs => [ "res" ], attr_type => "ia32_condcode_attr_t", - attr => "int pnc", + attr => "ia32_condition_code_t condition_code", # The way we handle Setcc with float nodes (potentially) destroys the flags # (when we emit the setX; setp; orb and the setX;setnp;andb sequences) init_attr => "set_ia32_ls_mode(res, mode_Bu);\n" - . "\tif ((pnc & ia32_pn_Cmp_float) && ((pnc & 0xf) != pn_Cmp_Uo) && ((pnc & 0xf) != pn_Cmp_Leg)) {\n" + . "\tif (condition_code & ia32_cc_additional_float_cases) {\n" . "\t\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);\n" . "\t\t/* attr->latency = 3; */\n" . "\t}\n", @@ -1020,7 +1020,7 @@ SetccMem => { reg_req => { in => [ "gp", "gp", "none", "eflags" ], out => [ "none" ] }, ins => [ "base", "index", "mem","eflags" ], attr_type => "ia32_condcode_attr_t", - attr => "int pnc", + attr => "ia32_condition_code_t condition_code", init_attr => "set_ia32_ls_mode(res, mode_Bu);\n", emit => '. set%CMP3 %AM', latency => 1, @@ -1039,7 +1039,7 @@ CMovcc => { outs => [ "res", "flags", "M" ], am => "source,binary", attr_type => "ia32_condcode_attr_t", - attr => "int pnc", + attr => "ia32_condition_code_t condition_code", latency => 1, units => [ "GP" ], mode => $mode_gp, @@ -1052,7 +1052,7 @@ Jcc => { ins => [ "eflags" ], outs => [ "false", "true" ], attr_type => "ia32_condcode_attr_t", - attr => "int pnc", + attr => "ia32_condition_code_t condition_code", latency => 2, units => [ "BRANCH" ], }, @@ -1062,8 +1062,8 @@ SwitchJmp => { op_flags => [ "labeled", "cfopcode", "forking" ], reg_req => { in => [ "gp" ] }, mode => "mode_T", - attr_type => "ia32_condcode_attr_t", - attr => "long pnc", + attr_type => "ia32_switch_attr_t", + attr => "long default_pn", latency => 3, units => [ "BRANCH" ], modified_flags => $status_flags, @@ -1849,7 +1849,7 @@ Ucomi => { ins => [ "base", "index", "mem", "left", "right" ], outs => [ "flags" ], am => "source,binary", - attr => "int ins_permuted", + attr => "bool ins_permuted", init_attr => "attr->data.ins_permuted = ins_permuted;", emit => ' .ucomi%XXM %binop', latency => 3, @@ -2258,7 +2258,7 @@ vFucomFnstsw => { reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] }, ins => [ "left", "right" ], outs => [ "flags" ], - attr => "int ins_permuted", + attr => "bool ins_permuted", init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], @@ -2271,7 +2271,7 @@ vFucomi => { reg_req => { in => [ "vfp", "vfp" ], out => [ "eflags" ] }, ins => [ "left", "right" ], outs => [ "flags" ], - attr => "int ins_permuted", + attr => "bool ins_permuted", init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], @@ -2284,7 +2284,7 @@ vFtstFnstsw => { reg_req => { in => [ "vfp" ], out => [ "eax" ] }, ins => [ "left" ], outs => [ "flags" ], - attr => "int ins_permuted", + attr => "bool ins_permuted", init_attr => "attr->attr.data.ins_permuted = ins_permuted;", latency => 3, units => [ "VFP" ], diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 6e1628799..e3cad3178 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -871,7 +871,7 @@ static void match_arguments(ia32_address_mode_t *am, ir_node *block, } else { new_op1 = be_transform_node(op2); new_op2 = noreg; - am->ins_permuted = 1; + am->ins_permuted = true; } am->op_type = ia32_AddrModeS; } else { @@ -1907,81 +1907,151 @@ static ir_node *gen_bt(ir_node *cmp, ir_node *x, ir_node *n) return new_bd_ia32_Bt(dbgi, new_block, op1, op2); } -/** - * Transform a node returning a "flag" result. - * - * @param node the node to transform - * @param pnc_out the compare mode to use - */ -static ir_node *get_flags_node(ir_node *node, int *pnc_out) +static ia32_condition_code_t pnc_to_condition_code(pn_Cmp pnc, ir_mode *mode) { + if (mode_is_float(mode)) { + switch (pnc) { + case pn_Cmp_Eq: return ia32_cc_float_equal; + case pn_Cmp_Lt: return ia32_cc_float_below; + case pn_Cmp_Le: return ia32_cc_float_below_equal; + case pn_Cmp_Gt: return ia32_cc_float_above; + case pn_Cmp_Ge: return ia32_cc_float_above_equal; + case pn_Cmp_Lg: return ia32_cc_not_equal; + case pn_Cmp_Leg: return ia32_cc_not_parity; + case pn_Cmp_Uo: return ia32_cc_parity; + case pn_Cmp_Ue: return ia32_cc_equal; + case pn_Cmp_Ul: return ia32_cc_float_unordered_below; + case pn_Cmp_Ule: return ia32_cc_float_unordered_below_equal; + case pn_Cmp_Ug: return ia32_cc_float_unordered_above; + case pn_Cmp_Uge: return ia32_cc_float_unordered_above_equal; + case pn_Cmp_Ne: return ia32_cc_float_not_equal; + case pn_Cmp_False: + case pn_Cmp_True: + case pn_Cmp_max: + /* should we introduce a jump always/jump never? */ + break; + } + panic("Unexpected float pnc"); + } else if (mode_is_signed(mode)) { + switch (pnc) { + case pn_Cmp_Ue: + case pn_Cmp_Eq: return ia32_cc_equal; + case pn_Cmp_Ul: + case pn_Cmp_Lt: return ia32_cc_less; + case pn_Cmp_Ule: + case pn_Cmp_Le: return ia32_cc_less_equal; + case pn_Cmp_Ug: + case pn_Cmp_Gt: return ia32_cc_greater; + case pn_Cmp_Uge: + case pn_Cmp_Ge: return ia32_cc_greater_equal; + case pn_Cmp_Lg: + case pn_Cmp_Ne: return ia32_cc_not_equal; + case pn_Cmp_Leg: + case pn_Cmp_Uo: + case pn_Cmp_False: + case pn_Cmp_True: + case pn_Cmp_max: + /* introduce jump always/jump never? */ + break; + } + panic("Unexpected pnc"); + } else { + switch (pnc) { + case pn_Cmp_Ue: + case pn_Cmp_Eq: return ia32_cc_equal; + case pn_Cmp_Ul: + case pn_Cmp_Lt: return ia32_cc_below; + case pn_Cmp_Ule: + case pn_Cmp_Le: return ia32_cc_below_equal; + case pn_Cmp_Ug: + case pn_Cmp_Gt: return ia32_cc_above; + case pn_Cmp_Uge: + case pn_Cmp_Ge: return ia32_cc_above_equal; + case pn_Cmp_Lg: + case pn_Cmp_Ne: return ia32_cc_not_equal; + case pn_Cmp_Leg: + case pn_Cmp_Uo: + case pn_Cmp_False: + case pn_Cmp_True: + case pn_Cmp_max: + /* introduce jump always/jump never? */ + break; + } + panic("Unexpected pnc"); + } +} + +static ir_node *get_flags_mode_b(ir_node *node, ia32_condition_code_t *cc_out) +{ + /* a mode_b value, we have to compare it against 0 */ + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_block = be_transform_node(get_nodes_block(node)); + ir_node *new_op = be_transform_node(node); + ir_node *flags = new_bd_ia32_Test(dbgi, new_block, noreg_GP, noreg_GP, nomem, new_op, new_op, false); + *cc_out = ia32_cc_not_equal; + return flags; +} + +static ir_node *get_flags_node_cmp(ir_node *node, ia32_condition_code_t *cc_out) +{ + /* must have a Proj(Cmp) as input */ + ir_node *cmp = get_Proj_pred(node); + int pnc = get_Proj_pn_cmp(node); + ir_node *l = get_Cmp_left(cmp); + ir_mode *mode = get_irn_mode(l); ir_node *flags; - ir_node *new_op; - 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)) { - int pnc = get_Proj_pn_cmp(node); - if (ia32_cg_config.use_bt && (pnc == pn_Cmp_Lg || pnc == pn_Cmp_Eq)) { - ir_node *l = get_Cmp_left(pred); - ir_node *r = get_Cmp_right(pred); - if (is_And(l)) { - ir_node *la = get_And_left(l); - ir_node *ra = get_And_right(l); - if (is_Shl(la)) { - ir_node *c = get_Shl_left(la); - if (is_Const_1(c) && is_Const_0(r)) { - /* (1 << n) & ra) */ - ir_node *n = get_Shl_right(la); - flags = gen_bt(pred, ra, n); - /* we must generate a Jc/Jnc jump */ - pnc = pnc == pn_Cmp_Lg ? pn_Cmp_Lt : pn_Cmp_Ge; - *pnc_out = ia32_pn_Cmp_unsigned | pnc; - return flags; - } - } - if (is_Shl(ra)) { - ir_node *c = get_Shl_left(ra); - if (is_Const_1(c) && is_Const_0(r)) { - /* la & (1 << n)) */ - ir_node *n = get_Shl_right(ra); - flags = gen_bt(pred, la, n); - /* we must generate a Jc/Jnc jump */ - pnc = pnc == pn_Cmp_Lg ? pn_Cmp_Lt : pn_Cmp_Ge; - *pnc_out = ia32_pn_Cmp_unsigned | pnc; - return flags; - } - } - } + /* check for bit-test */ + if (ia32_cg_config.use_bt + && (pnc == pn_Cmp_Lg || pnc == pn_Cmp_Eq || pnc == pn_Cmp_Ne + || pnc == pn_Cmp_Ue)) { + ir_node *l = get_Cmp_left(cmp); + ir_node *r = get_Cmp_right(cmp); + if (is_And(l)) { + ir_node *la = get_And_left(l); + ir_node *ra = get_And_right(l); + if (is_Shl(ra)) { + ir_node *tmp = la; + la = ra; + ra = tmp; } - /* add ia32 compare flags */ - { - ir_node *l = get_Cmp_left(pred); - ir_mode *mode = get_irn_mode(l); - if (mode_is_float(mode)) - pnc |= ia32_pn_Cmp_float; - else if (! mode_is_signed(mode)) - pnc |= ia32_pn_Cmp_unsigned; + if (is_Shl(la)) { + ir_node *c = get_Shl_left(la); + if (is_Const_1(c) && is_Const_0(r)) { + /* (1 << n) & ra) */ + ir_node *n = get_Shl_right(la); + flags = gen_bt(cmp, ra, n); + /* the bit is copied into the CF flag */ + if (pnc & pn_Cmp_Eq) + *cc_out = ia32_cc_below; /* ==0, so we test for CF=1 */ + else + *cc_out = ia32_cc_above_equal; /* test for CF=0 */ + return flags; + } } - *pnc_out = pnc; - flags = be_transform_node(pred); - 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); - flags = new_bd_ia32_Test(dbgi, new_block, noreg_GP, noreg_GP, nomem, new_op, - new_op, /*is_permuted=*/0, /*cmp_unsigned=*/0); - *pnc_out = pn_Cmp_Lg; + /* just do a normal transformation of the Cmp */ + *cc_out = pnc_to_condition_code(pnc, mode); + flags = be_transform_node(cmp); return flags; } +/** + * Transform a node returning a "flag" result. + * + * @param node the node to transform + * @param cc_out the compare mode to use + */ +static ir_node *get_flags_node(ir_node *node, ia32_condition_code_t *cc_out) +{ + if (is_Proj(node) && is_Cmp(get_Proj_pred(node))) + return get_flags_node_cmp(node, cc_out); + assert(get_irn_mode(node) == mode_b); + return get_flags_mode_b(node, cc_out); +} + /** * Transforms a Load. * @@ -2188,26 +2258,20 @@ static ir_node *dest_am_unop(ir_node *node, ir_node *op, ir_node *mem, return new_node; } -static int ia32_get_negated_pnc(int pnc) -{ - ir_mode *mode = pnc & ia32_pn_Cmp_float ? mode_F : mode_Iu; - return get_negated_pnc(pnc, mode); -} - static ir_node *try_create_SetMem(ir_node *node, ir_node *ptr, ir_node *mem) { - ir_mode *mode = get_irn_mode(node); - ir_node *mux_true = get_Mux_true(node); - ir_node *mux_false = get_Mux_false(node); - ir_node *cond; - dbg_info *dbgi; - ir_node *block; - ir_node *new_block; - ir_node *flags; - ir_node *new_node; - bool negated; - int pnc; - ia32_address_t addr; + ir_mode *mode = get_irn_mode(node); + ir_node *mux_true = get_Mux_true(node); + ir_node *mux_false = get_Mux_false(node); + ir_node *cond; + dbg_info *dbgi; + ir_node *block; + ir_node *new_block; + ir_node *flags; + ir_node *new_node; + bool negated; + ia32_condition_code_t cc; + ia32_address_t addr; if (get_mode_size_bits(mode) != 8) return NULL; @@ -2221,12 +2285,12 @@ static ir_node *try_create_SetMem(ir_node *node, ir_node *ptr, ir_node *mem) } cond = get_Mux_sel(node); - flags = get_flags_node(cond, &pnc); + flags = get_flags_node(cond, &cc); /* we can't handle the float special cases with SetM */ - if (pnc & ia32_pn_Cmp_float) + if (cc & ia32_cc_additional_float_cases) return NULL; if (negated) - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); build_address_ptr(&addr, ptr, mem); @@ -2234,7 +2298,7 @@ static ir_node *try_create_SetMem(ir_node *node, ir_node *ptr, ir_node *mem) block = get_nodes_block(node); new_block = be_transform_node(block); new_node = new_bd_ia32_SetccMem(dbgi, new_block, addr.base, - addr.index, addr.mem, flags, pnc); + addr.index, addr.mem, flags, cc); set_address(new_node, &addr); set_ia32_op_type(new_node, ia32_AddrModeD); set_ia32_ls_mode(new_node, mode); @@ -2674,23 +2738,23 @@ static ir_node *create_Switch(ir_node *node) */ static ir_node *gen_Cond(ir_node *node) { - ir_node *block = get_nodes_block(node); - ir_node *new_block = be_transform_node(block); - 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 *flags = NULL; - ir_node *new_node; - int pnc; + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + 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 *flags = NULL; + ir_node *new_node; + ia32_condition_code_t cc; if (sel_mode != mode_b) { return create_Switch(node); } /* we get flags from a Cmp */ - flags = get_flags_node(sel, &pnc); + flags = get_flags_node(sel, &cc); - new_node = new_bd_ia32_Jcc(dbgi, new_block, flags, pnc); + new_node = new_bd_ia32_Jcc(dbgi, new_block, flags, cc); SET_IA32_ORIG_NODE(new_node, node); return new_node; @@ -2886,7 +2950,6 @@ static ir_node *gen_Cmp(ir_node *node) ir_node *new_node; ia32_address_mode_t am; ia32_address_t *addr = &am.addr; - int cmp_unsigned; if (mode_is_float(cmp_mode)) { if (ia32_cg_config.use_sse2) { @@ -2899,7 +2962,6 @@ static ir_node *gen_Cmp(ir_node *node) assert(ia32_mode_needs_gp_reg(cmp_mode)); /* Prefer the Test instruction, when encountering (x & y) ==/!= 0 */ - cmp_unsigned = !mode_is_signed(cmp_mode); if (is_Const_0(right) && is_And(left) && get_irn_n_edges(left) == 1 && @@ -2927,11 +2989,10 @@ static ir_node *gen_Cmp(ir_node *node) if (get_mode_size_bits(cmp_mode) == 8) { new_node = new_bd_ia32_Test8Bit(dbgi, new_block, addr->base, - addr->index, addr->mem, am.new_op1, am.new_op2, am.ins_permuted, - cmp_unsigned); + addr->index, addr->mem, am.new_op1, am.new_op2, am.ins_permuted); } else { new_node = new_bd_ia32_Test(dbgi, new_block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, am.ins_permuted, cmp_unsigned); + addr->mem, am.new_op1, am.new_op2, am.ins_permuted); } } else { /* Cmp(left, right) */ @@ -2948,11 +3009,10 @@ static ir_node *gen_Cmp(ir_node *node) if (get_mode_size_bits(cmp_mode) == 8) { new_node = new_bd_ia32_Cmp8Bit(dbgi, new_block, addr->base, addr->index, addr->mem, am.new_op1, - am.new_op2, am.ins_permuted, - cmp_unsigned); + am.new_op2, am.ins_permuted); } else { new_node = new_bd_ia32_Cmp(dbgi, new_block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, am.ins_permuted, cmp_unsigned); + addr->mem, am.new_op1, am.new_op2, am.ins_permuted); } } set_am_attributes(new_node, &am); @@ -2966,7 +3026,7 @@ static ir_node *gen_Cmp(ir_node *node) } static ir_node *create_CMov(ir_node *node, ir_node *flags, ir_node *new_flags, - int pnc) + ia32_condition_code_t cc) { dbg_info *dbgi = get_irn_dbg_info(node); ir_node *block = get_nodes_block(node); @@ -2986,11 +3046,11 @@ static ir_node *create_CMov(ir_node *node, ir_node *flags, ir_node *new_flags, match_commutative | match_am | match_16bit_am | match_mode_neutral); if (am.ins_permuted) - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_invert_condition_code(cc); new_node = new_bd_ia32_CMovcc(dbgi, new_block, addr->base, addr->index, addr->mem, am.new_op1, am.new_op2, new_flags, - pnc); + cc); set_am_attributes(new_node, &am); SET_IA32_ORIG_NODE(new_node, node); @@ -3004,13 +3064,13 @@ static ir_node *create_CMov(ir_node *node, ir_node *flags, ir_node *new_flags, * Creates a ia32 Setcc instruction. */ static ir_node *create_set_32bit(dbg_info *dbgi, ir_node *new_block, - ir_node *flags, int pnc, + ir_node *flags, ia32_condition_code_t cc, ir_node *orig_node) { ir_mode *mode = get_irn_mode(orig_node); ir_node *new_node; - new_node = new_bd_ia32_Setcc(dbgi, new_block, flags, pnc); + new_node = new_bd_ia32_Setcc(dbgi, new_block, flags, cc); SET_IA32_ORIG_NODE(new_node, orig_node); /* we might need to conv the result up */ @@ -3138,8 +3198,8 @@ enum setcc_transform_insn { }; typedef struct setcc_transform { - unsigned num_steps; - int pnc; + unsigned num_steps; + ia32_condition_code_t cc; struct { enum setcc_transform_insn transform; long val; @@ -3152,7 +3212,8 @@ typedef struct setcc_transform { * Find a transformation that creates 0 and 1 from * tv_t and tv_f. */ -static void find_const_transform(int pnc, ir_tarval *t, ir_tarval *f, +static void find_const_transform(ia32_condition_code_t cc, + ir_tarval *t, ir_tarval *f, setcc_transform_t *res) { unsigned step = 0; @@ -3163,15 +3224,15 @@ static void find_const_transform(int pnc, ir_tarval *t, ir_tarval *f, ir_tarval *tmp = t; t = f; f = tmp; - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); } else if (tarval_cmp(t, f) == pn_Cmp_Lt) { // now, t is the bigger one ir_tarval *tmp = t; t = f; f = tmp; - pnc = ia32_get_negated_pnc(pnc); + cc = ia32_negate_condition_code(cc); } - res->pnc = pnc; + res->cc = cc; if (! tarval_is_null(f)) { ir_tarval *t_sub = tarval_sub(t, f, NULL); @@ -3276,17 +3337,17 @@ static void find_const_transform(int pnc, ir_tarval *t, ir_tarval *f, */ static ir_node *gen_Mux(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 *mux_true = get_Mux_true(node); - ir_node *mux_false = get_Mux_false(node); - ir_node *cond = get_Mux_sel(node); - ir_mode *mode = get_irn_mode(node); - ir_node *flags; - ir_node *new_node; - int is_abs; - int pnc; + 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 *mux_true = get_Mux_true(node); + ir_node *mux_false = get_Mux_false(node); + ir_node *cond = get_Mux_sel(node); + ir_mode *mode = get_irn_mode(node); + ir_node *flags; + ir_node *new_node; + int is_abs; + ia32_condition_code_t cc; assert(get_irn_mode(cond) == mode_b); @@ -3332,8 +3393,8 @@ static ir_node *gen_Mux(ir_node *node) ir_mode *new_mode; unsigned scale; - flags = get_flags_node(cond, &pnc); - new_node = create_set_32bit(dbgi, new_block, flags, pnc, node); + flags = get_flags_node(cond, &cc); + new_node = create_set_32bit(dbgi, new_block, flags, cc, node); if (ia32_cg_config.use_sse2) { /* cannot load from different mode on SSE */ @@ -3388,7 +3449,7 @@ static ir_node *gen_Mux(ir_node *node) am.new_op2 = NULL; am.pinned = op_pin_state_floats; am.commutative = 1; - am.ins_permuted = 0; + am.ins_permuted = false; if (ia32_cg_config.use_sse2) load = new_bd_ia32_xLoad(dbgi, block, am.addr.base, am.addr.index, am.addr.mem, new_mode); @@ -3416,7 +3477,7 @@ static ir_node *gen_Mux(ir_node *node) ir_node *tmp = val_false; val_false = val_true; val_true = tmp; - pnc = ia32_get_negated_pnc(pnc); + pnc = get_negated_pnc(pnc, get_irn_mode(cmp_left)); } if (is_Const_0(val_false) && is_Sub(val_true)) { if ((pnc == pn_Cmp_Gt || pnc == pn_Cmp_Ge) @@ -3433,7 +3494,7 @@ static ir_node *gen_Mux(ir_node *node) } } - flags = get_flags_node(cond, &pnc); + flags = get_flags_node(cond, &cc); if (is_Const(mux_true) && is_Const(mux_false)) { /* both are const, good */ @@ -3442,7 +3503,7 @@ static ir_node *gen_Mux(ir_node *node) setcc_transform_t res; int step; - find_const_transform(pnc, tv_true, tv_false, &res); + find_const_transform(cc, tv_true, tv_false, &res); new_node = node; for (step = (int)res.num_steps - 1; step >= 0; --step) { ir_node *imm; @@ -3480,7 +3541,7 @@ static ir_node *gen_Mux(ir_node *node) new_node = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, new_node, imm); break; case SETCC_TR_SET: - new_node = create_set_32bit(dbgi, new_block, flags, res.pnc, node); + new_node = create_set_32bit(dbgi, new_block, flags, res.cc, node); break; case SETCC_TR_SBB: new_node = new_bd_ia32_Sbb0(dbgi, new_block, flags); @@ -3490,7 +3551,7 @@ static ir_node *gen_Mux(ir_node *node) } } } else { - new_node = create_CMov(node, cond, flags, pnc); + new_node = create_CMov(node, cond, flags, cc); } return new_node; } @@ -4085,41 +4146,6 @@ static ir_node *gen_IJmp(ir_node *node) return new_node; } -/** - * Transform a Bound node. - */ -static ir_node *gen_Bound(ir_node *node) -{ - ir_node *new_node; - ir_node *lower = get_Bound_lower(node); - dbg_info *dbgi = get_irn_dbg_info(node); - - if (is_Const_0(lower)) { - /* typical case for Java */ - ir_node *sub, *res, *flags, *block; - - res = gen_binop(node, get_Bound_index(node), get_Bound_upper(node), - new_bd_ia32_Sub, - match_mode_neutral | match_am | match_immediate); - - block = get_nodes_block(res); - if (! is_Proj(res)) { - sub = res; - set_irn_mode(sub, mode_T); - res = new_rd_Proj(NULL, sub, mode_Iu, pn_ia32_res); - } else { - sub = get_Proj_pred(res); - } - flags = new_rd_Proj(NULL, sub, mode_Iu, pn_ia32_Sub_flags); - new_node = new_bd_ia32_Jcc(dbgi, block, flags, pn_Cmp_Lt | ia32_pn_Cmp_unsigned); - SET_IA32_ORIG_NODE(new_node, node); - } else { - panic("generic Bound not supported in ia32 Backend"); - } - return new_node; -} - - static ir_node *gen_ia32_l_ShlDep(ir_node *node) { ir_node *left = get_irn_n(node, n_ia32_l_ShlDep_val); @@ -4349,7 +4375,7 @@ static ir_node *gen_ia32_l_LLtoFloat(ir_node *node) am.new_op2 = ia32_new_NoReg_vfp(current_ir_graph); am.pinned = op_pin_state_floats; am.commutative = 1; - am.ins_permuted = 0; + am.ins_permuted = false; fadd = new_bd_ia32_vfadd(dbgi, block, am.addr.base, am.addr.index, am.addr.mem, am.new_op1, am.new_op2, get_fpcw()); @@ -5051,7 +5077,7 @@ static ir_node *gen_parity(ir_node *node) match_arguments(&am, block, NULL, param, NULL, match_am); imm = ia32_create_Immediate(NULL, 0, 0); cmp = new_bd_ia32_Cmp(dbgi, new_block, addr->base, addr->index, - addr->mem, imm, am.new_op2, am.ins_permuted, 0); + addr->mem, imm, am.new_op2, am.ins_permuted); set_am_attributes(cmp, &am); set_ia32_ls_mode(cmp, mode_Iu); @@ -5060,7 +5086,7 @@ static ir_node *gen_parity(ir_node *node) cmp = fix_mem_proj(cmp, &am); /* setp */ - new_node = new_bd_ia32_Setcc(dbgi, new_block, cmp, ia32_pn_Cmp_parity); + new_node = new_bd_ia32_Setcc(dbgi, new_block, cmp, ia32_cc_parity); SET_IA32_ORIG_NODE(new_node, node); /* conv to 32bit */ @@ -5510,30 +5536,6 @@ static ir_node *gen_Proj_Cmp(ir_node *node) node); } -/** - * Transform the Projs from a Bound. - */ -static ir_node *gen_Proj_Bound(ir_node *node) -{ - ir_node *new_node; - ir_node *pred = get_Proj_pred(node); - - switch (get_Proj_proj(node)) { - case pn_Bound_M: - return be_transform_node(get_Bound_mem(pred)); - case pn_Bound_X_regular: - new_node = be_transform_node(pred); - return new_r_Proj(new_node, mode_X, pn_ia32_Jcc_true); - case pn_Bound_X_except: - new_node = be_transform_node(pred); - return new_r_Proj(new_node, mode_X, pn_ia32_Jcc_false); - case pn_Bound_res: - return be_transform_node(get_Bound_index(pred)); - default: - panic("unsupported Proj from Bound"); - } -} - static ir_node *gen_Proj_ASM(ir_node *node) { ir_mode *mode = get_irn_mode(node); @@ -5590,8 +5592,6 @@ static ir_node *gen_Proj(ir_node *node) return gen_Proj_be_Call(node); case iro_Cmp: return gen_Proj_Cmp(node); - case iro_Bound: - return gen_Proj_Bound(node); case iro_Start: proj = get_Proj_proj(node); switch (proj) { @@ -5649,7 +5649,6 @@ static void register_transformers(void) be_set_transform_function(op_be_IncSP, gen_be_IncSP); be_set_transform_function(op_be_Return, gen_be_Return); be_set_transform_function(op_be_SubSP, gen_be_SubSP); - be_set_transform_function(op_Bound, gen_Bound); be_set_transform_function(op_Builtin, gen_Builtin); be_set_transform_function(op_Cmp, gen_Cmp); be_set_transform_function(op_Cond, gen_Cond);