This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix noce_try_cmove_arith (PR rtl-optimization/19579)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 24 Jan 2005 09:11:36 -0500
- Subject: [PATCH] Fix noce_try_cmove_arith (PR rtl-optimization/19579)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following patch fixes a miscompilation due to noce_try_cmove_arith.
When emitting preparation instructions for the conditional move, it doesn't
check whether the instructions don't clobber each other's dependencies.
On the testcase below, A is (plus:SI (reg/v:SI 59 [ i ]) (const_int 2 [0x2])))
and B is (if_then_else:SI (ge (reg:CC 17 flags) (const_int 0 [0x0]))
(reg/v:SI 61 [ k ]) (reg/v:SI 59 [ i ]))
but the instruction to set up A is:
(insn 59 60 61 1 (parallel [
(set (reg:SI 63)
(plus:SI (reg/v:SI 59 [ i ])
(const_int 2 [0x2])))
(clobber (reg:CC 17 flags))
]) 196 {*addsi_1} (nil)
(expr_list:REG_DEAD (reg/v:SI 59 [ i ])
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil))))
and thus CC register that B depends on is clobbered by it.
The patch below attempts to swap insn to set up A with insn to set up B,
and if even that doesn't help, punts.
Ok for 3.4/HEAD?
2005-01-24 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/19579
* ifcvt.c (noce_try_cmove_arith): If emitting instructions to set up
both A and B, see if they don't clobber registers the other expr uses.
* gcc.c-torture/execute/20050124-1.c: New test.
--- gcc/ifcvt.c.jj 2004-06-22 15:11:57.000000000 +0200
+++ gcc/ifcvt.c 2005-01-24 14:42:06.605517266 +0100
@@ -1193,6 +1193,7 @@ noce_try_cmove_arith (struct noce_if_inf
rtx a = if_info->a;
rtx b = if_info->b;
rtx x = if_info->x;
+ rtx orig_a, orig_b;
rtx insn_a, insn_b;
rtx tmp, target;
int is_mem = 0;
@@ -1248,6 +1249,9 @@ noce_try_cmove_arith (struct noce_if_inf
start_sequence ();
+ orig_a = a;
+ orig_b = b;
+
/* If either operand is complex, load it into a register first.
The best way to do this is to copy the original insn. In this
way we preserve any clobbers etc that the insn may have had.
@@ -1279,7 +1283,7 @@ noce_try_cmove_arith (struct noce_if_inf
}
if (! general_operand (b, GET_MODE (b)))
{
- rtx set;
+ rtx set, last;
if (no_new_pseudos)
goto end_seq_and_fail;
@@ -1287,9 +1291,7 @@ noce_try_cmove_arith (struct noce_if_inf
if (is_mem)
{
tmp = gen_reg_rtx (GET_MODE (b));
- tmp = emit_insn (gen_rtx_SET (VOIDmode,
- tmp,
- b));
+ tmp = gen_rtx_SET (VOIDmode, tmp, b);
}
else if (! insn_b)
goto end_seq_and_fail;
@@ -1299,8 +1301,22 @@ noce_try_cmove_arith (struct noce_if_inf
tmp = copy_rtx (insn_b);
set = single_set (tmp);
SET_DEST (set) = b;
- tmp = emit_insn (PATTERN (tmp));
+ tmp = PATTERN (tmp);
}
+
+ /* 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. */
+ last = get_last_insn ();
+ if (last && modified_in_p (orig_b, last))
+ {
+ tmp = emit_insn_before (tmp, get_insns ());
+ if (modified_in_p (orig_a, tmp))
+ goto end_seq_and_fail;
+ }
+ else
+ tmp = emit_insn (tmp);
+
if (recog_memoized (tmp) < 0)
goto end_seq_and_fail;
}
--- gcc/testsuite/gcc.c-torture/execute/20050124-1.c.jj 2005-01-24 14:48:37.546585122 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20050124-1.c 2005-01-24 14:34:22.000000000 +0100
@@ -0,0 +1,41 @@
+/* PR rtl-optimization/19579 */
+
+extern void abort (void);
+
+int
+foo (int i, int j)
+{
+ int k = i + 1;
+
+ if (j)
+ {
+ if (k > 0)
+ k++;
+ else if (k < 0)
+ k--;
+ }
+
+ return k;
+}
+
+int
+main (void)
+{
+ if (foo (-2, 0) != -1)
+ abort ();
+ if (foo (-1, 0) != 0)
+ abort ();
+ if (foo (0, 0) != 1)
+ abort ();
+ if (foo (1, 0) != 2)
+ abort ();
+ if (foo (-2, 1) != -2)
+ abort ();
+ if (foo (-1, 1) != 0)
+ abort ();
+ if (foo (0, 1) != 2)
+ abort ();
+ if (foo (1, 1) != 3)
+ abort ();
+ return 0;
+}
Jakub