From 46662f25ea011aa367beab9b6dd6276a47c4e48a Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Wed, 6 Aug 2008 15:34:45 +0000 Subject: [PATCH] re PR target/36613 (likely codegen bug) PR target/36613 * reload.c (push_reload): Merge in,out,in_reg,out_reg members for reused reload, instead of overwriting them. * gcc.target/i386/pr36613.c: New testcase. From-SVN: r138807 --- gcc/ChangeLog | 6 ++++ gcc/reload.c | 31 ++++++++++++++--- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.target/i386/pr36613.c | 44 +++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr36613.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a22491f20e0..a08bd6e6f69 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2008-08-06 Michael Matz + + PR target/36613 + * reload.c (push_reload): Merge in,out,in_reg,out_reg members + for reused reload, instead of overwriting them. + 2008-08-06 H.J. Lu PR middle-end/37009 diff --git a/gcc/reload.c b/gcc/reload.c index 93fff404569..5a79c44e874 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -1403,13 +1403,36 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, else remove_address_replacements (rld[i].in); } - rld[i].in = in; - rld[i].in_reg = in_reg; + /* When emitting reloads we don't necessarily look at the in- + and outmode, but also directly at the operands (in and out). + So we can't simply overwrite them with whatever we have found + for this (to-be-merged) reload, we have to "merge" that too. + Reusing another reload already verified that we deal with the + same operands, just possibly in different modes. So we + overwrite the operands only when the new mode is larger. + See also PR33613. */ + if (!rld[i].in + || GET_MODE_SIZE (GET_MODE (in)) + > GET_MODE_SIZE (GET_MODE (rld[i].in))) + rld[i].in = in; + if (!rld[i].in_reg + || (in_reg + && GET_MODE_SIZE (GET_MODE (in_reg)) + > GET_MODE_SIZE (GET_MODE (rld[i].in_reg)))) + rld[i].in_reg = in_reg; } if (out != 0) { - rld[i].out = out; - rld[i].out_reg = outloc ? *outloc : 0; + if (!rld[i].out + || (out + && GET_MODE_SIZE (GET_MODE (out)) + > GET_MODE_SIZE (GET_MODE (rld[i].out)))) + rld[i].out = out; + if (outloc + && (!rld[i].out_reg + || GET_MODE_SIZE (GET_MODE (*outloc)) + > GET_MODE_SIZE (GET_MODE (rld[i].out_reg)))) + rld[i].out_reg = *outloc; } if (reg_class_subset_p (rclass, rld[i].rclass)) rld[i].rclass = rclass; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ead96385f80..d5b229a70e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-08-06 Michael Matz + + PR target/36613 + * gcc.target/i386/pr36613.c: New testcase. + 2008-08-06 H.J. Lu PR middle-end/37009 diff --git a/gcc/testsuite/gcc.target/i386/pr36613.c b/gcc/testsuite/gcc.target/i386/pr36613.c new file mode 100644 index 00000000000..e9d7d11cedc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr36613.c @@ -0,0 +1,44 @@ +/* { dg-do run { target { { i?86-*-linux* x86_64-*-linux* } && ilp32 } } } */ +/* { dg-options "-Os" } */ +/* PR target/36613 */ + +extern void abort (void); + +static inline int +lshifts (int val, int cnt) +{ + if (val < 0) + return val; + return val << cnt; +} + +static inline unsigned int +lshiftu (unsigned int val, unsigned int cnt) +{ + if (cnt >= sizeof (unsigned int) * __CHAR_BIT__ + || val > ((__INT_MAX__ * 2U) >> cnt)) + return val; + return val << cnt; +} + +static inline int +rshifts (int val, unsigned int cnt) +{ + if (val < 0 || cnt >= sizeof (int) * __CHAR_BIT__) + return val; + return val >> cnt; +} + +int +foo (unsigned int val) +{ + return rshifts (1 + val, lshifts (lshiftu (val, val), 1)); +} + +int +main (void) +{ + if (foo (1) != 0) + abort (); + return 0; +}