diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2018-01-12 10:18:24 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2018-01-12 10:18:24 +0000 |
commit | 371ae937660d0a6e5c1ce680c775d37d7ff13ba9 (patch) | |
tree | 41fac78fb9fc33bf7665d785001199058967572c | |
parent | c574147e6298bf5e623c1c10c0deddde8cec507b (diff) | |
download | gcc-371ae937660d0a6e5c1ce680c775d37d7ff13ba9.zip gcc-371ae937660d0a6e5c1ce680c775d37d7ff13ba9.tar.gz gcc-371ae937660d0a6e5c1ce680c775d37d7ff13ba9.tar.bz2 |
re PR rtl-optimization/83565 (RTL combine pass yields wrong rotate result)
PR rtl-optimization/83565
* rtlanal.c (nonzero_bits1): On WORD_REGISTER_OPERATIONS machines, do
not extend the result to a larger mode for rotate operations.
(num_sign_bit_copies1): Likewise.
From-SVN: r256572
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/rtlanal.c | 65 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20180112-1.c | 32 |
4 files changed, 85 insertions, 23 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 36e8aa8..a8737dc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2018-01-12 Eric Botcazou <ebotcazou@adacore.com> + + PR rtl-optimization/83565 + * rtlanal.c (nonzero_bits1): On WORD_REGISTER_OPERATIONS machines, do + not extend the result to a larger mode for rotate operations. + (num_sign_bit_copies1): Likewise. + 2018-01-12 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> PR target/40411 diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index b728391..89d586b 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -4429,7 +4429,7 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, { unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode); unsigned HOST_WIDE_INT inner_nz; - enum rtx_code code; + enum rtx_code code = GET_CODE (x); machine_mode inner_mode; unsigned int inner_width; scalar_int_mode xmode; @@ -4465,16 +4465,16 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, return nonzero; /* If MODE is wider than X, but both are a single word for both the host - and target machines, we can compute this from which bits of the - object might be nonzero in its own mode, taking into account the fact - that on many CISC machines, accessing an object in a wider mode - causes the high-order bits to become undefined. So they are - not known to be zero. */ - - if (!WORD_REGISTER_OPERATIONS - && mode_width > xmode_width + and target machines, we can compute this from which bits of the object + might be nonzero in its own mode, taking into account the fact that, on + CISC machines, accessing an object in a wider mode generally causes the + high-order bits to become undefined, so they are not known to be zero. + We extend this reasoning to RISC machines for rotate operations since the + semantics of the operations in the larger mode is not well defined. */ + if (mode_width > xmode_width && xmode_width <= BITS_PER_WORD - && xmode_width <= HOST_BITS_PER_WIDE_INT) + && xmode_width <= HOST_BITS_PER_WIDE_INT + && (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)) { nonzero &= cached_nonzero_bits (x, xmode, known_x, known_mode, known_ret); @@ -4484,7 +4484,6 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, /* Please keep nonzero_bits_binary_arith_p above in sync with the code in the switch below. */ - code = GET_CODE (x); switch (code) { case REG: @@ -4760,10 +4759,11 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, } break; + case ASHIFT: case ASHIFTRT: case LSHIFTRT: - case ASHIFT: case ROTATE: + case ROTATERT: /* The nonzero bits are in two classes: any bits within MODE that aren't in xmode are always significant. The rest of the nonzero bits are those that are significant in the operand of @@ -4786,10 +4786,17 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, if (mode_width > xmode_width) outer = (op_nonzero & nonzero & ~mode_mask); - if (code == LSHIFTRT) - inner >>= count; - else if (code == ASHIFTRT) + switch (code) { + case ASHIFT: + inner <<= count; + break; + + case LSHIFTRT: + inner >>= count; + break; + + case ASHIFTRT: inner >>= count; /* If the sign bit may have been nonzero before the shift, we @@ -4798,13 +4805,23 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, if (inner & (HOST_WIDE_INT_1U << (xmode_width - 1 - count))) inner |= (((HOST_WIDE_INT_1U << count) - 1) << (xmode_width - count)); + break; + + case ROTATE: + inner = (inner << (count % xmode_width) + | (inner >> (xmode_width - (count % xmode_width)))) + & mode_mask; + break; + + case ROTATERT: + inner = (inner >> (count % xmode_width) + | (inner << (xmode_width - (count % xmode_width)))) + & mode_mask; + break; + + default: + gcc_unreachable (); } - else if (code == ASHIFT) - inner <<= count; - else - inner = ((inner << (count % xmode_width) - | (inner >> (xmode_width - (count % xmode_width)))) - & mode_mask); nonzero &= (outer | inner); } @@ -4992,8 +5009,10 @@ num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, { /* If this machine does not do all register operations on the entire register and MODE is wider than the mode of X, we can say nothing - at all about the high-order bits. */ - if (!WORD_REGISTER_OPERATIONS) + at all about the high-order bits. We extend this reasoning to every + machine for rotate operations since the semantics of the operations + in the larger mode is not well defined. */ + if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT) return 1; /* Likewise on machines that do, if the mode of the object is smaller diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cb4b120..6b6b8e0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2018-01-12 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.c-torture/execute/20180112-1.c: New test. + 2018-01-12 Tom de Vries <tom@codesourcery.com> * g++.dg/ext/label13.C: Add dg-require-effective-target indirect_jumps. diff --git a/gcc/testsuite/gcc.c-torture/execute/20180112-1.c b/gcc/testsuite/gcc.c-torture/execute/20180112-1.c new file mode 100644 index 0000000..6752661 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20180112-1.c @@ -0,0 +1,32 @@ +/* PR rtl-optimization/83565 */ +/* Testcase by Sergei Trofimovich <slyfox@inbox.ru> */ + +extern void abort (void); + +typedef unsigned int u32; + +u32 bug (u32 * result) __attribute__((noinline)); +u32 bug (u32 * result) +{ + volatile u32 ss = 0xFFFFffff; + volatile u32 d = 0xEEEEeeee; + u32 tt = d & 0x00800000; + u32 r = tt << 8; + + r = (r >> 31) | (r << 1); + + u32 u = r^ss; + u32 off = u >> 1; + + *result = tt; + return off; +} + +int main(void) +{ + u32 l; + u32 off = bug(&l); + if (off != 0x7fffffff) + abort (); + return 0; +} |