return false;
}
-/* Analyse argument X to see if it represents an (ASHIFT X Y) operation
- and return the expression to be shifted in SHIFT_OPND and the shift amount
- in SHIFT_AMNT. This is primarily used to group handling of ASHIFT (X, CST)
- and (PLUS (X, X)) in one place. If the expression is not equivalent to an
- ASHIFT then return FALSE and set SHIFT_OPND and SHIFT_AMNT to NULL. */
-
-static bool
-extract_ashift_operands_p (rtx x, rtx *shift_opnd, rtx *shift_amnt)
-{
- if (GET_CODE (x) == ASHIFT)
- {
- *shift_opnd = XEXP (x, 0);
- *shift_amnt = XEXP (x, 1);
- return true;
- }
- if (GET_CODE (x) == PLUS && rtx_equal_p (XEXP (x, 0), XEXP (x, 1)))
- {
- *shift_opnd = XEXP (x, 0);
- *shift_amnt = CONST1_RTX (GET_MODE (x));
- return true;
- }
- *shift_opnd = NULL_RTX;
- *shift_amnt = NULL_RTX;
- return false;
-}
-
-/* OP0 and OP1 are combined under an operation of mode MODE that can
- potentially result in a ROTATE expression. Analyze the OP0 and OP1
- and return the resulting ROTATE expression if so. Return NULL otherwise.
- This is used in detecting the patterns (X << C1) [+,|,^] (X >> C2) where
- C1 + C2 == GET_MODE_UNIT_PRECISION (mode).
- (X << C1) and (C >> C2) would be OP0 and OP1. */
-
-static rtx
-simplify_rotate_op (rtx op0, rtx op1, machine_mode mode)
-{
- /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
- mode size to (rotate A CX). */
-
- rtx opleft = simplify_rtx (op0);
- rtx opright = simplify_rtx (op1);
- rtx ashift_opnd, ashift_amnt;
- /* In some cases the ASHIFT is not a direct ASHIFT. Look deeper and extract
- the relevant operands here. */
- bool ashift_op_p
- = extract_ashift_operands_p (op1, &ashift_opnd, &ashift_amnt);
-
- if (ashift_op_p
- || GET_CODE (op1) == SUBREG)
- {
- opleft = op1;
- opright = op0;
- }
- else
- {
- opright = op1;
- opleft = op0;
- ashift_op_p
- = extract_ashift_operands_p (opleft, &ashift_opnd, &ashift_amnt);
- }
-
- if (ashift_op_p && GET_CODE (opright) == LSHIFTRT
- && rtx_equal_p (ashift_opnd, XEXP (opright, 0)))
- {
- rtx leftcst = unwrap_const_vec_duplicate (ashift_amnt);
- rtx rightcst = unwrap_const_vec_duplicate (XEXP (opright, 1));
-
- if (CONST_INT_P (leftcst) && CONST_INT_P (rightcst)
- && (INTVAL (leftcst) + INTVAL (rightcst)
- == GET_MODE_UNIT_PRECISION (mode)))
- return gen_rtx_ROTATE (mode, XEXP (opright, 0), ashift_amnt);
- }
-
- /* Same, but for ashift that has been "simplified" to a wider mode
- by simplify_shift_const. */
- scalar_int_mode int_mode, inner_mode;
-
- if (GET_CODE (opleft) == SUBREG
- && is_a <scalar_int_mode> (mode, &int_mode)
- && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (opleft)),
- &inner_mode)
- && GET_CODE (SUBREG_REG (opleft)) == ASHIFT
- && GET_CODE (opright) == LSHIFTRT
- && GET_CODE (XEXP (opright, 0)) == SUBREG
- && known_eq (SUBREG_BYTE (opleft), SUBREG_BYTE (XEXP (opright, 0)))
- && GET_MODE_SIZE (int_mode) < GET_MODE_SIZE (inner_mode)
- && rtx_equal_p (XEXP (SUBREG_REG (opleft), 0),
- SUBREG_REG (XEXP (opright, 0)))
- && CONST_INT_P (XEXP (SUBREG_REG (opleft), 1))
- && CONST_INT_P (XEXP (opright, 1))
- && (INTVAL (XEXP (SUBREG_REG (opleft), 1))
- + INTVAL (XEXP (opright, 1))
- == GET_MODE_PRECISION (int_mode)))
- return gen_rtx_ROTATE (int_mode, XEXP (opright, 0),
- XEXP (SUBREG_REG (opleft), 1));
- return NULL_RTX;
-}
-
/* Subroutine of simplify_binary_operation. Simplify a binary operation
CODE with result mode MODE, operating on OP0 and OP1. If OP0 and/or
OP1 are constant pool references, TRUEOP0 and TRUEOP1 represent the
rtx op0, rtx op1,
rtx trueop0, rtx trueop1)
{
- rtx tem, reversed, elt0, elt1;
+ rtx tem, reversed, opleft, opright, elt0, elt1;
HOST_WIDE_INT val;
scalar_int_mode int_mode, inner_mode;
poly_int64 offset;
return
simplify_gen_unary (NEG, mode, reversed, mode);
- /* Convert (plus (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
- mode size to (rotate A CX). */
- if ((tem = simplify_rotate_op (op0, op1, mode)))
- return tem;
-
/* If one of the operands is a PLUS or a MINUS, see if we can
simplify this by the associative law.
Don't use the associative law for floating point.
return op1;
/* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
- mode size to (rotate A CX). */
- tem = simplify_rotate_op (op0, op1, mode);
- if (tem)
- return tem;
+ mode size to (rotate A CX). */
+
+ if (GET_CODE (op1) == ASHIFT
+ || GET_CODE (op1) == SUBREG)
+ {
+ opleft = op1;
+ opright = op0;
+ }
+ else
+ {
+ opright = op1;
+ opleft = op0;
+ }
+
+ if (GET_CODE (opleft) == ASHIFT && GET_CODE (opright) == LSHIFTRT
+ && rtx_equal_p (XEXP (opleft, 0), XEXP (opright, 0)))
+ {
+ rtx leftcst = unwrap_const_vec_duplicate (XEXP (opleft, 1));
+ rtx rightcst = unwrap_const_vec_duplicate (XEXP (opright, 1));
+
+ if (CONST_INT_P (leftcst) && CONST_INT_P (rightcst)
+ && (INTVAL (leftcst) + INTVAL (rightcst)
+ == GET_MODE_UNIT_PRECISION (mode)))
+ return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1));
+ }
+
+ /* Same, but for ashift that has been "simplified" to a wider mode
+ by simplify_shift_const. */
+
+ if (GET_CODE (opleft) == SUBREG
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (opleft)),
+ &inner_mode)
+ && GET_CODE (SUBREG_REG (opleft)) == ASHIFT
+ && GET_CODE (opright) == LSHIFTRT
+ && GET_CODE (XEXP (opright, 0)) == SUBREG
+ && known_eq (SUBREG_BYTE (opleft), SUBREG_BYTE (XEXP (opright, 0)))
+ && GET_MODE_SIZE (int_mode) < GET_MODE_SIZE (inner_mode)
+ && rtx_equal_p (XEXP (SUBREG_REG (opleft), 0),
+ SUBREG_REG (XEXP (opright, 0)))
+ && CONST_INT_P (XEXP (SUBREG_REG (opleft), 1))
+ && CONST_INT_P (XEXP (opright, 1))
+ && (INTVAL (XEXP (SUBREG_REG (opleft), 1))
+ + INTVAL (XEXP (opright, 1))
+ == GET_MODE_PRECISION (int_mode)))
+ return gen_rtx_ROTATE (int_mode, XEXP (opright, 0),
+ XEXP (SUBREG_REG (opleft), 1));
/* If OP0 is (ashiftrt (plus ...) C), it might actually be
a (sign_extend (plus ...)). Then check if OP1 is a CONST_INT and
return tem;
}
- /* Convert (xor (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
- mode size to (rotate A CX). */
- tem = simplify_rotate_op (op0, op1, mode);
- if (tem)
- return tem;
-
/* Convert (xor (and (not A) B) A) into A | B. */
if (GET_CODE (op0) == AND
&& GET_CODE (XEXP (op0, 0)) == NOT
simplify_rtx (nvm));
}
-/* Test that vector rotate formation works at RTL level. Try various
- combinations of (REG << C) [|,^,+] (REG >> (<bitwidth> - C)). */
-
-static void
-test_vector_rotate (rtx reg)
-{
- machine_mode mode = GET_MODE (reg);
- unsigned bitwidth = GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT;
- rtx plus_rtx = gen_rtx_PLUS (mode, reg, reg);
- rtx lshftrt_amnt = GEN_INT (bitwidth - 1);
- lshftrt_amnt = gen_const_vec_duplicate (mode, lshftrt_amnt);
- rtx lshiftrt_rtx = gen_rtx_LSHIFTRT (mode, reg, lshftrt_amnt);
- rtx rotate_rtx = gen_rtx_ROTATE (mode, reg, CONST1_RTX (mode));
- /* Test explicitly the case where ASHIFT (x, 1) is a PLUS (x, x). */
- ASSERT_RTX_EQ (rotate_rtx,
- simplify_rtx (gen_rtx_IOR (mode, plus_rtx, lshiftrt_rtx)));
- ASSERT_RTX_EQ (rotate_rtx,
- simplify_rtx (gen_rtx_XOR (mode, plus_rtx, lshiftrt_rtx)));
- ASSERT_RTX_EQ (rotate_rtx,
- simplify_rtx (gen_rtx_PLUS (mode, plus_rtx, lshiftrt_rtx)));
-
- /* Don't go through every possible rotate amount to save execution time.
- Multiple of BITS_PER_UNIT amounts could conceivably be simplified to
- other bswap operations sometimes. Go through just the odd amounts. */
- for (unsigned i = 3; i < bitwidth - 2; i += 2)
- {
- rtx rot_amnt = gen_const_vec_duplicate (mode, GEN_INT (i));
- rtx ashift_rtx = gen_rtx_ASHIFT (mode, reg, rot_amnt);
- lshftrt_amnt = gen_const_vec_duplicate (mode, GEN_INT (bitwidth - i));
- lshiftrt_rtx = gen_rtx_LSHIFTRT (mode, reg, lshftrt_amnt);
- rotate_rtx = gen_rtx_ROTATE (mode, reg, rot_amnt);
- ASSERT_RTX_EQ (rotate_rtx,
- simplify_rtx (gen_rtx_IOR (mode, ashift_rtx, lshiftrt_rtx)));
- ASSERT_RTX_EQ (rotate_rtx,
- simplify_rtx (gen_rtx_XOR (mode, ashift_rtx, lshiftrt_rtx)));
- ASSERT_RTX_EQ (rotate_rtx,
- simplify_rtx (gen_rtx_PLUS (mode, ashift_rtx, lshiftrt_rtx)));
- }
-}
-
/* Test subregs of integer vector constant X, trying elements in
the range [ELT_BIAS, ELT_BIAS + constant_lower_bound (NELTS)),
where NELTS is the number of elements in X. Subregs involving
{
rtx scalar_reg = make_test_reg (GET_MODE_INNER (mode));
test_vector_ops_duplicate (mode, scalar_reg);
- rtx vector_reg = make_test_reg (mode);
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
&& maybe_gt (GET_MODE_NUNITS (mode), 2))
{
test_vector_ops_series (mode, scalar_reg);
test_vector_subregs (mode);
- test_vector_rotate (vector_reg);
}
test_vec_merge (mode);
}