@@ -84,7 +84,7 @@ static rtx_insn *find_active_insn_after (basic_block, rtx_insn *);
static basic_block block_fallthru (basic_block);
static int cond_exec_process_insns (ce_if_block *, rtx_insn *, rtx, rtx, int,
int);
-static rtx cond_exec_get_condition (rtx_insn *);
+static rtx get_condition_from_jump (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 *);
@@ -421,7 +421,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)
+get_condition_from_jump (rtx_insn *jump)
{
rtx test_if, cond;
@@ -493,7 +493,7 @@ cond_exec_process_if_block (ce_if_block * ce_info,
/* Find the conditional jump to the ELSE or JOIN part, and isolate
the test. */
- test_expr = cond_exec_get_condition (BB_END (test_bb));
+ test_expr = get_condition_from_jump (BB_END (test_bb));
if (! test_expr)
return FALSE;
@@ -652,7 +652,7 @@ cond_exec_process_if_block (ce_if_block * ce_info,
goto fail;
/* Find the conditional jump and isolate the test. */
- t = cond_exec_get_condition (BB_END (bb));
+ t = get_condition_from_jump (BB_END (bb));
if (! t)
goto fail;
@@ -2017,6 +2017,29 @@ noce_emit_bb (rtx last_insn, basic_block bb, bool simple)
return true;
}
+/* For basic block BB record in USES_CC and CLOBBERS_CC whether it
+ uses and/or clobbers the condition code register CC. */
+
+static void
+noce_record_cc_use_in_bb (basic_block bb, rtx cc,
+ bool *uses_cc, bool *clobbers_cc)
+{
+ rtx_insn *insn = NULL;
+ *uses_cc = false;
+ *clobbers_cc = false;
+ if (!cc)
+ return;
+ FOR_BB_INSNS (bb, insn)
+ {
+ if (!active_insn_p (insn))
+ continue;
+
+ *clobbers_cc |= set_of (cc, PATTERN (insn)) != NULL_RTX;
+ *uses_cc |= reg_mentioned_p (cc, SET_SRC (single_set (insn)));
+ }
+}
+
+
/* Try more complex cases involving conditional_move. */
static int
@@ -2202,6 +2225,26 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
}
}
+ bool then_uses_cc = false;
+ bool then_clobbers_cc = false;
+ bool else_uses_cc = false;
+ bool else_clobbers_cc = false;
+
+ rtx cc = cc_in_cond (if_info->cond);
+ /* If there is no condition code register in cond
+ (noce_get_condition could have replaced it) look into the original
+ jump condition. */
+ if (!cc)
+ {
+ rtx jmp_cond = get_condition_from_jump (if_info->jump);
+ if (jmp_cond)
+ cc = cc_in_cond (jmp_cond);
+ }
+ if (then_bb)
+ noce_record_cc_use_in_bb (then_bb, cc, &then_uses_cc, &then_clobbers_cc);
+ if (else_bb)
+ noce_record_cc_use_in_bb (else_bb, cc, &else_uses_cc, &else_clobbers_cc);
+
modified_in_a = emit_a != NULL_RTX && modified_in_p (orig_b, emit_a);
if (tmp_b && then_bb)
{
@@ -2233,8 +2276,10 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
/* If insn to set up A clobbers any registers B depends on, try to
swap insn that sets up A with the one that sets up B. If even
- that doesn't help, punt. */
- if (modified_in_a && !modified_in_b)
+ that doesn't help, punt. Make sure one basic block doesn't clobber
+ the condition code register before the other uses it. */
+ if (modified_in_a && !modified_in_b
+ && !(then_uses_cc && else_clobbers_cc))
{
if (!noce_emit_bb (emit_b, else_bb, b_simple))
goto end_seq_and_fail;
@@ -2242,7 +2287,8 @@ noce_try_cmove_arith (struct noce_if_info *if_info)
if (!noce_emit_bb (emit_a, then_bb, a_simple))
goto end_seq_and_fail;
}
- else if (!modified_in_a)
+ else if (!modified_in_a
+ && !(else_uses_cc && then_clobbers_cc))
{
if (!noce_emit_bb (emit_a, then_bb, a_simple))
goto end_seq_and_fail;
@@ -5045,7 +5091,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
rtx cond;
- cond = cond_exec_get_condition (jump);
+ cond = get_condition_from_jump (jump);
if (! cond)
return FALSE;
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-Og -fif-conversion -flive-range-shrinkage -fpeel-loops -frerun-cse-after-loop" } */
+
+static inline int
+foo (int *x, int y)
+{
+ int z = *x;
+ while (y > z)
+ z *= 2;
+ return z;
+}
+
+int
+main ()
+{
+ int i;
+ for (i = 1; i < 17; i++)
+ {
+ int j;
+ int k;
+ j = foo (&i, 7);
+ if (i >= 7)
+ k = i;
+ else if (i >= 4)
+ k = 8 + (i - 4) * 2;
+ else if (i == 3)
+ k = 12;
+ else
+ k = 8;
+ if (j != k)
+ __builtin_abort ();
+ }
+ return 0;
+}