This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR target/11087
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Henderson <rth at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 17 Jul 2003 10:59:08 +0200
- Subject: [PATCH] Fix PR target/11087
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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