Commit 16f6812f by Jakub Jelinek Committed by Jakub Jelinek

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
parent 2d5f9af2
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
......
......@@ -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;
}
......
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.
......
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment