- reg_live_length is not updated
- reg_n_refs is not adjusted in the rare case when a register is
no longer required in a computation
- - there are extremely rare cases (see distribute_regnotes) when a
+ - there are extremely rare cases (see distribute_notes) when a
REG_DEAD note is lost
- a LOG_LINKS entry that refers to an insn with multiple SETs may be
removed because there is no way to know which register it was
static rtx make_field_assignment (rtx);
static rtx apply_distributive_law (rtx);
static rtx distribute_and_simplify_rtx (rtx, int);
+static rtx simplify_and_const_int_1 (enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT);
static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
unsigned HOST_WIDE_INT);
static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
HOST_WIDE_INT, enum machine_mode, int *);
-static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx,
+static rtx simplify_shift_const_1 (enum rtx_code, enum machine_mode, rtx, int);
+static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx,
int);
static int recog_for_combine (rtx *, rtx, rtx *);
static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
rtx newdest = i2dest;
enum rtx_code split_code = GET_CODE (*split);
enum machine_mode split_mode = GET_MODE (*split);
+ bool subst_done = false;
+ newi2pat = NULL_RTX;
/* Get NEWDEST as a register in the proper mode. We have already
validated that we can do this. */
}
#endif
- newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
- SUBST (*split, newdest);
+ /* Attempt to split binary operators using arithmetic identities. */
+ if (BINARY_P (SET_SRC (newpat))
+ && split_mode == GET_MODE (SET_SRC (newpat))
+ && ! side_effects_p (SET_SRC (newpat)))
+ {
+ rtx setsrc = SET_SRC (newpat);
+ enum machine_mode mode = GET_MODE (setsrc);
+ enum rtx_code code = GET_CODE (setsrc);
+ rtx src_op0 = XEXP (setsrc, 0);
+ rtx src_op1 = XEXP (setsrc, 1);
+
+ /* Split "X = Y op Y" as "Z = Y; X = Z op Z". */
+ if (rtx_equal_p (src_op0, src_op1))
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((P op Q) op R) op S" where op is PLUS or MULT. */
+ else if ((code == PLUS || code == MULT)
+ && GET_CODE (src_op0) == code
+ && GET_CODE (XEXP (src_op0, 0)) == code
+ && (INTEGRAL_MODE_P (mode)
+ || (FLOAT_MODE_P (mode)
+ && flag_unsafe_math_optimizations)))
+ {
+ rtx p = XEXP (XEXP (src_op0, 0), 0);
+ rtx q = XEXP (XEXP (src_op0, 0), 1);
+ rtx r = XEXP (src_op0, 1);
+ rtx s = src_op1;
+
+ /* Split both "((X op Y) op X) op Y" and
+ "((X op Y) op Y) op X" as "T op T" where T is
+ "X op Y". */
+ if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
+ || (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest,
+ XEXP (src_op0, 0));
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((X op X) op Y) op Y)" as "T op T" where
+ T is "X op Y". */
+ else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
+ {
+ rtx tmp = simplify_gen_binary (code, mode, p, r);
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ }
+ }
+
+ if (!subst_done)
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
+ SUBST (*split, newdest);
+ }
+
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* recog_for_combine might have added CLOBBERs to newi2pat.
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
rtx temp;
- rtx reversed;
int i;
/* If this is a commutative operation, put a constant last and a complex
break;
- case NOT:
- if (GET_CODE (XEXP (x, 0)) == SUBREG
- && subreg_lowpart_p (XEXP (x, 0))
- && (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (x, 0)))))
- && GET_CODE (SUBREG_REG (XEXP (x, 0))) == ASHIFT
- && XEXP (SUBREG_REG (XEXP (x, 0)), 0) == const1_rtx)
- {
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
-
- x = gen_rtx_ROTATE (inner_mode,
- simplify_gen_unary (NOT, inner_mode, const1_rtx,
- inner_mode),
- XEXP (SUBREG_REG (XEXP (x, 0)), 1));
- return gen_lowpart (mode, x);
- }
-
- /* Apply De Morgan's laws to reduce number of patterns for machines
- with negating logical insns (and-not, nand, etc.). If result has
- only one NOT, put it first, since that is how the patterns are
- coded. */
-
- if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND)
- {
- rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1);
- enum machine_mode op_mode;
-
- op_mode = GET_MODE (in1);
- in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
-
- op_mode = GET_MODE (in2);
- if (op_mode == VOIDmode)
- op_mode = mode;
- in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
-
- if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
- {
- rtx tem = in2;
- in2 = in1; in1 = tem;
- }
-
- return gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
- mode, in1, in2);
- }
- break;
-
case NEG:
- /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
- if (GET_CODE (XEXP (x, 0)) == XOR
- && XEXP (XEXP (x, 0), 1) == const1_rtx
- && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
- return simplify_gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
- constm1_rtx);
-
temp = expand_compound_operation (XEXP (x, 0));
/* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), 0));
- /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI. */
- if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
- || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
- && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
- return XEXP (XEXP (x, 0), 0);
-
- /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
- (OP:SI foo:SI) if OP is NEG or ABS. */
- if ((GET_CODE (XEXP (x, 0)) == ABS
- || GET_CODE (XEXP (x, 0)) == NEG)
- && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
- || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
- && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
- return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
- XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
-
- /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
- (truncate:SI x). */
- if (GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
- && subreg_lowpart_p (XEXP (x, 0)))
- return SUBREG_REG (XEXP (x, 0));
-
- /* If we know that the value is already truncated, we can
- replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION
- is nonzero for the corresponding modes. But don't do this
- for an (LSHIFTRT (MULT ...)) since this will cause problems
- with the umulXi3_highpart patterns. */
- if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
- GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
- && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
- >= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
- && ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
- return gen_lowpart (mode, XEXP (x, 0));
-
- /* A truncate of a comparison can be replaced with a subreg if
- STORE_FLAG_VALUE permits. This is like the previous test,
- but it works even if the comparison is done in a mode larger
- than HOST_BITS_PER_WIDE_INT. */
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && COMPARISON_P (XEXP (x, 0))
- && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
- return gen_lowpart (mode, XEXP (x, 0));
-
- /* Similarly, a truncate of a register whose value is a
- comparison can be replaced with a subreg if STORE_FLAG_VALUE
- permits. */
+ /* Similarly to what we do in simplify-rtx.c, a truncate of a register
+ whose value is a comparison can be replaced with a subreg if
+ STORE_FLAG_VALUE permits. */
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
&& (temp = get_last_value (XEXP (x, 0)))
&& COMPARISON_P (temp))
return gen_lowpart (mode, XEXP (x, 0));
-
- break;
-
- case FLOAT_TRUNCATE:
- /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF. */
- if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
- && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
- return XEXP (XEXP (x, 0), 0);
-
- /* (float_truncate:SF (float_truncate:DF foo:XF))
- = (float_truncate:SF foo:XF).
- This may eliminate double rounding, so it is unsafe.
-
- (float_truncate:SF (float_extend:XF foo:DF))
- = (float_truncate:SF foo:DF).
-
- (float_truncate:DF (float_extend:XF foo:SF))
- = (float_extend:SF foo:DF). */
- if ((GET_CODE (XEXP (x, 0)) == FLOAT_TRUNCATE
- && flag_unsafe_math_optimizations)
- || GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND)
- return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0),
- 0)))
- > GET_MODE_SIZE (mode)
- ? FLOAT_TRUNCATE : FLOAT_EXTEND,
- mode,
- XEXP (XEXP (x, 0), 0), mode);
-
- /* (float_truncate (float x)) is (float x) */
- if (GET_CODE (XEXP (x, 0)) == FLOAT
- && (flag_unsafe_math_optimizations
- || ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
- >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
- - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
- GET_MODE (XEXP (XEXP (x, 0), 0)))))))
- return simplify_gen_unary (FLOAT, mode,
- XEXP (XEXP (x, 0), 0),
- GET_MODE (XEXP (XEXP (x, 0), 0)));
-
- /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
- (OP:SF foo:SF) if OP is NEG or ABS. */
- if ((GET_CODE (XEXP (x, 0)) == ABS
- || GET_CODE (XEXP (x, 0)) == NEG)
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == FLOAT_EXTEND
- && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
- return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
- XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
-
- /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
- is (float_truncate:SF x). */
- if (GET_CODE (XEXP (x, 0)) == SUBREG
- && subreg_lowpart_p (XEXP (x, 0))
- && GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE)
- return SUBREG_REG (XEXP (x, 0));
break;
- case FLOAT_EXTEND:
- /* (float_extend (float_extend x)) is (float_extend x)
-
- (float_extend (float x)) is (float x) assuming that double
- rounding can't happen.
- */
- if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
- || (GET_CODE (XEXP (x, 0)) == FLOAT
- && ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
- >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
- - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
- GET_MODE (XEXP (XEXP (x, 0), 0)))))))
- return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
- XEXP (XEXP (x, 0), 0),
- GET_MODE (XEXP (XEXP (x, 0), 0)));
- break;
#ifdef HAVE_cc0
case COMPARE:
/* Convert (compare FOO (const_int 0)) to FOO unless we aren't
#endif
case PLUS:
- /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).
- */
- if (GET_CODE (XEXP (x, 0)) == MULT
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == NEG)
- {
- rtx in1, in2;
-
- in1 = XEXP (XEXP (XEXP (x, 0), 0), 0);
- in2 = XEXP (XEXP (x, 0), 1);
- return simplify_gen_binary (MINUS, mode, XEXP (x, 1),
- simplify_gen_binary (MULT, mode,
- in1, in2));
- }
-
- /* If we have (plus (plus (A const) B)), associate it so that CONST is
- outermost. That's because that's the way indexed addresses are
- supposed to appear. This code used to check many more cases, but
- they are now checked elsewhere. */
- if (GET_CODE (XEXP (x, 0)) == PLUS
- && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
- return simplify_gen_binary (PLUS, mode,
- simplify_gen_binary (PLUS, mode,
- XEXP (XEXP (x, 0), 0),
- XEXP (x, 1)),
- XEXP (XEXP (x, 0), 1));
-
/* (plus (xor (and <foo> (const_int pow2 - 1)) <c>) <-c>)
when c is (const_int (pow2 + 1) / 2) is a sign extension of a
bit-field and can be replaced by either a sign_extend or a
GET_MODE_BITSIZE (mode) - (i + 1)),
GET_MODE_BITSIZE (mode) - (i + 1));
- /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
- C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
- is 1. This produces better code than the alternative immediately
- below. */
- if (COMPARISON_P (XEXP (x, 0))
- && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
- || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))
- && (reversed = reversed_comparison (XEXP (x, 0), mode)))
- return
- simplify_gen_unary (NEG, mode, reversed, mode);
-
/* If only the low-order bit of X is possibly nonzero, (plus x -1)
can become (ashiftrt (ashift (xor x 1) C) C) where C is
the bitsize of the mode - 1. This allows simplification of
break;
case MINUS:
- /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
- by reversing the comparison code if valid. */
- if (STORE_FLAG_VALUE == 1
- && XEXP (x, 0) == const1_rtx
- && COMPARISON_P (XEXP (x, 1))
- && (reversed = reversed_comparison (XEXP (x, 1), mode)))
- return reversed;
-
/* (minus <foo> (and <foo> (const_int -pow2))) becomes
(and <foo> (const_int pow2-1)) */
if (GET_CODE (XEXP (x, 1)) == AND
&& rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
-INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
-
- /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).
- */
- if (GET_CODE (XEXP (x, 1)) == MULT
- && GET_CODE (XEXP (XEXP (x, 1), 0)) == NEG)
- {
- rtx in1, in2;
-
- in1 = XEXP (XEXP (XEXP (x, 1), 0), 0);
- in2 = XEXP (XEXP (x, 1), 1);
- return simplify_gen_binary (PLUS, mode,
- simplify_gen_binary (MULT, mode,
- in1, in2),
- XEXP (x, 0));
- }
-
- /* Canonicalize (minus (neg A) (mult B C)) to
- (minus (mult (neg B) C) A). */
- if (GET_CODE (XEXP (x, 1)) == MULT
- && GET_CODE (XEXP (x, 0)) == NEG)
- {
- rtx in1, in2;
-
- in1 = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 1), 0), mode);
- in2 = XEXP (XEXP (x, 1), 1);
- return simplify_gen_binary (MINUS, mode,
- simplify_gen_binary (MULT, mode,
- in1, in2),
- XEXP (XEXP (x, 0), 0));
- }
-
- /* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for
- integers. */
- if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
- return simplify_gen_binary (MINUS, mode,
- simplify_gen_binary (MINUS, mode,
- XEXP (x, 0),
- XEXP (XEXP (x, 1), 0)),
- XEXP (XEXP (x, 1), 1));
break;
case MULT:
case AND:
case IOR:
- case XOR:
return simplify_logical (x);
- case ABS:
- /* (abs (neg <foo>)) -> (abs <foo>) */
- if (GET_CODE (XEXP (x, 0)) == NEG)
- SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-
- /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
- do nothing. */
- if (GET_MODE (XEXP (x, 0)) == VOIDmode)
- break;
-
- /* If operand is something known to be positive, ignore the ABS. */
- if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
- || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- <= HOST_BITS_PER_WIDE_INT)
- && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
- & ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
- == 0)))
- return XEXP (x, 0);
-
- /* If operand is known to be only -1 or 0, convert ABS to NEG. */
- if (num_sign_bit_copies (XEXP (x, 0), mode) == GET_MODE_BITSIZE (mode))
- return gen_rtx_NEG (mode, XEXP (x, 0));
-
- break;
-
- case FFS:
- /* (ffs (*_extend <X>)) = (ffs <X>) */
- if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
- || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
- SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
- break;
-
- case POPCOUNT:
- case PARITY:
- /* (pop* (zero_extend <X>)) = (pop* <X>) */
- if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
- SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
- break;
-
- case FLOAT:
- /* (float (sign_extend <X>)) = (float <X>). */
- if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
- SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
- break;
-
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
0));
break;
- case VEC_SELECT:
- {
- rtx op0 = XEXP (x, 0);
- rtx op1 = XEXP (x, 1);
- int len;
-
- gcc_assert (GET_CODE (op1) == PARALLEL);
- len = XVECLEN (op1, 0);
- if (len == 1
- && GET_CODE (XVECEXP (op1, 0, 0)) == CONST_INT
- && GET_CODE (op0) == VEC_CONCAT)
- {
- int offset = INTVAL (XVECEXP (op1, 0, 0)) * GET_MODE_SIZE (GET_MODE (x));
-
- /* Try to find the element in the VEC_CONCAT. */
- for (;;)
- {
- if (GET_MODE (op0) == GET_MODE (x))
- return op0;
- if (GET_CODE (op0) == VEC_CONCAT)
- {
- HOST_WIDE_INT op0_size = GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)));
- if (offset < op0_size)
- op0 = XEXP (op0, 0);
- else
- {
- offset -= op0_size;
- op0 = XEXP (op0, 1);
- }
- }
- else
- break;
- }
- }
- }
-
- break;
-
default:
break;
}
enum machine_mode mode = GET_MODE (x);
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
- rtx tmp, reversed;
switch (GET_CODE (x))
{
case AND:
- /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
- insn (and may simplify more). */
- if (GET_CODE (op0) == XOR
- && rtx_equal_p (XEXP (op0, 0), op1)
- && ! side_effects_p (op1))
- x = simplify_gen_binary (AND, mode,
- simplify_gen_unary (NOT, mode,
- XEXP (op0, 1), mode),
- op1);
-
- if (GET_CODE (op0) == XOR
- && rtx_equal_p (XEXP (op0, 1), op1)
- && ! side_effects_p (op1))
- x = simplify_gen_binary (AND, mode,
- simplify_gen_unary (NOT, mode,
- XEXP (op0, 0), mode),
- op1);
-
- /* Similarly for (~(A ^ B)) & A. */
- if (GET_CODE (op0) == NOT
- && GET_CODE (XEXP (op0, 0)) == XOR
- && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
- && ! side_effects_p (op1))
- x = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
-
- if (GET_CODE (op0) == NOT
- && GET_CODE (XEXP (op0, 0)) == XOR
- && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
- && ! side_effects_p (op1))
- x = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
-
/* We can call simplify_and_const_int only if we don't lose
any (sign) bits when converting INTVAL (op1) to
"unsigned HOST_WIDE_INT". */
|| INTVAL (op1) > 0))
{
x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
-
- /* If we have (ior (and (X C1) C2)) and the next restart would be
- the last, simplify this by making C1 as small as possible
- and then exit. Only do this if C1 actually changes: for now
- this only saves memory but, should this transformation be
- moved to simplify-rtx.c, we'd risk unbounded recursion there. */
- if (GET_CODE (x) == IOR && GET_CODE (op0) == AND
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && GET_CODE (op1) == CONST_INT
- && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
- return simplify_gen_binary (IOR, mode,
- simplify_gen_binary
- (AND, mode, XEXP (op0, 0),
- GEN_INT (INTVAL (XEXP (op0, 1))
- & ~INTVAL (op1))), op1);
-
if (GET_CODE (x) != AND)
return x;
op1 = XEXP (x, 1);
}
- /* Convert (A | B) & A to A. */
- if (GET_CODE (op0) == IOR
- && (rtx_equal_p (XEXP (op0, 0), op1)
- || rtx_equal_p (XEXP (op0, 1), op1))
- && ! side_effects_p (XEXP (op0, 0))
- && ! side_effects_p (XEXP (op0, 1)))
- return op1;
-
/* If we have any of (and (ior A B) C) or (and (xor A B) C),
apply the distributive law and then the inverse distributive
law to see if things simplify. */
break;
case IOR:
- /* (ior A C) is C if all bits of A that might be nonzero are on in C. */
- if (GET_CODE (op1) == CONST_INT
- && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
- return op1;
-
- /* Convert (A & B) | A to A. */
- if (GET_CODE (op0) == AND
- && (rtx_equal_p (XEXP (op0, 0), op1)
- || rtx_equal_p (XEXP (op0, 1), op1))
- && ! side_effects_p (XEXP (op0, 0))
- && ! side_effects_p (XEXP (op0, 1)))
- return op1;
-
/* If we have (ior (and A B) C), apply the distributive law and then
the inverse distributive law to see if things simplify. */
if (result)
return result;
}
-
- /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
- mode size to (rotate A CX). */
-
- if (GET_CODE (op1) == ASHIFT
- || GET_CODE (op1) == SUBREG)
- tmp = op1, op1 = op0, op0 = tmp;
-
- if (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT
- && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && GET_CODE (XEXP (op1, 1)) == CONST_INT
- && (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
- == GET_MODE_BITSIZE (mode)))
- return gen_rtx_ROTATE (mode, XEXP (op1, 0), XEXP (op0, 1));
-
- /* Same, but for ashift that has been "simplified" to a wider mode
- by simplify_shift_const. */
-
- if (GET_CODE (op0) == SUBREG
- && GET_CODE (SUBREG_REG (op0)) == ASHIFT
- && GET_CODE (op1) == LSHIFTRT
- && GET_CODE (XEXP (op1, 0)) == SUBREG
- && GET_MODE (op0) == GET_MODE (XEXP (op1, 0))
- && SUBREG_BYTE (op0) == SUBREG_BYTE (XEXP (op1, 0))
- && (GET_MODE_SIZE (GET_MODE (op0))
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
- && rtx_equal_p (XEXP (SUBREG_REG (op0), 0),
- SUBREG_REG (XEXP (op1, 0)))
- && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
- && GET_CODE (XEXP (op1, 1)) == CONST_INT
- && (INTVAL (XEXP (SUBREG_REG (op0), 1)) + INTVAL (XEXP (op1, 1))
- == GET_MODE_BITSIZE (mode)))
- return gen_rtx_ROTATE (mode, XEXP (op1, 0),
- XEXP (SUBREG_REG (op0), 1));
-
- /* If OP0 is (ashiftrt (plus ...) C), it might actually be
- a (sign_extend (plus ...)). If so, OP1 is a CONST_INT, and the PLUS
- does not affect any of the bits in OP1, it can really be done
- as a PLUS and we can associate. We do this by seeing if OP1
- can be safely shifted left C bits. */
- if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
- && GET_CODE (XEXP (op0, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
- {
- int count = INTVAL (XEXP (op0, 1));
- HOST_WIDE_INT mask = INTVAL (op1) << count;
-
- if (mask >> count == INTVAL (op1)
- && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
- {
- SUBST (XEXP (XEXP (op0, 0), 1),
- GEN_INT (INTVAL (XEXP (XEXP (op0, 0), 1)) | mask));
- return op0;
- }
- }
- break;
-
- case XOR:
- /* If we are XORing two things that have no bits in common,
- convert them into an IOR. This helps to detect rotation encoded
- using those methods and possibly other simplifications. */
-
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (op0, mode)
- & nonzero_bits (op1, mode)) == 0)
- return (simplify_gen_binary (IOR, mode, op0, op1));
-
- /* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
- Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
- (NOT y). */
- {
- int num_negated = 0;
-
- if (GET_CODE (op0) == NOT)
- num_negated++, op0 = XEXP (op0, 0);
- if (GET_CODE (op1) == NOT)
- num_negated++, op1 = XEXP (op1, 0);
-
- if (num_negated == 2)
- {
- SUBST (XEXP (x, 0), op0);
- SUBST (XEXP (x, 1), op1);
- }
- else if (num_negated == 1)
- return
- simplify_gen_unary (NOT, mode,
- simplify_gen_binary (XOR, mode, op0, op1),
- mode);
- }
-
- /* Convert (xor (and A B) B) to (and (not A) B). The latter may
- correspond to a machine insn or result in further simplifications
- if B is a constant. */
-
- if (GET_CODE (op0) == AND
- && rtx_equal_p (XEXP (op0, 1), op1)
- && ! side_effects_p (op1))
- return simplify_gen_binary (AND, mode,
- simplify_gen_unary (NOT, mode,
- XEXP (op0, 0), mode),
- op1);
-
- else if (GET_CODE (op0) == AND
- && rtx_equal_p (XEXP (op0, 0), op1)
- && ! side_effects_p (op1))
- return simplify_gen_binary (AND, mode,
- simplify_gen_unary (NOT, mode,
- XEXP (op0, 1), mode),
- op1);
-
- /* (xor (comparison foo bar) (const_int 1)) can become the reversed
- comparison if STORE_FLAG_VALUE is 1. */
- if (STORE_FLAG_VALUE == 1
- && op1 == const1_rtx
- && COMPARISON_P (op0)
- && (reversed = reversed_comparison (op0, mode)))
- return reversed;
-
- /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
- is (lt foo (const_int 0)), so we can perform the above
- simplification if STORE_FLAG_VALUE is 1. */
-
- if (STORE_FLAG_VALUE == 1
- && op1 == const1_rtx
- && GET_CODE (op0) == LSHIFTRT
- && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
- return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
-
- /* (xor (comparison foo bar) (const_int sign-bit))
- when STORE_FLAG_VALUE is the sign bit. */
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
- == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
- && op1 == const_true_rtx
- && COMPARISON_P (op0)
- && (reversed = reversed_comparison (op0, mode)))
- return reversed;
-
break;
default:
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
{
- int i = -1;
+ 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.
nonzero >>= INTVAL (XEXP (x, 1));
}
- if ((mask & ~nonzero) == 0
- || (i = exact_log2 (mask)) >= 0)
+ if ((mask & ~nonzero) == 0)
+ {
+ x = simplify_shift_const (x, LSHIFTRT, GET_MODE (x),
+ XEXP (x, 0), INTVAL (XEXP (x, 1)));
+ if (GET_CODE (x) != ASHIFTRT)
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ else if ((i = exact_log2 (mask)) >= 0)
{
x = simplify_shift_const
- (x, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
- i < 0 ? INTVAL (XEXP (x, 1))
- : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
+ (NULL_RTX, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
+ GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
if (GET_CODE (x) != ASHIFTRT)
return force_to_mode (x, mode, mask, next_select);
return NULL_RTX;
}
\f
-/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
- in MODE.
-
- Return an equivalent form, if different from X. Otherwise, return X. If
- X is zero, we are to always construct the equivalent form. */
+/* Simplify a logical `and' of VAROP with the constant CONSTOP, to be done
+ in MODE. Return an equivalent form, if different from (and VAROP
+ (const_int CONSTOP)). Otherwise, return NULL_RTX. */
static rtx
-simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
- unsigned HOST_WIDE_INT constop)
+simplify_and_const_int_1 (enum machine_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
{
unsigned HOST_WIDE_INT nonzero;
+ unsigned HOST_WIDE_INT orig_constop;
+ rtx orig_varop;
int i;
+ orig_varop = varop;
+ orig_constop = constop;
+ if (GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
+
/* Simplify VAROP knowing that we will be only looking at some of the
bits in it.
return o0;
}
- /* Get VAROP in MODE. Try to get a SUBREG if not. Don't make a new SUBREG
- if we already had one (just check for the simplest cases). */
- if (x && GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_MODE (XEXP (x, 0)) == mode
- && SUBREG_REG (XEXP (x, 0)) == varop)
- varop = XEXP (x, 0);
- else
- varop = gen_lowpart (mode, varop);
-
- /* If we can't make the SUBREG, try to return what we were given. */
- if (GET_CODE (varop) == CLOBBER)
- return x ? x : varop;
+ /* Make a SUBREG if necessary. If we can't make it, fail. */
+ varop = gen_lowpart (mode, varop);
+ if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
/* If we are only masking insignificant bits, return VAROP. */
if (constop == nonzero)
- x = varop;
- else
- {
- /* Otherwise, return an AND. */
- constop = trunc_int_for_mode (constop, mode);
- /* See how much, if any, of X we can use. */
- if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
- x = simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+ return varop;
- else
- {
- if (GET_CODE (XEXP (x, 1)) != CONST_INT
- || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
- SUBST (XEXP (x, 1), GEN_INT (constop));
+ if (varop == orig_varop && constop == orig_constop)
+ return NULL_RTX;
- SUBST (XEXP (x, 0), varop);
- }
- }
+ /* Otherwise, return an AND. */
+ constop = trunc_int_for_mode (constop, mode);
+ return simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+}
+
+
+/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
+ in MODE.
+
+ Return an equivalent form, if different from X. Otherwise, return X. If
+ X is zero, we are to always construct the equivalent form. */
+
+static rtx
+simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
+{
+ rtx tem = simplify_and_const_int_1 (mode, varop, constop);
+ if (tem)
+ return tem;
+ if (!x)
+ x = simplify_gen_binary (AND, GET_MODE (varop), varop, GEN_INT (constop));
+ if (GET_MODE (x) != mode)
+ x = gen_lowpart (mode, x);
return x;
}
\f
}
\f
/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
- The result of the shift is RESULT_MODE. X, if nonzero, is an expression
- that we started with.
+ The result of the shift is RESULT_MODE. Return NULL_RTX if we cannot
+ simplify it. Otherwise, return a simplified value.
The shift is normally computed in the widest mode we find in VAROP, as
long as it isn't a different number of words than RESULT_MODE. Exceptions
- are ASHIFTRT and ROTATE, which are always done in their original mode, */
+ are ASHIFTRT and ROTATE, which are always done in their original mode. */
static rtx
-simplify_shift_const (rtx x, enum rtx_code code,
- enum machine_mode result_mode, rtx varop,
- int orig_count)
+simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
+ rtx varop, int orig_count)
{
enum rtx_code orig_code = code;
- unsigned int count;
- int signed_count;
+ rtx orig_varop = varop;
+ int count;
enum machine_mode mode = result_mode;
enum machine_mode shift_mode, tmode;
unsigned int mode_words
/* We form (outer_op (code varop count) (outer_const)). */
enum rtx_code outer_op = UNKNOWN;
HOST_WIDE_INT outer_const = 0;
- rtx const_rtx;
int complement_p = 0;
- rtx new;
+ rtx new, x;
/* Make sure and truncate the "natural" shift on the way in. We don't
want to do this inside the loop as it makes it more difficult to
what was requested. */
if (orig_count < 0 || orig_count >= (int) GET_MODE_BITSIZE (mode))
- {
- if (x)
- return x;
-
- return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (orig_count));
- }
+ return NULL_RTX;
count = orig_count;
while (count != 0)
{
- /* If we have an operand of (clobber (const_int 0)), just return that
- value. */
+ /* If we have an operand of (clobber (const_int 0)), fail. */
if (GET_CODE (varop) == CLOBBER)
- return varop;
+ return NULL_RTX;
/* If we discovered we had to complement VAROP, leave. Making a NOT
here would cause an infinite loop. */
multiple operations, each of which are defined, we know what the
result is supposed to be. */
- if (count > (unsigned int) (GET_MODE_BITSIZE (shift_mode) - 1))
+ if (count > (GET_MODE_BITSIZE (shift_mode) - 1))
{
if (code == ASHIFTRT)
count = GET_MODE_BITSIZE (shift_mode) - 1;
interpreted as the sign bit in a narrower mode, so, if
the result is narrower, don't discard the shift. */
if (code == LSHIFTRT
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& (GET_MODE_BITSIZE (result_mode)
>= GET_MODE_BITSIZE (GET_MODE (varop))))
{
(ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1).
This simplifies certain SIGN_EXTEND operations. */
if (code == ASHIFT && first_code == ASHIFTRT
- && count == (unsigned int)
- (GET_MODE_BITSIZE (result_mode)
+ && count == (GET_MODE_BITSIZE (result_mode)
- GET_MODE_BITSIZE (GET_MODE (varop))))
{
/* C3 has the low-order C1 bits zero. */
> first_count))
{
varop = XEXP (varop, 0);
-
- signed_count = count - first_count;
- if (signed_count < 0)
- count = -signed_count, code = ASHIFT;
- else
- count = signed_count;
+ count -= first_count;
+ if (count < 0)
+ {
+ count = -count;
+ code = ASHIFT;
+ }
continue;
}
mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
mask_rtx
- = simplify_binary_operation (code, result_mode, mask_rtx,
- GEN_INT (count));
+ = simplify_const_binary_operation (code, result_mode, mask_rtx,
+ GEN_INT (count));
/* Give up if we can't compute an outer operation to use. */
if (mask_rtx == 0
/* If the shifts are in the same direction, we add the
counts. Otherwise, we subtract them. */
- signed_count = count;
if ((code == ASHIFTRT || code == LSHIFTRT)
== (first_code == ASHIFTRT || first_code == LSHIFTRT))
- signed_count += first_count;
+ count += first_count;
else
- signed_count -= first_count;
+ count -= first_count;
/* If COUNT is positive, the new shift is usually CODE,
except for the two exceptions below, in which case it is
FIRST_CODE. If the count is negative, FIRST_CODE should
always be used */
- if (signed_count > 0
+ if (count > 0
&& ((first_code == ROTATE && code == ASHIFT)
|| (first_code == ASHIFTRT && code == LSHIFTRT)))
- code = first_code, count = signed_count;
- else if (signed_count < 0)
- code = first_code, count = -signed_count;
- else
- count = signed_count;
+ code = first_code;
+ else if (count < 0)
+ code = first_code, count = -count;
varop = XEXP (varop, 0);
continue;
B is not a constant. */
else if (GET_CODE (varop) == code
- && GET_CODE (XEXP (varop, 1)) != CONST_INT
- && 0 != (new
- = simplify_binary_operation (code, mode,
- XEXP (varop, 0),
- GEN_INT (count))))
+ && GET_CODE (XEXP (varop, 0)) == CONST_INT
+ && GET_CODE (XEXP (varop, 1)) != CONST_INT)
{
+ rtx new = simplify_const_binary_operation (code, mode,
+ XEXP (varop, 0),
+ GEN_INT (count));
varop = gen_rtx_fmt_ee (code, mode, new, XEXP (varop, 1));
count = 0;
continue;
&& XEXP (XEXP (varop, 0), 1) == constm1_rtx
&& (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == LSHIFTRT || code == ASHIFTRT)
- && count == (unsigned int)
- (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+ && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
&& !(code == ASHIFTRT && GET_CODE (varop) == XOR
&& 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
shift_mode))
- && (new = simplify_binary_operation (code, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
+ && (new = simplify_const_binary_operation (code, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
&& GET_CODE (new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
INTVAL (new), result_mode, &complement_p))
if (code == LSHIFTRT
&& XEXP (varop, 1) == const0_rtx
&& GET_MODE (XEXP (varop, 0)) == result_mode
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
- && ((STORE_FLAG_VALUE
- & ((HOST_WIDE_INT) 1
- < (GET_MODE_BITSIZE (result_mode) - 1))))
+ && STORE_FLAG_VALUE == -1
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
(HOST_WIDE_INT) 1, result_mode,
/* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
than the number of bits in the mode is equivalent to A. */
if (code == LSHIFTRT
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1)
{
varop = XEXP (varop, 0);
is one less than the number of bits in the mode is
equivalent to (xor A 1). */
if (code == LSHIFTRT
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& XEXP (varop, 1) == constm1_rtx
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
/* (ashift (plus foo C) N) is (plus (ashift foo N) C'). */
if (code == ASHIFT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
- && (new = simplify_binary_operation (ASHIFT, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
+ && (new = simplify_const_binary_operation (ASHIFT, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
&& GET_CODE (new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, PLUS,
INTVAL (new), result_mode, &complement_p))
if (code == LSHIFTRT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
&& mode_signbit_p (result_mode, XEXP (varop, 1))
- && (new = simplify_binary_operation (code, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
+ && (new = simplify_const_binary_operation (code, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
&& GET_CODE (new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, XOR,
INTVAL (new), result_mode, &complement_p))
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& GET_CODE (XEXP (varop, 0)) == ASHIFTRT
- && count == (unsigned int)
- (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+ && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1))
- == count
+ && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If
OUTER_OP is non-UNKNOWN, it is an operation that needs to be applied
to the result of the shift. OUTER_CONST is the relevant constant,
- but we must turn off all bits turned off in the shift.
-
- If we were passed a value for X, see if we can use any pieces of
- it. If not, make new rtx. */
-
- if (x && GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count)
- const_rtx = XEXP (x, 1);
- else
- const_rtx = GEN_INT (count);
-
- if (x && GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_MODE (XEXP (x, 0)) == shift_mode
- && SUBREG_REG (XEXP (x, 0)) == varop)
- varop = XEXP (x, 0);
- else if (GET_MODE (varop) != shift_mode)
- varop = gen_lowpart (shift_mode, varop);
+ but we must turn off all bits turned off in the shift. */
- /* If we can't make the SUBREG, try to return what we were given. */
- if (GET_CODE (varop) == CLOBBER)
- return x ? x : varop;
+ if (outer_op == UNKNOWN
+ && orig_code == code && orig_count == count
+ && varop == orig_varop
+ && shift_mode == GET_MODE (varop))
+ return NULL_RTX;
- new = simplify_binary_operation (code, shift_mode, varop, const_rtx);
- if (new != 0)
- x = new;
- else
- x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx);
+ /* Make a SUBREG if necessary. If we can't make it, fail. */
+ varop = gen_lowpart (shift_mode, varop);
+ if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
/* If we have an outer operation and we just made a shift, it is
possible that we could have simplified the shift were it not
for the outer operation. So try to do the simplification
recursively. */
- if (outer_op != UNKNOWN && GET_CODE (x) == code
- && GET_CODE (XEXP (x, 1)) == CONST_INT)
- x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
- INTVAL (XEXP (x, 1)));
+ if (outer_op != UNKNOWN)
+ x = simplify_shift_const_1 (code, shift_mode, varop, count);
+ else
+ x = NULL_RTX;
+
+ if (x == NULL_RTX)
+ x = simplify_gen_binary (code, shift_mode, varop, GEN_INT (count));
/* If we were doing an LSHIFTRT in a wider mode than it was originally,
turn off all the bits that the shift would have turned off. */
return x;
}
+
+/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
+ The result of the shift is RESULT_MODE. If we cannot simplify it,
+ return X or, if it is NULL, synthesize the expression with
+ simplify_gen_binary. Otherwise, return a simplified value.
+
+ The shift is normally computed in the widest mode we find in VAROP, as
+ long as it isn't a different number of words than RESULT_MODE. Exceptions
+ are ASHIFTRT and ROTATE, which are always done in their original mode. */
+
+static rtx
+simplify_shift_const (rtx x, enum rtx_code code, enum machine_mode result_mode,
+ rtx varop, int count)
+{
+ rtx tem = simplify_shift_const_1 (code, result_mode, varop, count);
+ if (tem)
+ return tem;
+
+ if (!x)
+ x = simplify_gen_binary (code, GET_MODE (varop), varop, GEN_INT (count));
+ if (GET_MODE (x) != result_mode)
+ x = gen_lowpart (result_mode, x);
+ return x;
+}
+
\f
/* Like recog, but we receive the address of a pointer to a new pattern.
We try to match the rtx that the pointer points to.
&& XEXP (XEXP (op0, 0), 0) == const1_rtx)
{
op0 = simplify_and_const_int
- (op0, mode, gen_rtx_LSHIFTRT (mode,
- XEXP (op0, 1),
- XEXP (XEXP (op0, 0), 1)),
+ (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
+ XEXP (op0, 1),
+ XEXP (XEXP (op0, 0), 1)),
(HOST_WIDE_INT) 1);
continue;
}