Revert r12-674{3,4,5,6,7,8,9} and r12-7114, as there are several PRs reported against those changes still unresolved. --- gcc/ifcvt.cc +++ gcc/ifcvt.cc @@ -3391,11 +3391,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, rtx cond = noce_get_condition (jump, &cond_earliest, false); rtx cc_cmp = cond_exec_get_condition (jump); - if (cc_cmp) - cc_cmp = copy_rtx (cc_cmp); rtx rev_cc_cmp = cond_exec_get_condition (jump, /* get_reversed */ true); - if (rev_cc_cmp) - rev_cc_cmp = copy_rtx (rev_cc_cmp); rtx_insn *insn; int count = 0; @@ -3519,7 +3515,6 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, unsigned cost1 = 0, cost2 = 0; rtx_insn *seq, *seq1, *seq2; rtx temp_dest = NULL_RTX, temp_dest1 = NULL_RTX, temp_dest2 = NULL_RTX; - bool read_comparison = false; seq1 = try_emit_cmove_seq (if_info, temp, cond, new_val, old_val, need_cmov, @@ -3529,41 +3524,10 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, as well. This allows the backend to emit a cmov directly without creating an additional compare for each. If successful, costing is easier and this sequence is usually preferred. */ - seq2 = try_emit_cmove_seq (if_info, temp, cond, + seq2 = try_emit_cmove_seq (if_info, target, cond, new_val, old_val, need_cmov, &cost2, &temp_dest2, cc_cmp, rev_cc_cmp); - /* The backend might have created a sequence that uses the - condition. Check this. */ - rtx_insn *walk = seq2; - while (walk) - { - rtx set = single_set (walk); - - if (!set || !SET_SRC (set)) - { - walk = NEXT_INSN (walk); - continue; - } - - rtx src = SET_SRC (set); - - if (XEXP (set, 1) && GET_CODE (XEXP (set, 1)) == IF_THEN_ELSE) - ; /* We assume that this is the cmove created by the backend that - naturally uses the condition. Therefore we ignore it. */ - else - { - if (reg_mentioned_p (XEXP (cond, 0), src) - || reg_mentioned_p (XEXP (cond, 1), src)) - { - read_comparison = true; - break; - } - } - - walk = NEXT_INSN (walk); - } - /* Check which version is less expensive. */ if (seq1 != NULL_RTX && (cost1 <= cost2 || seq2 == NULL_RTX)) { @@ -3576,8 +3540,6 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, { seq = seq2; temp_dest = temp_dest2; - if (!second_try && read_comparison) - *last_needs_comparison = count; } else { @@ -3596,12 +3558,6 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, unmodified_insns->safe_push (insn); } - /* Even if we did not actually need the comparison, we want to make sure - to try a second time in order to get rid of the temporaries. */ - if (*last_needs_comparison == -1) - *last_needs_comparison = 0; - - return true; } --- gcc/config/rs6000/rs6000.cc +++ gcc/config/rs6000/rs6000.cc @@ -16373,10 +16373,10 @@ rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1) c = GEU; if (code == SMAX || code == UMAX) - target = emit_conditional_move (dest, { c, op0, op1, mode }, + target = emit_conditional_move (dest, c, op0, op1, mode, op0, op1, mode, 0); else - target = emit_conditional_move (dest, { c, op0, op1, mode }, + target = emit_conditional_move (dest, c, op0, op1, mode, op1, op0, mode, 0); gcc_assert (target); if (target != dest) @@ -22769,7 +22769,7 @@ rs6000_emit_swsqrt (rtx dst, rtx src, bool recip) if (mode == SFmode) { - rtx target = emit_conditional_move (e, { GT, src, zero, mode }, + rtx target = emit_conditional_move (e, GT, src, zero, mode, e, zero, mode, 0); if (target != e) emit_move_insn (e, target); --- gcc/expmed.cc +++ gcc/expmed.cc @@ -4124,8 +4124,8 @@ expand_sdiv_pow2 (scalar_int_mode mode, rtx op0, HOST_WIDE_INT d) temp = force_reg (mode, temp); /* Construct "temp2 = (temp2 < 0) ? temp : temp2". */ - temp2 = emit_conditional_move (temp2, { LT, temp2, const0_rtx, mode }, - temp, temp2, mode, 0); + temp2 = emit_conditional_move (temp2, LT, temp2, const0_rtx, + mode, temp, temp2, mode, 0); if (temp2) { rtx_insn *seq = get_insns (); @@ -6127,10 +6127,10 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, return 0; if (and_them) - tem = emit_conditional_move (target, { code, op0, op1, mode }, + tem = emit_conditional_move (target, code, op0, op1, mode, tem, const0_rtx, GET_MODE (tem), 0); else - tem = emit_conditional_move (target, { code, op0, op1, mode }, + tem = emit_conditional_move (target, code, op0, op1, mode, trueval, tem, GET_MODE (tem), 0); if (tem == 0) --- gcc/expr.cc +++ gcc/expr.cc @@ -8824,9 +8824,8 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED, op2 = gen_lowpart (mode, op2); /* Try to emit the conditional move. */ - insn = emit_conditional_move (temp, - { comparison_code, op00, op01, - comparison_mode }, + insn = emit_conditional_move (temp, comparison_code, + op00, op01, comparison_mode, op1, op2, mode, unsignedp); @@ -9717,9 +9716,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, start_sequence (); /* Try to emit the conditional move. */ - insn = emit_conditional_move (target, - { comparison_code, - op0, cmpop1, mode }, + insn = emit_conditional_move (target, comparison_code, + op0, cmpop1, mode, op0, op1, mode, unsignedp); --- gcc/ifcvt.cc +++ gcc/ifcvt.cc @@ -83,7 +83,7 @@ static rtx_insn *last_active_insn (basic_block, int); static rtx_insn *find_active_insn_before (basic_block, rtx_insn *); 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 *, bool); +static rtx cond_exec_get_condition (rtx_insn *); static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool); static int noce_operand_ok (const_rtx); static void merge_if_block (ce_if_block *); @@ -98,14 +98,6 @@ static int dead_or_predicable (basic_block, basic_block, basic_block, edge, int); static void noce_emit_move_insn (rtx, rtx); static rtx_insn *block_has_only_trap (basic_block); -static void need_cmov_or_rewire (basic_block, hash_set *, - hash_map *); -static bool noce_convert_multiple_sets_1 (struct noce_if_info *, - hash_set *, - hash_map *, - auto_vec *, - auto_vec *, - auto_vec *, int *); /* Count the number of non-jump active insns in BB. */ @@ -433,7 +425,7 @@ cond_exec_process_insns (ce_if_block *ce_info ATTRIBUTE_UNUSED, /* Return the condition for a jump. Do not do any special processing. */ static rtx -cond_exec_get_condition (rtx_insn *jump, bool get_reversed = false) +cond_exec_get_condition (rtx_insn *jump) { rtx test_if, cond; @@ -445,10 +437,8 @@ cond_exec_get_condition (rtx_insn *jump, bool get_reversed = false) /* If this branches to JUMP_LABEL when the condition is false, reverse the condition. */ - if (get_reversed - || (GET_CODE (XEXP (test_if, 2)) == LABEL_REF - && label_ref_label (XEXP (test_if, 2)) - == JUMP_LABEL (jump))) + if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF + && label_ref_label (XEXP (test_if, 2)) == JUMP_LABEL (jump)) { enum rtx_code rev = reversed_comparison_code (cond, jump); if (rev == UNKNOWN) @@ -780,7 +770,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 = NULL, rtx = NULL); + rtx, rtx, rtx); 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 **); @@ -1719,8 +1709,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 cc_cmp, - rtx rev_cc_cmp) + rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue) { rtx target ATTRIBUTE_UNUSED; int unsignedp ATTRIBUTE_UNUSED; @@ -1752,30 +1741,23 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code, end_sequence (); } - unsignedp = (code == LTU || code == GEU - || code == LEU || code == GTU); - - if (cc_cmp != NULL_RTX && rev_cc_cmp != NULL_RTX) - target = emit_conditional_move (x, cc_cmp, rev_cc_cmp, - vtrue, vfalse, GET_MODE (x)); - else + /* Don't even try if the comparison operands are weird + except that the target supports cbranchcc4. */ + if (! general_operand (cmp_a, GET_MODE (cmp_a)) + || ! general_operand (cmp_b, GET_MODE (cmp_b))) { - /* Don't even try if the comparison operands are weird - except that the target supports cbranchcc4. */ - if (! general_operand (cmp_a, GET_MODE (cmp_a)) - || ! general_operand (cmp_b, GET_MODE (cmp_b))) - { - if (!have_cbranchcc4 - || GET_MODE_CLASS (GET_MODE (cmp_a)) != MODE_CC - || cmp_b != const0_rtx) - return NULL_RTX; - } - - target = emit_conditional_move (x, { code, cmp_a, cmp_b, VOIDmode }, - vtrue, vfalse, GET_MODE (x), - unsignedp); + if (!have_cbranchcc4 + || GET_MODE_CLASS (GET_MODE (cmp_a)) != MODE_CC + || cmp_b != const0_rtx) + return NULL_RTX; } + unsignedp = (code == LTU || code == GEU + || code == LEU || code == GTU); + + target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode, + vtrue, vfalse, GET_MODE (x), + unsignedp); if (target) return target; @@ -1811,9 +1793,8 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code, promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue)); - target = emit_conditional_move (promoted_target, - { code, cmp_a, cmp_b, VOIDmode }, - reg_vtrue, reg_vfalse, + target = emit_conditional_move (promoted_target, code, cmp_a, cmp_b, + VOIDmode, reg_vtrue, reg_vfalse, GET_MODE (reg_vtrue), unsignedp); /* Nope, couldn't do it in that mode either. */ if (!target) @@ -3160,50 +3141,6 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond, return false; } -/* Helper function to emit a cmov sequence encapsulated in - start_sequence () and end_sequence (). If NEED_CMOV is true - we call noce_emit_cmove to create a cmove sequence. Otherwise emit - a simple move. If successful, store the first instruction of the - sequence in TEMP_DEST and the sequence costs in SEQ_COST. */ - -static rtx_insn* -try_emit_cmove_seq (struct noce_if_info *if_info, rtx temp, - rtx cond, rtx new_val, rtx old_val, bool need_cmov, - unsigned *cost, rtx *temp_dest, - rtx cc_cmp = NULL, rtx rev_cc_cmp = NULL) -{ - rtx_insn *seq = NULL; - *cost = 0; - - rtx x = XEXP (cond, 0); - rtx y = XEXP (cond, 1); - rtx_code cond_code = GET_CODE (cond); - - start_sequence (); - - if (need_cmov) - *temp_dest = noce_emit_cmove (if_info, temp, cond_code, - x, y, new_val, old_val, cc_cmp, rev_cc_cmp); - else - { - *temp_dest = temp; - if (if_info->then_else_reversed) - noce_emit_move_insn (temp, old_val); - else - noce_emit_move_insn (temp, new_val); - } - - if (*temp_dest != NULL_RTX) - { - seq = get_insns (); - *cost = seq_cost (seq, if_info->speed_p); - } - - end_sequence (); - - return seq; -} - /* We have something like: if (x > y) @@ -3261,6 +3198,7 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) rtx cond = noce_get_condition (jump, &cond_earliest, false); rtx x = XEXP (cond, 0); rtx y = XEXP (cond, 1); + rtx_code cond_code = GET_CODE (cond); /* The true targets for a conditional move. */ auto_vec targets; @@ -3269,139 +3207,8 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) auto_vec temporaries; /* The insns we've emitted. */ auto_vec unmodified_insns; - - hash_set need_no_cmov; - hash_map rewired_src; - - need_cmov_or_rewire (then_bb, &need_no_cmov, &rewired_src); - - int last_needs_comparison = -1; - - bool ok = noce_convert_multiple_sets_1 - (if_info, &need_no_cmov, &rewired_src, &targets, &temporaries, - &unmodified_insns, &last_needs_comparison); - if (!ok) - return false; - - /* If there are insns that overwrite part of the initial - comparison, we can still omit creating temporaries for - the last of them. - As the second try will always create a less expensive, - valid sequence, we do not need to compare and can discard - the first one. */ - if (last_needs_comparison != -1) - { - end_sequence (); - start_sequence (); - ok = noce_convert_multiple_sets_1 - (if_info, &need_no_cmov, &rewired_src, &targets, &temporaries, - &unmodified_insns, &last_needs_comparison); - /* Actually we should not fail anymore if we reached here, - but better still check. */ - if (!ok) - return false; - } - - /* We must have seen some sort of insn to insert, otherwise we were - given an empty BB to convert, and we can't handle that. */ - gcc_assert (!unmodified_insns.is_empty ()); - - /* Now fixup the assignments. */ - for (unsigned i = 0; i < targets.length (); i++) - if (targets[i] != temporaries[i]) - noce_emit_move_insn (targets[i], temporaries[i]); - - /* Actually emit the sequence if it isn't too expensive. */ - rtx_insn *seq = get_insns (); - - if (!targetm.noce_conversion_profitable_p (seq, if_info)) - { - end_sequence (); - return FALSE; - } - - for (insn = seq; insn; insn = NEXT_INSN (insn)) - set_used_flags (insn); - - /* Mark all our temporaries and targets as used. */ - for (unsigned i = 0; i < targets.length (); i++) - { - set_used_flags (temporaries[i]); - set_used_flags (targets[i]); - } - - set_used_flags (cond); - set_used_flags (x); - set_used_flags (y); - - unshare_all_rtl_in_chain (seq); - end_sequence (); - - if (!seq) - return FALSE; - - for (insn = seq; insn; insn = NEXT_INSN (insn)) - if (JUMP_P (insn) - || recog_memoized (insn) == -1) - return FALSE; - - emit_insn_before_setloc (seq, if_info->jump, - INSN_LOCATION (unmodified_insns.last ())); - - /* Clean up THEN_BB and the edges in and out of it. */ - remove_edge (find_edge (test_bb, join_bb)); - remove_edge (find_edge (then_bb, join_bb)); - redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb); - delete_basic_block (then_bb); - num_true_changes++; - - /* Maybe merge blocks now the jump is simple enough. */ - if (can_merge_blocks_p (test_bb, join_bb)) - { - merge_blocks (test_bb, join_bb); - num_true_changes++; - } - - num_updated_if_blocks++; - if_info->transform_name = "noce_convert_multiple_sets"; - return TRUE; -} - -/* This goes through all relevant insns of IF_INFO->then_bb and tries to - create conditional moves. In case a simple move sufficis the insn - should be listed in NEED_NO_CMOV. The rewired-src cases should be - specified via REWIRED_SRC. TARGETS, TEMPORARIES and UNMODIFIED_INSNS - are specified and used in noce_convert_multiple_sets and should be passed - to this function.. */ - -static bool -noce_convert_multiple_sets_1 (struct noce_if_info *if_info, - hash_set *need_no_cmov, - hash_map *rewired_src, - auto_vec *targets, - auto_vec *temporaries, - auto_vec *unmodified_insns, - int *last_needs_comparison) -{ - basic_block then_bb = if_info->then_bb; - rtx_insn *jump = if_info->jump; - rtx_insn *cond_earliest; - - /* Decompose the condition attached to the jump. */ - rtx cond = noce_get_condition (jump, &cond_earliest, false); - - rtx cc_cmp = cond_exec_get_condition (jump); - rtx rev_cc_cmp = cond_exec_get_condition (jump, /* get_reversed */ true); - - rtx_insn *insn; int count = 0; - targets->truncate (0); - temporaries->truncate (0); - unmodified_insns->truncate (0); - - bool second_try = *last_needs_comparison != -1; - FOR_BB_INSNS (then_bb, insn) { /* Skip over non-insns. */ @@ -3412,53 +3219,26 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, gcc_checking_assert (set); rtx target = SET_DEST (set); - rtx temp; - + rtx temp = gen_reg_rtx (GET_MODE (target)); rtx new_val = SET_SRC (set); - if (int *ii = rewired_src->get (insn)) - new_val = simplify_replace_rtx (new_val, (*targets)[*ii], - (*temporaries)[*ii]); rtx old_val = target; - /* As we are transforming - if (x > y) - { - a = b; - c = d; - } - into - a = (x > y) ... - c = (x > y) ... - - we potentially check x > y before every set. - Even though the check might be removed by subsequent passes, this means - that we cannot transform - if (x > y) - { - x = y; - ... - } - into - x = (x > y) ... - ... - since this would invalidate x and the following to-be-removed checks. - Therefore we introduce a temporary every time we are about to - overwrite a variable used in the check. Costing of a sequence with - these is going to be inaccurate so only use temporaries when - needed. - - If performing a second try, we know how many insns require a - temporary. For the last of these, we can omit creating one. */ - if (reg_overlap_mentioned_p (target, cond) - && (!second_try || count < *last_needs_comparison)) - temp = gen_reg_rtx (GET_MODE (target)); - else - temp = target; - - /* We have identified swap-style idioms before. A normal - set will need to be a cmov while the first instruction of a swap-style - idiom can be a regular move. This helps with costing. */ - bool need_cmov = !need_no_cmov->contains (insn); + /* If we were supposed to read from an earlier write in this block, + we've changed the register allocation. Rewire the read. While + we are looking, also try to catch a swap idiom. */ + for (int i = count - 1; i >= 0; --i) + if (reg_overlap_mentioned_p (new_val, targets[i])) + { + /* Catch a "swap" style idiom. */ + if (find_reg_note (insn, REG_DEAD, new_val) != NULL_RTX) + /* The write to targets[i] is only live until the read + here. As the condition codes match, we can propagate + the set to here. */ + new_val = SET_SRC (single_set (unmodified_insns[i])); + else + new_val = temporaries[i]; + break; + } /* If we had a non-canonical conditional jump (i.e. one where the fallthrough is to the "else" case) we need to reverse @@ -3478,9 +3258,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, we'll end up trying to emit r4:HI = cond ? (r1:SI) : (r3:HI). Wrap the two cmove operands into subregs if appropriate to prevent that. */ - - if (!CONSTANT_P (new_val) - && GET_MODE (new_val) != GET_MODE (temp)) + if (GET_MODE (new_val) != GET_MODE (temp)) { machine_mode src_mode = GET_MODE (new_val); machine_mode dst_mode = GET_MODE (temp); @@ -3491,8 +3269,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, } new_val = lowpart_subreg (dst_mode, new_val, src_mode); } - if (!CONSTANT_P (old_val) - && GET_MODE (old_val) != GET_MODE (temp)) + if (GET_MODE (old_val) != GET_MODE (temp)) { machine_mode src_mode = GET_MODE (old_val); machine_mode dst_mode = GET_MODE (temp); @@ -3504,80 +3281,101 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info, old_val = lowpart_subreg (dst_mode, old_val, src_mode); } - /* Try emitting a conditional move passing the backend the - canonicalized comparison. The backend is then able to - recognize expressions like - - if (x > y) - y = x; - - as min/max and emit an insn, accordingly. */ - unsigned cost1 = 0, cost2 = 0; - rtx_insn *seq, *seq1, *seq2; - rtx temp_dest = NULL_RTX, temp_dest1 = NULL_RTX, temp_dest2 = NULL_RTX; + /* Actually emit the conditional move. */ + rtx temp_dest = noce_emit_cmove (if_info, temp, cond_code, + x, y, new_val, old_val); - seq1 = try_emit_cmove_seq (if_info, temp, cond, - new_val, old_val, need_cmov, - &cost1, &temp_dest1); - - /* Here, we try to pass the backend a non-canonicalized cc comparison - as well. This allows the backend to emit a cmov directly without - creating an additional compare for each. If successful, costing - is easier and this sequence is usually preferred. */ - seq2 = try_emit_cmove_seq (if_info, target, cond, - new_val, old_val, need_cmov, - &cost2, &temp_dest2, cc_cmp, rev_cc_cmp); - - /* Check which version is less expensive. */ - if (seq1 != NULL_RTX && (cost1 <= cost2 || seq2 == NULL_RTX)) - { - seq = seq1; - temp_dest = temp_dest1; - if (!second_try) - *last_needs_comparison = count; - } - else if (seq2 != NULL_RTX) - { - seq = seq2; - temp_dest = temp_dest2; - } - else + /* If we failed to expand the conditional move, drop out and don't + try to continue. */ + if (temp_dest == NULL_RTX) { - /* Nothing worked, bail out. */ end_sequence (); return FALSE; } - /* End the sub sequence and emit to the main sequence. */ - emit_insn (seq); - /* Bookkeeping. */ count++; - targets->safe_push (target); - temporaries->safe_push (temp_dest); - unmodified_insns->safe_push (insn); + targets.safe_push (target); + temporaries.safe_push (temp_dest); + unmodified_insns.safe_push (insn); } - return true; -} + /* We must have seen some sort of insn to insert, otherwise we were + given an empty BB to convert, and we can't handle that. */ + gcc_assert (!unmodified_insns.is_empty ()); + + /* Now fixup the assignments. */ + for (int i = 0; i < count; i++) + noce_emit_move_insn (targets[i], temporaries[i]); + + /* Actually emit the sequence if it isn't too expensive. */ + rtx_insn *seq = get_insns (); + + if (!targetm.noce_conversion_profitable_p (seq, if_info)) + { + end_sequence (); + return FALSE; + } + + for (insn = seq; insn; insn = NEXT_INSN (insn)) + set_used_flags (insn); + + /* Mark all our temporaries and targets as used. */ + for (int i = 0; i < count; i++) + { + set_used_flags (temporaries[i]); + set_used_flags (targets[i]); + } + set_used_flags (cond); + set_used_flags (x); + set_used_flags (y); + unshare_all_rtl_in_chain (seq); + end_sequence (); + + if (!seq) + return FALSE; + + for (insn = seq; insn; insn = NEXT_INSN (insn)) + if (JUMP_P (insn) + || recog_memoized (insn) == -1) + return FALSE; + + emit_insn_before_setloc (seq, if_info->jump, + INSN_LOCATION (unmodified_insns.last ())); + + /* Clean up THEN_BB and the edges in and out of it. */ + remove_edge (find_edge (test_bb, join_bb)); + remove_edge (find_edge (then_bb, join_bb)); + redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb); + delete_basic_block (then_bb); + num_true_changes++; + + /* Maybe merge blocks now the jump is simple enough. */ + if (can_merge_blocks_p (test_bb, join_bb)) + { + merge_blocks (test_bb, join_bb); + num_true_changes++; + } + + num_updated_if_blocks++; + if_info->transform_name = "noce_convert_multiple_sets"; + return TRUE; +} /* Return true iff basic block TEST_BB is comprised of only (SET (REG) (REG)) insns suitable for conversion to a series of conditional moves. Also check that we have more than one set (other routines can handle a single set better than we would), and - fewer than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets. While going - through the insns store the sum of their potential costs in COST. */ + fewer than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets. */ static bool -bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost) +bb_ok_for_noce_convert_multiple_sets (basic_block test_bb) { rtx_insn *insn; unsigned count = 0; unsigned param = param_max_rtl_if_conversion_insns; - bool speed_p = optimize_bb_for_speed_p (test_bb); - unsigned potential_cost = 0; FOR_BB_INSNS (test_bb, insn) { @@ -3600,9 +3398,9 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost) if (!REG_P (dest)) return false; - if (!((REG_P (src) || CONSTANT_P (src)) - || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) - && subreg_lowpart_p (src)))) + if (!(REG_P (src) + || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) + && subreg_lowpart_p (src)))) return false; /* Destination must be appropriate for a conditional write. */ @@ -3613,13 +3411,9 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost) if (!can_conditionally_move_p (GET_MODE (dest))) return false; - potential_cost += insn_cost (insn, speed_p); - count++; } - *cost += potential_cost; - /* If we would only put out one conditional move, the other strategies this pass tries are better optimized and will be more appropriate. Some targets want to strictly limit the number of conditional moves @@ -3667,24 +3461,11 @@ noce_process_if_block (struct noce_if_info *if_info) to calculate a value for x. ??? For future expansion, further expand the "multiple X" rules. */ - /* First look for multiple SETS. The original costs already include - a base cost of COSTS_N_INSNS (2): one instruction for the compare - (which we will be needing either way) and one instruction for the - branch. When comparing costs we want to use the branch instruction - cost and the sets vs. the cmovs generated here. Therefore subtract - the costs of the compare before checking. - ??? Actually, instead of the branch instruction costs we might want - to use COSTS_N_INSNS (BRANCH_COST ()) as in other places. */ - - unsigned potential_cost = if_info->original_cost - COSTS_N_INSNS (1); - unsigned old_cost = if_info->original_cost; + /* First look for multiple SETS. */ if (!else_bb && HAVE_conditional_move - && bb_ok_for_noce_convert_multiple_sets (then_bb, &potential_cost)) + && bb_ok_for_noce_convert_multiple_sets (then_bb)) { - /* Temporarily set the original costs to what we estimated so - we can determine if the transformation is worth it. */ - if_info->original_cost = potential_cost; if (noce_convert_multiple_sets (if_info)) { if (dump_file && if_info->transform_name) @@ -3692,9 +3473,6 @@ noce_process_if_block (struct noce_if_info *if_info) if_info->transform_name); return TRUE; } - - /* Restore the original costs. */ - if_info->original_cost = old_cost; } bool speed_p = optimize_bb_for_speed_p (test_bb); @@ -4036,89 +3814,6 @@ check_cond_move_block (basic_block bb, return TRUE; } -/* Find local swap-style idioms in BB and mark the first insn (1) - that is only a temporary as not needing a conditional move as - it is going to be dead afterwards anyway. - - (1) int tmp = a; - a = b; - b = tmp; - - ifcvt - --> - - tmp = a; - a = cond ? b : a_old; - b = cond ? tmp : b_old; - - Additionally, store the index of insns like (2) when a subsequent - SET reads from their destination. - - (2) int c = a; - int d = c; - - ifcvt - --> - - c = cond ? a : c_old; - d = cond ? d : c; // Need to use c rather than c_old here. -*/ - -static void -need_cmov_or_rewire (basic_block bb, - hash_set *need_no_cmov, - hash_map *rewired_src) -{ - rtx_insn *insn; - int count = 0; - auto_vec insns; - auto_vec dests; - - /* Iterate over all SETs, storing the destinations - in DEST. - - If we hit a SET that reads from a destination - that we have seen before and the corresponding register - is dead afterwards, the register does not need to be - moved conditionally. - - If we encounter a previously changed register, - rewire the read to the original source. */ - FOR_BB_INSNS (bb, insn) - { - rtx set, src, dest; - - if (!active_insn_p (insn)) - continue; - - set = single_set (insn); - if (set == NULL_RTX) - continue; - - src = SET_SRC (set); - if (SUBREG_P (src)) - src = SUBREG_REG (src); - dest = SET_DEST (set); - - /* Check if the current SET's source is the same - as any previously seen destination. - This is quadratic but the number of insns in BB - is bounded by PARAM_MAX_RTL_IF_CONVERSION_INSNS. */ - if (REG_P (src)) - for (int i = count - 1; i >= 0; --i) - if (reg_overlap_mentioned_p (src, dests[i])) - { - if (find_reg_note (insn, REG_DEAD, src) != NULL_RTX) - need_no_cmov->add (insns[i]); - else - rewired_src->put (insn, i); - } - - insns.safe_push (insn); - dests.safe_push (dest); - - count++; - } -} - /* Given a basic block BB suitable for conditional move conversion, a condition COND, and pointer maps THEN_VALS and ELSE_VALS containing the register values depending on COND, emit the insns in the block as --- gcc/optabs.cc +++ gcc/optabs.cc @@ -52,8 +52,6 @@ static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *, static rtx expand_unop_direct (machine_mode, optab, rtx, rtx, int); static void emit_libcall_block_1 (rtx_insn *, rtx, rtx, rtx, bool); -static rtx emit_conditional_move_1 (rtx, rtx, rtx, rtx, machine_mode); - /* Debug facility for use in GDB. */ void debug_optab_libfuncs (void); @@ -626,13 +624,12 @@ expand_doubleword_shift_condmove (scalar_int_mode op1_mode, optab binoptab, /* Select between them. Do the INTO half first because INTO_SUPERWORD might be the current value of OUTOF_TARGET. */ - if (!emit_conditional_move (into_target, { cmp_code, cmp1, cmp2, op1_mode }, + if (!emit_conditional_move (into_target, cmp_code, cmp1, cmp2, op1_mode, into_target, into_superword, word_mode, false)) return false; if (outof_target != 0) - if (!emit_conditional_move (outof_target, - { cmp_code, cmp1, cmp2, op1_mode }, + if (!emit_conditional_move (outof_target, cmp_code, cmp1, cmp2, op1_mode, outof_target, outof_superword, word_mode, false)) return false; @@ -4854,8 +4851,8 @@ emit_indirect_jump (rtx loc) is not supported. */ rtx -emit_conditional_move (rtx target, struct rtx_comparison comp, - rtx op2, rtx op3, +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) { rtx comparison; @@ -4877,33 +4874,31 @@ emit_conditional_move (rtx target, struct rtx_comparison comp, /* If one operand is constant, make it the second one. Only do this if the other operand is not constant as well. */ - if (swap_commutative_operands_p (comp.op0, comp.op1)) + if (swap_commutative_operands_p (op0, op1)) { - std::swap (comp.op0, comp.op1); - comp.code = swap_condition (comp.code); + std::swap (op0, op1); + code = swap_condition (code); } /* get_condition will prefer to generate LT and GT even if the old comparison was against zero, so undo that canonicalization here since comparisons against zero are cheaper. */ + if (code == LT && op1 == const1_rtx) + code = LE, op1 = const0_rtx; + else if (code == GT && op1 == constm1_rtx) + code = GE, op1 = const0_rtx; - if (comp.code == LT && comp.op1 == const1_rtx) - comp.code = LE, comp.op1 = const0_rtx; - else if (comp.code == GT && comp.op1 == constm1_rtx) - comp.code = GE, comp.op1 = const0_rtx; - - if (comp.mode == VOIDmode) - comp.mode = GET_MODE (comp.op0); + if (cmode == VOIDmode) + cmode = GET_MODE (op0); - enum rtx_code orig_code = comp.code; + enum rtx_code orig_code = code; bool swapped = false; if (swap_commutative_operands_p (op2, op3) - && ((reversed = - reversed_comparison_code_parts (comp.code, comp.op0, comp.op1, NULL)) - != UNKNOWN)) + && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL)) + != UNKNOWN)) { std::swap (op2, op3); - comp.code = reversed; + code = reversed; swapped = true; } @@ -4920,10 +4915,8 @@ emit_conditional_move (rtx target, struct rtx_comparison comp, for (int pass = 0; ; pass++) { - comp.code = unsignedp ? unsigned_condition (comp.code) : comp.code; - comparison = - simplify_gen_relational (comp.code, VOIDmode, - comp.mode, comp.op0, comp.op1); + code = unsignedp ? unsigned_condition (code) : code; + comparison = simplify_gen_relational (code, VOIDmode, cmode, op0, op1); /* We can get const0_rtx or const_true_rtx in some circumstances. Just punt and let the caller figure out how best to deal with this @@ -4934,16 +4927,24 @@ emit_conditional_move (rtx target, struct rtx_comparison comp, save_pending_stack_adjust (&save); last = get_last_insn (); do_pending_stack_adjust (); - machine_mode cmpmode = comp.mode; + machine_mode cmpmode = cmode; prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1), GET_CODE (comparison), NULL_RTX, unsignedp, OPTAB_WIDEN, &comparison, &cmpmode); if (comparison) { - rtx res = emit_conditional_move_1 (target, comparison, - op2, op3, mode); - if (res != NULL_RTX) - return res; + class expand_operand ops[4]; + + create_output_operand (&ops[0], target, mode); + 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)) + { + if (ops[0].value != target) + convert_move (target, ops[0].value, false); + return target; + } } delete_insns_since (last); restore_pending_stack_adjust (&save); @@ -4955,88 +4956,17 @@ emit_conditional_move (rtx target, struct rtx_comparison comp, /* If the preferred op2/op3 order is not usable, retry with other operand order, perhaps it will expand successfully. */ if (swapped) - comp.code = orig_code; - else if ((reversed = - reversed_comparison_code_parts (orig_code, comp.op0, comp.op1, + code = orig_code; + else if ((reversed = reversed_comparison_code_parts (orig_code, op0, op1, NULL)) != UNKNOWN) - comp.code = reversed; + code = reversed; else return NULL_RTX; std::swap (op2, op3); } } -/* Helper function that, in addition to COMPARISON, also tries - the reversed REV_COMPARISON with swapped OP2 and OP3. As opposed - to when we pass the specific constituents of a comparison, no - additional insns are emitted for it. It might still be necessary - to emit more than one insn for the final conditional move, though. */ - -rtx -emit_conditional_move (rtx target, rtx comparison, rtx rev_comparison, - rtx op2, rtx op3, machine_mode mode) -{ - rtx res = emit_conditional_move_1 (target, comparison, op2, op3, mode); - - if (res != NULL_RTX) - return res; - - return emit_conditional_move_1 (target, rev_comparison, op3, op2, mode); -} - -/* Helper for emitting a conditional move. */ - -static rtx -emit_conditional_move_1 (rtx target, rtx comparison, - rtx op2, rtx op3, machine_mode mode) -{ - enum insn_code icode; - - if (comparison == NULL_RTX || !COMPARISON_P (comparison)) - return NULL_RTX; - - /* If the two source operands are identical, that's just a move. - As the comparison comes in non-canonicalized, we must make - sure not to discard any possible side effects. If there are - side effects, just let the target handle it. */ - if (!side_effects_p (comparison) && rtx_equal_p (op2, op3)) - { - if (!target) - target = gen_reg_rtx (mode); - - emit_move_insn (target, op3); - return target; - } - - if (mode == VOIDmode) - mode = GET_MODE (op2); - - icode = direct_optab_handler (movcc_optab, mode); - - if (icode == CODE_FOR_nothing) - return NULL_RTX; - - if (!target) - target = gen_reg_rtx (mode); - - class expand_operand ops[4]; - - create_output_operand (&ops[0], target, mode); - 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)) - { - if (ops[0].value != target) - convert_move (target, ops[0].value, false); - return target; - } - - return NULL_RTX; -} - /* Emit a conditional negate or bitwise complement using the negcc or notcc optabs if available. Return NULL_RTX if such operations --- gcc/optabs.h +++ gcc/optabs.h @@ -279,8 +279,8 @@ extern void emit_indirect_jump (rtx); #endif /* Emit a conditional move operation. */ -rtx emit_conditional_move (rtx, rtx_comparison, rtx, rtx, machine_mode, int); -rtx emit_conditional_move (rtx, rtx, rtx, rtx, rtx, machine_mode); +rtx emit_conditional_move (rtx, enum rtx_code, rtx, rtx, machine_mode, + rtx, rtx, machine_mode, int); /* Emit a conditional negate or bitwise complement operation. */ rtx emit_conditional_neg_or_complement (rtx, rtx_code, machine_mode, rtx, --- gcc/rtl.h +++ gcc/rtl.h @@ -4604,16 +4604,7 @@ word_register_operation_p (const_rtx x) return true; } } - -/* Holds an rtx comparison to simplify passing many parameters pertaining to a - single comparison. */ - -struct rtx_comparison { - rtx_code code; - rtx op0, op1; - machine_mode mode; -}; - + /* gtype-desc.cc. */ extern void gt_ggc_mx (rtx &); extern void gt_pch_nx (rtx &);