aboutsummaryrefslogtreecommitdiff
path: root/gcc/combine.c
diff options
context:
space:
mode:
authorSegher Boessenkool <segher@kernel.crashing.org>2015-08-08 03:51:27 +0200
committerSegher Boessenkool <segher@gcc.gnu.org>2015-08-08 03:51:27 +0200
commit1aeec6dc1f26657cc32ed107b3de255566fcca41 (patch)
treee9ec333a8008794cd08d520fb3cdb36ff0415fbd /gcc/combine.c
parent0fa95f4ead2faf03bde6bb5c458e06f197b34ca2 (diff)
downloadgcc-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/combine.c')
-rw-r--r--gcc/combine.c19
1 files changed, 12 insertions, 7 deletions
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))