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 PR target/11087


Hi!

The following testcase is miscompiled at least on gcc-3_2-rhl8-branch on
ppc64. I cannot reproduce it on mainline, but it is not because the bug
is fixed there, just that basic_induction_var is not called with such
arguments (the difference is that into loop in one case goes
pseudo1:SI := loop_invariant mem:SI ()
pseudo2:DI := sign_extend:DI (pseudo1:SI)
and in the other case just
pseudo1:DI := sign_extend:DI (loop_invariant mem:SI ())
).
The problem I see is that basic_induction_var does not expect convert_modes
to emit any new instructions (it is not called within any new sequence,
so the emitted instructions go after the function's end and are garbage
collected by life analysis). In this particular case, convert_modes is
called with
(DImode, SImode, [(mem/s:SI (plus:DI (reg/v/f:DI 116) (const_int 20)))], 0),
creates 2 new pseudos and emits 2 new insns (1 to load the mem into SImode
pseudo, one to sign_extend it into a DImode pseudo which is returned).
There are workarounds for egcs bugs on sparc64 in the same routine
in linux kernel, so I think it is likely the same problem which resurfaced
again.
The following patch uses delete_insns_since () if any new insns were created
(and returns 0 in that case). Other alternatives include creating
convert_modes variant which is allowed to fail, but not allowed to emit
any instructions, change loop so that it can record some BIV
initialization sequence and if it is used, emit it before the loop,
or emit the possible sequence unconditionally before loop and let it be
garbage collected if inc_val etc. is not used.

2003-07-17  Jakub Jelinek  <jakub@redhat.com>

	PR target/11087
	* loop.c (basic_induction_var): Check if convert_modes emitted any
	instructions. Remove them and return 0 if so.

	* gcc.c-torture/execute/20030717-1.c: New test.

--- gcc/loop.c.jj	2003-04-28 06:14:32.000000000 -0400
+++ gcc/loop.c	2003-07-17 04:19:25.000000000 -0400
@@ -6157,7 +6157,7 @@ basic_induction_var (loop, x, mode, dest
 {
   enum rtx_code code;
   rtx *argp, arg;
-  rtx insn, set = 0;
+  rtx insn, set = 0, last, inc;
 
   code = GET_CODE (x);
   *location = NULL;
@@ -6185,7 +6185,14 @@ basic_induction_var (loop, x, mode, dest
       if (loop_invariant_p (loop, arg) != 1)
 	return 0;
 
-      *inc_val = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
+      last = get_last_insn ();
+      inc = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
+      if (get_last_insn () != last)
+	{
+	  delete_insns_since (last);
+	  return 0;
+	}
+      *inc_val = inc;
       *mult_val = const1_rtx;
       *location = argp;
       return 1;
@@ -6266,7 +6273,14 @@ basic_induction_var (loop, x, mode, dest
 	  && GET_MODE_CLASS (mode) != MODE_CC)
 	{
 	  /* Possible bug here?  Perhaps we don't know the mode of X.  */
-	  *inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
+	  last = get_last_insn ();
+	  inc = convert_modes (GET_MODE (dest_reg), mode, x, 0);
+	  if (get_last_insn () != last)
+	    {
+	      delete_insns_since (last);
+	      return 0;
+	    }
+	  *inc_val = inc;
 	  *mult_val = const0_rtx;
 	  return 1;
 	}
--- gcc/testsuite/gcc.c-torture/execute/20030717-1.c.jj	2003-07-17 04:39:29.000000000 -0400
+++ gcc/testsuite/gcc.c-torture/execute/20030717-1.c	2003-07-17 04:38:28.000000000 -0400
@@ -0,0 +1,69 @@
+/* PR target/11087
+   This testcase was miscompiled on ppc64, because basic_induction_var called
+   convert_modes, yet did not expect it to emit any new instructions.
+   Those were emitted at the end of the function and destroyed during life
+   analysis, while the program used uninitialized pseudos created by
+   convert_modes.  */
+
+struct A
+{
+  unsigned short a1;
+  unsigned long a2;
+};
+
+struct B
+{
+  int b1, b2, b3, b4, b5;
+};
+
+struct C
+{
+  struct B c1[1];
+  int c2, c3;
+};
+
+static
+int foo (int x)
+{
+  return  x < 0 ? -x : x;
+}
+
+int bar (struct C *x, struct A *y)
+{
+  int a = x->c3;
+  const int b = y->a1 >> 9;
+  const unsigned long c = y->a2;
+  int d = a;
+  unsigned long e, f;
+
+  f = foo (c - x->c1[d].b4);
+  do
+    {
+      if (d <= 0)
+	d = x->c2;
+      d--;
+
+      e = foo (c-x->c1[d].b4);
+      if (e < f)
+	a = d;
+    }
+  while (d != x->c3);
+  x->c1[a].b4 = c + b;
+  return a;
+}
+
+int
+main ()
+{
+  struct A a;
+  struct C b;
+  int c;
+
+  a.a1 = 512;
+  a.a2 = 4242;
+  __builtin_memset (&b, 0, sizeof (b));
+  b.c1[0].b3 = 424242;
+  b.c2 = 1;
+  c = bar (&b, &a);
+  return 0;
+}

	Jakub


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