diff options
author | Segher Boessenkool <segher@kernel.crashing.org> | 2015-08-08 03:51:27 +0200 |
---|---|---|
committer | Segher Boessenkool <segher@gcc.gnu.org> | 2015-08-08 03:51:27 +0200 |
commit | 1aeec6dc1f26657cc32ed107b3de255566fcca41 (patch) | |
tree | e9ec333a8008794cd08d520fb3cdb36ff0415fbd /gcc | |
parent | 0fa95f4ead2faf03bde6bb5c458e06f197b34ca2 (diff) | |
download | gcc-1aeec6dc1f26657cc32ed107b3de255566fcca41.zip gcc-1aeec6dc1f26657cc32ed107b3de255566fcca41.tar.gz gcc-1aeec6dc1f26657cc32ed107b3de255566fcca41.tar.bz2 |
re PR rtl-optimization/67028 (combine bug. Different assumptions about subreg in different places.)
PR rtl-optimization/67028
* combine.c (simplify_comparison): Fix comment. Rearrange code.
Add test to see if a const_int fits in the new mode.
gcc/testsuite/
PR rtl-optimization/67028
* gcc.dg/pr67028.c: New testcase.
From-SVN: r226731
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/combine.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr67028.c | 21 |
4 files changed, 44 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 00070d9..c85c8e3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2015-08-08 Segher Boessenkool <segher@kernel.crashing.org> + + PR rtl-optimization/67028 + * combine.c (simplify_comparison): Fix comment. Rearrange code. + Add test to see if a const_int fits in the new mode. + 2015-08-07 DJ Delorie <dj@redhat.com> * config/rx/rx.c (rx_mode_dependent_address_p): Remove unneeded asserts. diff --git a/gcc/combine.c b/gcc/combine.c index 4a92f55..8f98cbb 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -12057,14 +12057,15 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) continue; } - /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 + /* If this is (and:M1 (subreg:M1 X:M2 0) (const_int C1)) where C1 fits in both M1 and M2 and the SUBREG is either paradoxical or represents the low part, permute the SUBREG and the AND and try again. */ - if (GET_CODE (XEXP (op0, 0)) == SUBREG) + if (GET_CODE (XEXP (op0, 0)) == SUBREG + && CONST_INT_P (XEXP (op0, 1))) { - unsigned HOST_WIDE_INT c1; tmode = GET_MODE (SUBREG_REG (XEXP (op0, 0))); + unsigned HOST_WIDE_INT c1 = INTVAL (XEXP (op0, 1)); /* Require an integral mode, to avoid creating something like (AND:SF ...). */ if (SCALAR_INT_MODE_P (tmode) @@ -12074,16 +12075,20 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) have a defined value due to the AND operation. However, if we commute the AND inside the SUBREG then they no longer have defined values and the meaning of - the code has been changed. */ + the code has been changed. + Also C1 should not change value in the smaller mode, + see PR67028 (a positive C1 can become negative in the + smaller mode, so that the AND does no longer mask the + upper bits). */ && ((WORD_REGISTER_OPERATIONS && mode_width > GET_MODE_PRECISION (tmode) - && mode_width <= BITS_PER_WORD) + && mode_width <= BITS_PER_WORD + && trunc_int_for_mode (c1, tmode) == (HOST_WIDE_INT) c1) || (mode_width <= GET_MODE_PRECISION (tmode) && subreg_lowpart_p (XEXP (op0, 0)))) - && CONST_INT_P (XEXP (op0, 1)) && mode_width <= HOST_BITS_PER_WIDE_INT && HWI_COMPUTABLE_MODE_P (tmode) - && ((c1 = INTVAL (XEXP (op0, 1))) & ~mask) == 0 + && (c1 & ~mask) == 0 && (c1 & ~GET_MODE_MASK (tmode)) == 0 && c1 != mask && c1 != GET_MODE_MASK (tmode)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8aba7c0..38b6f9e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-08-08 Segher Boessenkool <segher@kernel.crashing.org> + + PR rtl-optimization/67028 + * gcc.dg/pr67028.c: New testcase. + 2015-08-07 H.J. Lu <hongjiu.lu@intel.com> PR rtl-optimization/67029 diff --git a/gcc/testsuite/gcc.dg/pr67028.c b/gcc/testsuite/gcc.dg/pr67028.c new file mode 100644 index 0000000..b42fb81 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr67028.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-options "-O3" } */ + +short c = 0; + +int __attribute__ ((noinline)) f(void) +{ + int d = 5; + signed char e = (c != 1) * -2; + int a = (unsigned short)e > d; + + return a; +} + +int main(void) +{ + if (!f()) + __builtin_abort(); + + return 0; +} |