On 05/13/2016 02:21 PM, Kyrill Tkachov wrote:
Hi all,
In this PR we may end up shifting a negative value left in
simplify_comparison.
The statement is:
const_op <<= INTVAL (XEXP (op0, 1));
This patch guards the block of that statement by const_op >= 0.
I _think_ that's a correct thing to do for that trasnformation:
"If we have (compare (xshiftrt FOO N) (const_int C)) and
the low order N bits of FOO are known to be zero, we can do this
by comparing FOO with C shifted left N bits so long as no
overflow occurs."
Isn't the condition testing for overflow though? In a somewhat
nonobvious way.
So I think you should just use an unsigned version of const_op. While
we're here we might as well make the code here a little more readable.
How about the patch below? Can you test whether this works for you?
Bernd
Index: combine.c
===================================================================
--- combine.c (revision 236113)
+++ combine.c (working copy)
@@ -11628,13 +11628,13 @@ simplify_comparison (enum rtx_code code,
while (CONST_INT_P (op1))
{
+ HOST_WIDE_INT amount;
machine_mode mode = GET_MODE (op0);
unsigned int mode_width = GET_MODE_PRECISION (mode);
unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
int equality_comparison_p;
int sign_bit_comparison_p;
int unsigned_comparison_p;
- HOST_WIDE_INT const_op;
/* We only want to handle integral modes. This catches VOIDmode,
CCmode, and the floating-point modes. An exception is that we
@@ -11649,7 +11649,8 @@ simplify_comparison (enum rtx_code code,
/* Try to simplify the compare to constant, possibly changing the
comparison op, and/or changing op1 to zero. */
code = simplify_compare_const (code, mode, op0, &op1);
- const_op = INTVAL (op1);
+ HOST_WIDE_INT const_op = INTVAL (op1);
+ unsigned HOST_WIDE_INT uconst_op = (unsigned HOST_WIDE_INT) const_op;
/* Compute some predicates to simplify code below. */
@@ -11899,7 +11900,7 @@ simplify_comparison (enum rtx_code code,
if (GET_MODE_CLASS (mode) == MODE_INT
&& (unsigned_comparison_p || equality_comparison_p)
&& HWI_COMPUTABLE_MODE_P (mode)
- && (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
+ && uconst_op <= GET_MODE_MASK (mode)
&& const_op >= 0
&& have_insn_for (COMPARE, mode))
{
@@ -12198,28 +12199,29 @@ simplify_comparison (enum rtx_code code,
break;
case ASHIFT:
+ amount = XEXP (op0, 1);
/* If we have (compare (ashift FOO N) (const_int C)) and
the high order N bits of FOO (N+1 if an inequality comparison)
are known to be zero, we can do this by comparing FOO with C
shifted right N bits so long as the low-order N bits of C are
zero. */
- if (CONST_INT_P (XEXP (op0, 1))
- && INTVAL (XEXP (op0, 1)) >= 0
- && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
+ if (CONST_INT_P (amount)
+ && INTVAL (amount) >= 0
+ && ((INTVAL (amount) + ! equality_comparison_p)
< HOST_BITS_PER_WIDE_INT)
- && (((unsigned HOST_WIDE_INT) const_op
- & (((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1)))
+ && ((uconst_op
+ & (((unsigned HOST_WIDE_INT) 1 << INTVAL (amount))
- 1)) == 0)
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (op0, 0), mode)
- & ~(mask >> (INTVAL (XEXP (op0, 1))
+ & ~(mask >> (INTVAL (amount)
+ ! equality_comparison_p))) == 0)
{
/* We must perform a logical shift, not an arithmetic one,
as we want the top N bits of C to be zero. */
unsigned HOST_WIDE_INT temp = const_op & GET_MODE_MASK (mode);
- temp >>= INTVAL (XEXP (op0, 1));
+ temp >>= INTVAL (amount);
op1 = gen_int_mode (temp, mode);
op0 = XEXP (op0, 0);
continue;
@@ -12227,13 +12229,13 @@ simplify_comparison (enum rtx_code code,
/* If we are doing a sign bit comparison, it means we are testing
a particular bit. Convert it to the appropriate AND. */
- if (sign_bit_comparison_p && CONST_INT_P (XEXP (op0, 1))
+ if (sign_bit_comparison_p && CONST_INT_P (amount)
&& mode_width <= HOST_BITS_PER_WIDE_INT)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0),
((unsigned HOST_WIDE_INT) 1
<< (mode_width - 1
- - INTVAL (XEXP (op0, 1)))));
+ - INTVAL (amount))));
code = (code == LT ? NE : EQ);
continue;
}
@@ -12242,8 +12244,8 @@ simplify_comparison (enum rtx_code code,
the low bit to the sign bit, we can convert this to an AND of the
low-order bit. */
if (const_op == 0 && equality_comparison_p
- && CONST_INT_P (XEXP (op0, 1))
- && UINTVAL (XEXP (op0, 1)) == mode_width - 1)
+ && CONST_INT_P (amount)
+ && UINTVAL (amount) == mode_width - 1)
{
op0 = simplify_and_const_int (NULL_RTX, mode, XEXP (op0, 0), 1);
continue;
@@ -12251,24 +12253,25 @@ simplify_comparison (enum rtx_code code,
break;
case ASHIFTRT:
+ amount = XEXP (op0, 1);
/* If this is an equality comparison with zero, we can do this
as a logical shift, which might be much simpler. */
if (equality_comparison_p && const_op == 0
- && CONST_INT_P (XEXP (op0, 1)))
+ && CONST_INT_P (amount))
{
op0 = simplify_shift_const (NULL_RTX, LSHIFTRT, mode,
XEXP (op0, 0),
- INTVAL (XEXP (op0, 1)));
+ INTVAL (amount));
continue;
}
/* If OP0 is a sign extension and CODE is not an unsigned comparison,
do the comparison in a narrower mode. */
if (! unsigned_comparison_p
- && CONST_INT_P (XEXP (op0, 1))
+ && CONST_INT_P (amount)
&& GET_CODE (XEXP (op0, 0)) == ASHIFT
- && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
- && (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
+ && amount == XEXP (XEXP (op0, 0), 1)
+ && (tmode = mode_for_size (mode_width - INTVAL (amount),
MODE_INT, 1)) != BLKmode
&& (((unsigned HOST_WIDE_INT) const_op
+ (GET_MODE_MASK (tmode) >> 1) + 1)
@@ -12282,12 +12285,12 @@ simplify_comparison (enum rtx_code code,
constant, which is usually represented with the PLUS
between the shifts. */
if (! unsigned_comparison_p
- && CONST_INT_P (XEXP (op0, 1))
+ && CONST_INT_P (amount)
&& GET_CODE (XEXP (op0, 0)) == PLUS
&& CONST_INT_P (XEXP (XEXP (op0, 0), 1))
&& GET_CODE (XEXP (XEXP (op0, 0), 0)) == ASHIFT
- && XEXP (op0, 1) == XEXP (XEXP (XEXP (op0, 0), 0), 1)
- && (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
+ && amount == XEXP (XEXP (XEXP (op0, 0), 0), 1)
+ && (tmode = mode_for_size (mode_width - INTVAL (amount),
MODE_INT, 1)) != BLKmode
&& (((unsigned HOST_WIDE_INT) const_op
+ (GET_MODE_MASK (tmode) >> 1) + 1)
@@ -12296,7 +12299,7 @@ simplify_comparison (enum rtx_code code,
rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
rtx add_const = XEXP (XEXP (op0, 0), 1);
rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
- add_const, XEXP (op0, 1));
+ add_const, amount);
op0 = simplify_gen_binary (PLUS, tmode,
gen_lowpart (tmode, inner),
@@ -12306,6 +12309,7 @@ simplify_comparison (enum rtx_code code,
/* ... fall through ... */
case LSHIFTRT:
+ amount = XEXP (op0, 1);
/* If we have (compare (xshiftrt FOO N) (const_int C)) and
the low order N bits of FOO are known to be zero, we can do this
by comparing FOO with C shifted left N bits so long as no
@@ -12313,21 +12317,20 @@ simplify_comparison (enum rtx_code code,
to be zero, if the comparison is >= or < we can use the same
optimization and for > or <= by setting all the low
order N bits in the comparison constant. */
- if (CONST_INT_P (XEXP (op0, 1))
- && INTVAL (XEXP (op0, 1)) > 0
- && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
+ if (CONST_INT_P (amount)
+ && INTVAL (amount) > 0
+ && INTVAL (amount) < HOST_BITS_PER_WIDE_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT
- && (((unsigned HOST_WIDE_INT) const_op
+ && ((uconst_op
+ (GET_CODE (op0) != LSHIFTRT
- ? ((GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1)) >> 1)
- + 1)
+ ? ((GET_MODE_MASK (mode) >> INTVAL (amount) >> 1) + 1)
: 0))
- <= GET_MODE_MASK (mode) >> INTVAL (XEXP (op0, 1))))
+ <= GET_MODE_MASK (mode) >> INTVAL (amount)))
{
+ unsigned HOST_WIDE_INT low_mask
+ = (((unsigned HOST_WIDE_INT) 1 << INTVAL (amount)) - 1);
unsigned HOST_WIDE_INT low_bits
- = (nonzero_bits (XEXP (op0, 0), mode)
- & (((unsigned HOST_WIDE_INT) 1
- << INTVAL (XEXP (op0, 1))) - 1));
+ = (nonzero_bits (XEXP (op0, 0), mode) & low_mask);
if (low_bits == 0 || !equality_comparison_p)
{
/* If the shift was logical, then we must make the condition
@@ -12335,13 +12338,12 @@ simplify_comparison (enum rtx_code code,
if (GET_CODE (op0) == LSHIFTRT)
code = unsigned_condition (code);
- const_op <<= INTVAL (XEXP (op0, 1));
+ uconst_op <<= INTVAL (amount);
if (low_bits != 0
&& (code == GT || code == GTU
|| code == LE || code == LEU))
- const_op
- |= (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1);
- op1 = GEN_INT (const_op);
+ uconst_op |= low_mask;
+ op1 = gen_int_mode (uconst_op, mode);
op0 = XEXP (op0, 0);
continue;
}
@@ -12351,8 +12353,8 @@ simplify_comparison (enum rtx_code code,
can replace this with an LT or GE comparison. */
if (const_op == 0
&& (equality_comparison_p || sign_bit_comparison_p)
- && CONST_INT_P (XEXP (op0, 1))
- && UINTVAL (XEXP (op0, 1)) == mode_width - 1)
+ && CONST_INT_P (amount)
+ && UINTVAL (amount) == mode_width - 1)
{
op0 = XEXP (op0, 0);
code = (code == NE || code == GT ? LT : GE);