enum machine_mode lmode, rmode, lnmode, rnmode;
int lunsignedp, runsignedp;
int lvolatilep = 0, rvolatilep = 0;
+ int alignment;
tree linner, rinner;
tree mask;
tree offset;
if the same as the size of the underlying object, we aren't doing an
extraction at all and so can do nothing. */
linner = get_inner_reference (lhs, &lbitsize, &lbitpos, &offset, &lmode,
- &lunsignedp, &lvolatilep);
+ &lunsignedp, &lvolatilep, &alignment);
if (linner == lhs || lbitsize == GET_MODE_BITSIZE (lmode) || lbitsize < 0
|| offset != 0)
return 0;
{
/* If this is not a constant, we can only do something if bit positions,
sizes, and signedness are the same. */
- rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset,
- &rmode, &runsignedp, &rvolatilep);
+ rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode,
+ &runsignedp, &rvolatilep, &alignment);
if (rinner == rhs || lbitpos != rbitpos || lbitsize != rbitsize
|| lunsignedp != runsignedp || offset != 0)
tree mask, inner, offset;
tree unsigned_type;
int precision;
+ int alignment;
/* All the optimizations using this function assume integer fields.
There are problems with FP fields since the type_for_size call
inner = get_inner_reference (exp, pbitsize, pbitpos, &offset, pmode,
- punsignedp, pvolatilep);
+ punsignedp, pvolatilep, &alignment);
if ((inner == exp && and_mask == 0)
|| *pbitsize < 0 || offset != 0)
return 0;
/* If they don't overlap, the result is the first range. If the
second range is a subset of the first, we can't describe this as
a single range unless both ranges end at the same place. If both
- ranges also start in the same place, then the result is false.
+ ranges start in the same place, then the result is false.
Otherwise, we go from the start of the first range to just before
the start of the second. */
if (no_overlap)
&& integer_zerop (range_binop (EQ_EXPR, integer_type_node,
high0, 1, high1, 0)))
return 0;
- else if (subset
- && integer_onep (range_binop (EQ_EXPR, integer_type_node,
- low0, 0, low1, 0)))
+ else if (integer_onep (range_binop (EQ_EXPR, integer_type_node,
+ low0, 0, low1, 0)))
in_p = 0, low = high = 0;
else
{
if (p == modesize || unsignedp)
return c;
- if (TREE_UNSIGNED (type))
- c = convert (signed_type (type), c);
-
/* We work by getting just the sign bit into the low-order bit, then
into the high-order bit, then sign-extend. We then XOR that value
with C. */
temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1), 0);
temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0);
+
+ /* We must use a signed type in order to get an arithmetic right shift.
+ However, we must also avoid introducing accidental overflows, so that
+ a subsequent call to integer_zerop will work. Hence we must
+ do the type conversion here. At this point, the constant is either
+ zero or one, and the conversion to a signed type can never overflow.
+ We could get an overflow if this conversion is done anywhere else. */
+ if (TREE_UNSIGNED (type))
+ temp = convert (signed_type (type), temp);
+
temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1), 0);
temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1), 0);
if (mask != 0)
temp = const_binop (BIT_AND_EXPR, temp, convert (TREE_TYPE (c), mask), 0);
+ /* If necessary, convert the type back to match the type of C. */
+ if (TREE_UNSIGNED (type))
+ temp = convert (type, temp);
return convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
}