This patch extracts a cc comparison from the initial compare/jump insn and allows it to be passed to noce_emit_cmove and emit_conditional_move. --- gcc/ifcvt.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++---- gcc/optabs.c | 7 ++++-- gcc/optabs.h | 2 +- 3 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 99716e5f63c..3db707e1fd1 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -86,6 +86,7 @@ static rtx_insn *find_active_insn_after (basic_block, rtx_insn *); static basic_block block_fallthru (basic_block); static rtx cond_exec_get_condition (rtx_insn *); static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool); +static rtx noce_get_compare (rtx_insn *, bool); static int noce_operand_ok (const_rtx); static void merge_if_block (ce_if_block *); static int find_cond_trap (basic_block, edge, edge); @@ -775,7 +776,7 @@ static int noce_try_addcc (struct noce_if_info *); static int noce_try_store_flag_constants (struct noce_if_info *); static int noce_try_store_flag_mask (struct noce_if_info *); static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx, - rtx, rtx, rtx); + rtx, rtx, rtx, rtx = NULL); static int noce_try_cmove (struct noce_if_info *); static int noce_try_cmove_arith (struct noce_if_info *); static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **); @@ -1658,7 +1659,7 @@ noce_try_store_flag_mask (struct noce_if_info *if_info) static rtx noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code, - rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue) + rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue, rtx cc_cmp) { rtx target ATTRIBUTE_UNUSED; int unsignedp ATTRIBUTE_UNUSED; @@ -1706,7 +1707,7 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code, target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode, vtrue, vfalse, GET_MODE (x), - unsignedp); + unsignedp, cc_cmp); if (target) return target; @@ -2970,6 +2971,60 @@ noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed return tmp; } +/* Get the comparison from the insn. */ +static rtx +noce_get_compare (rtx_insn *jump, bool then_else_reversed) +{ + enum rtx_code code; + const_rtx set; + rtx tem; + rtx op0, op1; + + if (!have_cbranchcc4) + return 0; + + if (! any_condjump_p (jump)) + return NULL_RTX; + + set = pc_set (jump); + + /* If this branches to JUMP_LABEL when the condition is false, + reverse the condition. */ + bool reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF + && label_ref_label (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (jump)); + + /* We may have to reverse because the caller's if block is not canonical, + i.e. the THEN block isn't the fallthrough block for the TEST block + (see find_if_header). */ + if (then_else_reversed) + reverse = !reverse; + + rtx cond = XEXP (SET_SRC (set), 0); + + code = GET_CODE (cond); + op0 = XEXP (cond, 0); + op1 = XEXP (cond, 1); + + if (reverse) + code = reversed_comparison_code (cond, jump); + if (code == UNKNOWN) + return 0; + + /* If constant is first, put it last. */ + if (CONSTANT_P (op0)) + code = swap_condition (code), tem = op0, op0 = op1, op1 = tem; + + /* Never return CC0; return zero instead. */ + if (CC0_P (op0)) + return 0; + + /* We promised to return a comparison. */ + rtx ret = gen_rtx_fmt_ee (code, VOIDmode, op0, op1); + if (COMPARISON_P (ret)) + return ret; + return 0; +} + /* Return true if OP is ok for if-then-else processing. */ static int @@ -3140,6 +3195,8 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) rtx y = XEXP (cond, 1); rtx_code cond_code = GET_CODE (cond); + rtx cc_cmp = noce_get_compare (jump, false); + /* The true targets for a conditional move. */ auto_vec<rtx> targets; /* The temporaries introduced to allow us to not consider register @@ -3151,7 +3208,8 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) hash_map<rtx, bool> need_temps; - check_need_temps (then_bb, &need_temps, cond); + if (!cc_cmp) + check_need_temps (then_bb, &need_temps, cond); hash_map<rtx, bool> temps_created; @@ -3242,7 +3300,7 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) /* Actually emit the conditional move. */ rtx temp_dest = noce_emit_cmove (if_info, temp, cond_code, - x, y, new_val, old_val); + x, y, new_val, old_val, cc_cmp); /* If we failed to expand the conditional move, drop out and don't try to continue. */ diff --git a/gcc/optabs.c b/gcc/optabs.c index 06bcaab1f55..3ce6f8cdd30 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -4325,7 +4325,7 @@ emit_indirect_jump (rtx loc) rtx emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, machine_mode cmode, rtx op2, rtx op3, - machine_mode mode, int unsignedp) + machine_mode mode, int unsignedp, rtx cc_cmp) { rtx comparison; rtx_insn *last; @@ -4408,7 +4408,10 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1, class expand_operand ops[4]; create_output_operand (&ops[0], target, mode); - create_fixed_operand (&ops[1], comparison); + if (cc_cmp) + create_fixed_operand (&ops[1], cc_cmp); + else + create_fixed_operand (&ops[1], comparison); create_input_operand (&ops[2], op2, mode); create_input_operand (&ops[3], op3, mode); if (maybe_expand_insn (icode, 4, ops)) diff --git a/gcc/optabs.h b/gcc/optabs.h index 0654107d6e3..c4540f87144 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -258,7 +258,7 @@ extern void emit_indirect_jump (rtx); /* Emit a conditional move operation. */ rtx emit_conditional_move (rtx, enum rtx_code, rtx, rtx, machine_mode, - rtx, rtx, machine_mode, int); + rtx, rtx, machine_mode, int, rtx = NULL); /* Emit a conditional negate or bitwise complement operation. */ rtx emit_conditional_neg_or_complement (rtx, rtx_code, machine_mode, rtx, -- 2.17.0