aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2003-07-18 13:13:37 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2003-07-18 13:13:37 +0200
commit16f6812f86b9095a7b38d1a6cbe665bc801ca50a (patch)
treeb37326901374d1542b48895f7a8d13061117176b
parent2d5f9af2bf821d062b6e089e15ccbae915aa1efe (diff)
downloadgcc-16f6812f86b9095a7b38d1a6cbe665bc801ca50a.zip
gcc-16f6812f86b9095a7b38d1a6cbe665bc801ca50a.tar.gz
gcc-16f6812f86b9095a7b38d1a6cbe665bc801ca50a.tar.bz2
re PR target/11087 (gcc miscompiles raid1.c from linux kernel)
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. From-SVN: r69552
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/loop.c33
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20030717-1.c69
4 files changed, 110 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2166ec5..1162471 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+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.
+
2003-07-18 Eric Botcazou <ebotcazou@libertysurf.fr>
PR optimization/11083
diff --git a/gcc/loop.c b/gcc/loop.c
index 71c322c..683d83a 100644
--- a/gcc/loop.c
+++ b/gcc/loop.c
@@ -6197,7 +6197,7 @@ basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
{
enum rtx_code code;
rtx *argp, arg;
- rtx insn, set = 0;
+ rtx insn, set = 0, last, inc;
code = GET_CODE (x);
*location = NULL;
@@ -6225,7 +6225,26 @@ basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
if (loop_invariant_p (loop, arg) != 1)
return 0;
- *inc_val = convert_modes (GET_MODE (dest_reg), GET_MODE (x), arg, 0);
+ /* convert_modes can emit new instructions, e.g. when arg is a loop
+ invariant MEM and dest_reg has a different mode.
+ These instructions would be emitted after the end of the function
+ and then *inc_val would be an unitialized pseudo.
+ Detect this and bail in this case.
+ Other alternatives to solve this can be introducing a convert_modes
+ variant which is allowed to fail but not allowed to emit new
+ instructions, emit these instructions before loop start and let
+ it be garbage collected if *inc_val is never used or saving the
+ *inc_val initialization sequence generated here and when *inc_val
+ is going to be actually used, emit it at some suitable place. */
+ 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;
@@ -6306,7 +6325,15 @@ basic_induction_var (const struct loop *loop, rtx x, enum machine_mode mode,
&& 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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c69031a..70c6936 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2003-07-17 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/11087
+ * gcc.c-torture/execute/20030717-1.c: New test.
+
2003-07-18 Eric Botcazou <ebotcazou@libertysurf.fr>
* g++.dg/opt/cfg1.C: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/20030717-1.c b/gcc/testsuite/gcc.c-torture/execute/20030717-1.c
new file mode 100644
index 0000000..7e43e44
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20030717-1.c
@@ -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;
+}