This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix noce_try_cmove_arith (PR rtl-optimization/19579)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]