===================================================================
@@ -449,6 +449,8 @@ static rtx extract_left_shift (rtx, int)
static int get_pos_from_mask (unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT *);
static rtx canon_reg_for_combine (rtx, rtx);
+static rtx force_int_to_mode (rtx, scalar_int_mode, scalar_int_mode,
+ scalar_int_mode, unsigned HOST_WIDE_INT, int);
static rtx force_to_mode (rtx, machine_mode,
unsigned HOST_WIDE_INT, int);
static rtx if_then_else_cond (rtx, rtx *, rtx *);
@@ -8517,8 +8519,7 @@ force_to_mode (rtx x, machine_mode mode,
enum rtx_code code = GET_CODE (x);
int next_select = just_select || code == XOR || code == NOT || code == NEG;
machine_mode op_mode;
- unsigned HOST_WIDE_INT fuller_mask, nonzero;
- rtx op0, op1, temp;
+ unsigned HOST_WIDE_INT nonzero;
/* If this is a CALL or ASM_OPERANDS, don't do anything. Some of the
code below will do the wrong thing since the mode of such an
@@ -8546,15 +8547,6 @@ force_to_mode (rtx x, machine_mode mode,
if (op_mode)
mask &= GET_MODE_MASK (op_mode);
- /* When we have an arithmetic operation, or a shift whose count we
- do not know, we need to assume that all bits up to the highest-order
- bit in MASK will be needed. This is how we form such a mask. */
- if (mask & (HOST_WIDE_INT_1U << (HOST_BITS_PER_WIDE_INT - 1)))
- fuller_mask = HOST_WIDE_INT_M1U;
- else
- fuller_mask = ((HOST_WIDE_INT_1U << (floor_log2 (mask) + 1))
- - 1);
-
/* Determine what bits of X are guaranteed to be (non)zero. */
nonzero = nonzero_bits (x, mode);
@@ -8592,9 +8584,42 @@ force_to_mode (rtx x, machine_mode mode,
& ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
return force_to_mode (SUBREG_REG (x), mode, mask, next_select);
- /* The arithmetic simplifications here only work for scalar integer modes. */
- if (!SCALAR_INT_MODE_P (mode) || !SCALAR_INT_MODE_P (GET_MODE (x)))
- return gen_lowpart_or_truncate (mode, x);
+ scalar_int_mode int_mode, xmode;
+ if (is_a <scalar_int_mode> (mode, &int_mode)
+ && is_a <scalar_int_mode> (GET_MODE (x), &xmode))
+ /* OP_MODE is either MODE or XMODE, so it must be a scalar
+ integer too. */
+ return force_int_to_mode (x, int_mode, xmode,
+ as_a <scalar_int_mode> (op_mode),
+ mask, just_select);
+
+ return gen_lowpart_or_truncate (mode, x);
+}
+
+/* Subroutine of force_to_mode that handles cases in which both X and
+ the result are scalar integers. MODE is the mode of the result,
+ XMODE is the mode of X, and OP_MODE says which of MODE or XMODE
+ is preferred for simplified versions of X. The other arguments
+ are as for force_to_mode. */
+
+static rtx
+force_int_to_mode (rtx x, scalar_int_mode mode, scalar_int_mode xmode,
+ scalar_int_mode op_mode, unsigned HOST_WIDE_INT mask,
+ int just_select)
+{
+ enum rtx_code code = GET_CODE (x);
+ int next_select = just_select || code == XOR || code == NOT || code == NEG;
+ unsigned HOST_WIDE_INT fuller_mask;
+ rtx op0, op1, temp;
+
+ /* When we have an arithmetic operation, or a shift whose count we
+ do not know, we need to assume that all bits up to the highest-order
+ bit in MASK will be needed. This is how we form such a mask. */
+ if (mask & (HOST_WIDE_INT_1U << (HOST_BITS_PER_WIDE_INT - 1)))
+ fuller_mask = HOST_WIDE_INT_M1U;
+ else
+ fuller_mask = ((HOST_WIDE_INT_1U << (floor_log2 (mask) + 1))
+ - 1);
switch (code)
{
@@ -8625,14 +8650,14 @@ force_to_mode (rtx x, machine_mode mode,
{
x = simplify_and_const_int (x, op_mode, XEXP (x, 0),
mask & INTVAL (XEXP (x, 1)));
+ xmode = op_mode;
/* If X is still an AND, see if it is an AND with a mask that
is just some low-order bits. If so, and it is MASK, we don't
need it. */
if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1))
- && ((INTVAL (XEXP (x, 1)) & GET_MODE_MASK (GET_MODE (x)))
- == mask))
+ && (INTVAL (XEXP (x, 1)) & GET_MODE_MASK (xmode)) == mask)
x = XEXP (x, 0);
/* If it remains an AND, try making another AND with the bits
@@ -8641,18 +8666,17 @@ force_to_mode (rtx x, machine_mode mode,
cheaper constant. */
if (GET_CODE (x) == AND && CONST_INT_P (XEXP (x, 1))
- && GET_MODE_MASK (GET_MODE (x)) != mask
- && HWI_COMPUTABLE_MODE_P (GET_MODE (x)))
+ && GET_MODE_MASK (xmode) != mask
+ && HWI_COMPUTABLE_MODE_P (xmode))
{
unsigned HOST_WIDE_INT cval
- = UINTVAL (XEXP (x, 1))
- | (GET_MODE_MASK (GET_MODE (x)) & ~mask);
+ = UINTVAL (XEXP (x, 1)) | (GET_MODE_MASK (xmode) & ~mask);
rtx y;
- y = simplify_gen_binary (AND, GET_MODE (x), XEXP (x, 0),
- gen_int_mode (cval, GET_MODE (x)));
- if (set_src_cost (y, GET_MODE (x), optimize_this_for_speed_p)
- < set_src_cost (x, GET_MODE (x), optimize_this_for_speed_p))
+ y = simplify_gen_binary (AND, xmode, XEXP (x, 0),
+ gen_int_mode (cval, xmode));
+ if (set_src_cost (y, xmode, optimize_this_for_speed_p)
+ < set_src_cost (x, xmode, optimize_this_for_speed_p))
x = y;
}
@@ -8682,7 +8706,7 @@ force_to_mode (rtx x, machine_mode mode,
&& pow2p_hwi (- smask)
&& (nonzero_bits (XEXP (x, 0), mode) & ~smask) == 0
&& (INTVAL (XEXP (x, 1)) & ~smask) != 0)
- return force_to_mode (plus_constant (GET_MODE (x), XEXP (x, 0),
+ return force_to_mode (plus_constant (xmode, XEXP (x, 0),
(INTVAL (XEXP (x, 1)) & smask)),
mode, smask, next_select);
}
@@ -8713,8 +8737,7 @@ force_to_mode (rtx x, machine_mode mode,
if (CONST_INT_P (XEXP (x, 0))
&& least_bit_hwi (UINTVAL (XEXP (x, 0))) > mask)
{
- x = simplify_gen_unary (NEG, GET_MODE (x), XEXP (x, 1),
- GET_MODE (x));
+ x = simplify_gen_unary (NEG, xmode, XEXP (x, 1), xmode);
return force_to_mode (x, mode, mask, next_select);
}
@@ -8723,8 +8746,7 @@ force_to_mode (rtx x, machine_mode mode,
if (CONST_INT_P (XEXP (x, 0))
&& ((UINTVAL (XEXP (x, 0)) | fuller_mask) == UINTVAL (XEXP (x, 0))))
{
- x = simplify_gen_unary (NOT, GET_MODE (x),
- XEXP (x, 1), GET_MODE (x));
+ x = simplify_gen_unary (NOT, xmode, XEXP (x, 1), xmode);
return force_to_mode (x, mode, mask, next_select);
}
@@ -8745,16 +8767,16 @@ force_to_mode (rtx x, machine_mode mode,
&& CONST_INT_P (XEXP (x, 1))
&& ((INTVAL (XEXP (XEXP (x, 0), 1))
+ floor_log2 (INTVAL (XEXP (x, 1))))
- < GET_MODE_PRECISION (GET_MODE (x)))
+ < GET_MODE_PRECISION (xmode))
&& (UINTVAL (XEXP (x, 1))
- & ~nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0)
+ & ~nonzero_bits (XEXP (x, 0), xmode)) == 0)
{
temp = gen_int_mode ((INTVAL (XEXP (x, 1)) & mask)
<< INTVAL (XEXP (XEXP (x, 0), 1)),
- GET_MODE (x));
- temp = simplify_gen_binary (GET_CODE (x), GET_MODE (x),
+ xmode);
+ temp = simplify_gen_binary (GET_CODE (x), xmode,
XEXP (XEXP (x, 0), 0), temp);
- x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), temp,
+ x = simplify_gen_binary (LSHIFTRT, xmode, temp,
XEXP (XEXP (x, 0), 1));
return force_to_mode (x, mode, mask, next_select);
}
@@ -8778,8 +8800,11 @@ force_to_mode (rtx x, machine_mode mode,
op0 = gen_lowpart_or_truncate (op_mode, op0);
op1 = gen_lowpart_or_truncate (op_mode, op1);
- if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
- x = simplify_gen_binary (code, op_mode, op0, op1);
+ if (op_mode != xmode || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+ {
+ x = simplify_gen_binary (code, op_mode, op0, op1);
+ xmode = op_mode;
+ }
break;
case ASHIFT:
@@ -8812,8 +8837,11 @@ force_to_mode (rtx x, machine_mode mode,
force_to_mode (XEXP (x, 0), op_mode,
mask, next_select));
- if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
- x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
+ if (op_mode != xmode || op0 != XEXP (x, 0))
+ {
+ x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
+ xmode = op_mode;
+ }
break;
case LSHIFTRT:
@@ -8835,13 +8863,16 @@ force_to_mode (rtx x, machine_mode mode,
/* We can only change the mode of the shift if we can do arithmetic
in the mode of the shift and INNER_MASK is no wider than the
width of X's mode. */
- if ((inner_mask & ~GET_MODE_MASK (GET_MODE (x))) != 0)
- op_mode = GET_MODE (x);
+ if ((inner_mask & ~GET_MODE_MASK (xmode)) != 0)
+ op_mode = xmode;
inner = force_to_mode (inner, op_mode, inner_mask, next_select);
- if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
- x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
+ if (xmode != op_mode || inner != XEXP (x, 0))
+ {
+ x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
+ xmode = op_mode;
+ }
}
/* If we have (and (lshiftrt FOO C1) C2) where the combination of the
@@ -8854,17 +8885,17 @@ force_to_mode (rtx x, machine_mode mode,
bit. */
&& ((INTVAL (XEXP (x, 1))
+ num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))))
- >= GET_MODE_PRECISION (GET_MODE (x)))
+ >= GET_MODE_PRECISION (xmode))
&& pow2p_hwi (mask + 1)
/* Number of bits left after the shift must be more than the mask
needs. */
&& ((INTVAL (XEXP (x, 1)) + exact_log2 (mask + 1))
- <= GET_MODE_PRECISION (GET_MODE (x)))
+ <= GET_MODE_PRECISION (xmode))
/* Must be more sign bit copies than the mask needs. */
&& ((int) num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
>= exact_log2 (mask + 1)))
- x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
- GEN_INT (GET_MODE_PRECISION (GET_MODE (x))
+ x = simplify_gen_binary (LSHIFTRT, xmode, XEXP (x, 0),
+ GEN_INT (GET_MODE_PRECISION (xmode)
- exact_log2 (mask + 1)));
goto shiftrt;
@@ -8872,7 +8903,7 @@ force_to_mode (rtx x, machine_mode mode,
case ASHIFTRT:
/* If we are just looking for the sign bit, we don't need this shift at
all, even if it has a variable count. */
- if (val_signbit_p (GET_MODE (x), mask))
+ if (val_signbit_p (xmode, mask))
return force_to_mode (XEXP (x, 0), mode, mask, next_select);
/* If this is a shift by a constant, get a mask that contains those bits
@@ -8885,13 +8916,14 @@ force_to_mode (rtx x, machine_mode mode,
if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
{
+ unsigned HOST_WIDE_INT nonzero;
int i;
/* If the considered data is wider than HOST_WIDE_INT, we can't
represent a mask for all its bits in a single scalar.
But we only care about the lower bits, so calculate these. */
- if (GET_MODE_PRECISION (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
+ if (GET_MODE_PRECISION (xmode) > HOST_BITS_PER_WIDE_INT)
{
nonzero = HOST_WIDE_INT_M1U;
@@ -8900,21 +8932,21 @@ force_to_mode (rtx x, machine_mode mode,
We need only shift if these are fewer than nonzero can
hold. If not, we must keep all bits set in nonzero. */
- if (GET_MODE_PRECISION (GET_MODE (x)) - INTVAL (XEXP (x, 1))
+ if (GET_MODE_PRECISION (xmode) - INTVAL (XEXP (x, 1))
< HOST_BITS_PER_WIDE_INT)
nonzero >>= INTVAL (XEXP (x, 1))
+ HOST_BITS_PER_WIDE_INT
- - GET_MODE_PRECISION (GET_MODE (x)) ;
+ - GET_MODE_PRECISION (xmode);
}
else
{
- nonzero = GET_MODE_MASK (GET_MODE (x));
+ nonzero = GET_MODE_MASK (xmode);
nonzero >>= INTVAL (XEXP (x, 1));
}
if ((mask & ~nonzero) == 0)
{
- x = simplify_shift_const (NULL_RTX, LSHIFTRT, GET_MODE (x),
+ x = simplify_shift_const (NULL_RTX, LSHIFTRT, xmode,
XEXP (x, 0), INTVAL (XEXP (x, 1)));
if (GET_CODE (x) != ASHIFTRT)
return force_to_mode (x, mode, mask, next_select);
@@ -8923,8 +8955,8 @@ force_to_mode (rtx x, machine_mode mode,
else if ((i = exact_log2 (mask)) >= 0)
{
x = simplify_shift_const
- (NULL_RTX, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
- GET_MODE_PRECISION (GET_MODE (x)) - 1 - i);
+ (NULL_RTX, LSHIFTRT, xmode, XEXP (x, 0),
+ GET_MODE_PRECISION (xmode) - 1 - i);
if (GET_CODE (x) != ASHIFTRT)
return force_to_mode (x, mode, mask, next_select);
@@ -8934,8 +8966,7 @@ force_to_mode (rtx x, machine_mode mode,
/* If MASK is 1, convert this to an LSHIFTRT. This can be done
even if the shift count isn't a constant. */
if (mask == 1)
- x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
- XEXP (x, 0), XEXP (x, 1));
+ x = simplify_gen_binary (LSHIFTRT, xmode, XEXP (x, 0), XEXP (x, 1));
shiftrt:
@@ -8947,7 +8978,7 @@ force_to_mode (rtx x, machine_mode mode,
&& CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) >= 0
&& (INTVAL (XEXP (x, 1))
- <= GET_MODE_PRECISION (GET_MODE (x)) - (floor_log2 (mask) + 1))
+ <= GET_MODE_PRECISION (xmode) - (floor_log2 (mask) + 1))
&& GET_CODE (XEXP (x, 0)) == ASHIFT
&& XEXP (XEXP (x, 0), 1) == XEXP (x, 1))
return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
@@ -8965,12 +8996,11 @@ force_to_mode (rtx x, machine_mode mode,
&& INTVAL (XEXP (x, 1)) >= 0)
{
temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE,
- GET_MODE (x),
- gen_int_mode (mask, GET_MODE (x)),
+ xmode, gen_int_mode (mask, xmode),
XEXP (x, 1));
if (temp && CONST_INT_P (temp))
- x = simplify_gen_binary (code, GET_MODE (x),
- force_to_mode (XEXP (x, 0), GET_MODE (x),
+ x = simplify_gen_binary (code, xmode,
+ force_to_mode (XEXP (x, 0), xmode,
INTVAL (temp), next_select),
XEXP (x, 1));
}
@@ -8997,14 +9027,12 @@ force_to_mode (rtx x, machine_mode mode,
&& CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
&& (INTVAL (XEXP (XEXP (x, 0), 1)) + floor_log2 (mask)
- < GET_MODE_PRECISION (GET_MODE (x)))
+ < GET_MODE_PRECISION (xmode))
&& INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT)
{
- temp = gen_int_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)),
- GET_MODE (x));
- temp = simplify_gen_binary (XOR, GET_MODE (x),
- XEXP (XEXP (x, 0), 0), temp);
- x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
+ temp = gen_int_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)), xmode);
+ temp = simplify_gen_binary (XOR, xmode, XEXP (XEXP (x, 0), 0), temp);
+ x = simplify_gen_binary (LSHIFTRT, xmode,
temp, XEXP (XEXP (x, 0), 1));
return force_to_mode (x, mode, mask, next_select);
@@ -9018,8 +9046,11 @@ force_to_mode (rtx x, machine_mode mode,
op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
next_select));
- if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
- x = simplify_gen_unary (code, op_mode, op0, op_mode);
+ if (op_mode != xmode || op0 != XEXP (x, 0))
+ {
+ x = simplify_gen_unary (code, op_mode, op0, op_mode);
+ xmode = op_mode;
+ }
break;
case NE:
@@ -9040,14 +9071,14 @@ force_to_mode (rtx x, machine_mode mode,
/* We have no way of knowing if the IF_THEN_ELSE can itself be
written in a narrower mode. We play it safe and do not do so. */
- op0 = gen_lowpart_or_truncate (GET_MODE (x),
+ op0 = gen_lowpart_or_truncate (xmode,
force_to_mode (XEXP (x, 1), mode,
mask, next_select));
- op1 = gen_lowpart_or_truncate (GET_MODE (x),
+ op1 = gen_lowpart_or_truncate (xmode,
force_to_mode (XEXP (x, 2), mode,
mask, next_select));
if (op0 != XEXP (x, 1) || op1 != XEXP (x, 2))
- x = simplify_gen_ternary (IF_THEN_ELSE, GET_MODE (x),
+ x = simplify_gen_ternary (IF_THEN_ELSE, xmode,
GET_MODE (XEXP (x, 0)), XEXP (x, 0),
op0, op1);
break;