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
This commit is contained in:
Jakub Jelinek 2003-07-18 13:13:37 +02:00 committed by Jakub Jelinek
parent 2d5f9af2bf
commit 16f6812f86
4 changed files with 110 additions and 3 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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;
}