+2015-08-20 Richard Sandiford <richard.sandiford@arm.com>
+
+ * rtl.h (rtvec_all_equal_p): Declare.
+ (const_vec_duplicate_p, unwrap_const_vec_duplicate): New functions.
+ * rtl.c (rtvec_all_equal_p): New function.
+ * expmed.c (expand_mult): Use unwrap_const_vec_duplicate.
+ * config/aarch64/aarch64.c (aarch64_vect_float_const_representable_p)
+ (aarch64_simd_dup_constant): Use const_vec_duplicate_p.
+ * config/arm/arm.c (neon_vdup_constant): Likewise.
+ * config/s390/s390.c (s390_contiguous_bitmask_vector_p): Likewise.
+ * config/tilegx/constraints.md (W, Y): Likewise.
+ * config/tilepro/constraints.md (W, Y): Likewise.
+ * config/spu/spu.c (spu_legitimate_constant_p): Likewise.
+ (classify_immediate): Use unwrap_const_vec_duplicate.
+ * config/tilepro/predicates.md (reg_or_v4s8bit_operand): Likewise.
+ (reg_or_v2s8bit_operand): Likewise.
+ * config/tilegx/predicates.md (reg_or_v8s8bit_operand): Likewise.
+ (reg_or_v4s8bit_operand): Likewise.
+
2015-08-20 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* config/rs6000/altivec.h (vec_pmsum_be): New #define.
static bool
aarch64_vect_float_const_representable_p (rtx x)
{
- int i = 0;
- REAL_VALUE_TYPE r0, ri;
- rtx x0, xi;
-
- if (GET_MODE_CLASS (GET_MODE (x)) != MODE_VECTOR_FLOAT)
- return false;
-
- x0 = CONST_VECTOR_ELT (x, 0);
- if (!CONST_DOUBLE_P (x0))
- return false;
-
- REAL_VALUE_FROM_CONST_DOUBLE (r0, x0);
-
- for (i = 1; i < CONST_VECTOR_NUNITS (x); i++)
- {
- xi = CONST_VECTOR_ELT (x, i);
- if (!CONST_DOUBLE_P (xi))
- return false;
-
- REAL_VALUE_FROM_CONST_DOUBLE (ri, xi);
- if (!REAL_VALUES_EQUAL (r0, ri))
- return false;
- }
-
- return aarch64_float_const_representable_p (x0);
+ rtx elt;
+ return (GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR_FLOAT
+ && const_vec_duplicate_p (x, &elt)
+ && aarch64_float_const_representable_p (elt));
}
/* Return true for valid and false for invalid. */
{
machine_mode mode = GET_MODE (vals);
machine_mode inner_mode = GET_MODE_INNER (mode);
- int n_elts = GET_MODE_NUNITS (mode);
- bool all_same = true;
rtx x;
- int i;
-
- if (GET_CODE (vals) != CONST_VECTOR)
- return NULL_RTX;
-
- for (i = 1; i < n_elts; ++i)
- {
- x = CONST_VECTOR_ELT (vals, i);
- if (!rtx_equal_p (x, CONST_VECTOR_ELT (vals, 0)))
- all_same = false;
- }
- if (!all_same)
+ if (!const_vec_duplicate_p (vals, &x))
return NULL_RTX;
/* We can load this constant by using DUP and a constant in a
single ARM register. This will be cheaper than a vector
load. */
- x = copy_to_mode_reg (inner_mode, CONST_VECTOR_ELT (vals, 0));
+ x = copy_to_mode_reg (inner_mode, x);
return gen_rtx_VEC_DUPLICATE (mode, x);
}
{
machine_mode mode = GET_MODE (vals);
machine_mode inner_mode = GET_MODE_INNER (mode);
- int n_elts = GET_MODE_NUNITS (mode);
- bool all_same = true;
rtx x;
- int i;
if (GET_CODE (vals) != CONST_VECTOR || GET_MODE_SIZE (inner_mode) > 4)
return NULL_RTX;
- for (i = 0; i < n_elts; ++i)
- {
- x = XVECEXP (vals, 0, i);
- if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
- all_same = false;
- }
-
- if (!all_same)
+ if (!const_vec_duplicate_p (vals, &x))
/* The elements are not all the same. We could handle repeating
patterns of a mode larger than INNER_MODE here (e.g. int8x8_t
{0, C, 0, C, 0, C, 0, C} which can be loaded using
single ARM register. This will be cheaper than a vector
load. */
- x = copy_to_mode_reg (inner_mode, XVECEXP (vals, 0, 0));
+ x = copy_to_mode_reg (inner_mode, x);
return gen_rtx_VEC_DUPLICATE (mode, x);
}
{
unsigned HOST_WIDE_INT mask;
int length, size;
+ rtx elt;
- if (!VECTOR_MODE_P (GET_MODE (op))
- || GET_CODE (op) != CONST_VECTOR
- || !CONST_INT_P (XVECEXP (op, 0, 0)))
+ if (!const_vec_duplicate_p (op, &elt)
+ || !CONST_INT_P (elt))
return false;
- if (GET_MODE_NUNITS (GET_MODE (op)) > 1)
- {
- int i;
-
- for (i = 1; i < GET_MODE_NUNITS (GET_MODE (op)); ++i)
- if (!rtx_equal_p (XVECEXP (op, 0, i), XVECEXP (op, 0, 0)))
- return false;
- }
-
size = GET_MODE_UNIT_BITSIZE (GET_MODE (op));
- mask = UINTVAL (XVECEXP (op, 0, 0));
+ mask = UINTVAL (elt);
if (s390_contiguous_bitmask_p (mask, size, start,
end != NULL ? &length : NULL))
{
&& mode == V4SImode
&& GET_CODE (op) == CONST_VECTOR
&& GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_INT
- && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_DOUBLE
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
- && CONST_VECTOR_ELT (op, 1) == CONST_VECTOR_ELT (op, 2)
- && CONST_VECTOR_ELT (op, 2) == CONST_VECTOR_ELT (op, 3))
- op = CONST_VECTOR_ELT (op, 0);
+ && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_DOUBLE)
+ op = unwrap_const_vec_duplicate (op);
switch (GET_CODE (op))
{
&& (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF
|| GET_CODE (CONST_VECTOR_ELT (x, 0)) == LABEL_REF
|| GET_CODE (CONST_VECTOR_ELT (x, 0)) == CONST))
- return CONST_VECTOR_ELT (x, 0) == CONST_VECTOR_ELT (x, 1)
- && CONST_VECTOR_ELT (x, 1) == CONST_VECTOR_ELT (x, 2)
- && CONST_VECTOR_ELT (x, 2) == CONST_VECTOR_ELT (x, 3);
+ return const_vec_duplicate_p (x);
if (GET_CODE (x) == CONST_VECTOR
&& !const_vector_immediate_p (x))
"An 8-element vector constant with identical elements"
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 8")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 2)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 3)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 4)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 5)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 6)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 7)")))
+ (match_test "const_vec_duplicate_p (op)")))
(define_constraint "Y"
"A 4-element vector constant with identical elements"
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 4")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 2)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 3)")))
+ (match_test "const_vec_duplicate_p (op)")))
+
(define_constraint "Z0"
"The integer constant 0xffffffff"
(and (match_code "const_int")
(ior (match_operand 0 "register_operand")
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 8
- && satisfies_constraint_I (CONST_VECTOR_ELT (op, 0))
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 2)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 3)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 4)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 5)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 6)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 7)"))))
+ && (satisfies_constraint_I
+ (unwrap_const_vec_duplicate (op)))"))))
;; Return 1 if OP is a 4-element vector constant with identical signed
;; 8-bit elements or any register.
(ior (match_operand 0 "register_operand")
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 4
- && satisfies_constraint_I (CONST_VECTOR_ELT (op, 0))
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 2)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 3)"))))
+ && (satisfies_constraint_I
+ (unwrap_const_vec_duplicate (op)))"))))
;; Return 1 if the operand is a valid second operand to an add insn.
(define_predicate "add_operand"
"A 4-element vector constant with identical elements"
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 4")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 2)")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 3)")))
+ (match_test "const_vec_duplicate_p (op)")))
(define_constraint "Y"
"A 2-element vector constant with identical elements"
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 2")
- (match_test "CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)")))
+ (match_test "const_vec_duplicate_p (op)")))
(ior (match_operand 0 "register_operand")
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 4
- && satisfies_constraint_I (CONST_VECTOR_ELT (op, 0))
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 2)
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 3)"))))
+ && (satisfies_constraint_I
+ (unwrap_const_vec_duplicate (op)))"))))
;; Return 1 if OP is a 2-element vector constant with identical signed
;; 8-bit elements or any register.
(ior (match_operand 0 "register_operand")
(and (match_code "const_vector")
(match_test "CONST_VECTOR_NUNITS (op) == 2
- && satisfies_constraint_I (CONST_VECTOR_ELT (op, 0))
- && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)"))))
+ && (satisfies_constraint_I
+ (unwrap_const_vec_duplicate (op)))"))))
;; Return 1 if the operand is a valid second operand to an add insn.
(define_predicate "add_operand"
/* For vectors, there are several simplifications that can be made if
all elements of the vector constant are identical. */
- scalar_op1 = op1;
- if (GET_CODE (op1) == CONST_VECTOR)
- {
- int i, n = CONST_VECTOR_NUNITS (op1);
- scalar_op1 = CONST_VECTOR_ELT (op1, 0);
- for (i = 1; i < n; ++i)
- if (!rtx_equal_p (scalar_op1, CONST_VECTOR_ELT (op1, i)))
- goto skip_scalar;
- }
+ scalar_op1 = unwrap_const_vec_duplicate (op1);
if (INTEGRAL_MODE_P (mode))
{
target, unsignedp, OPTAB_LIB_WIDEN);
}
}
- skip_scalar:
/* This used to use umul_optab if unsigned, but for non-widening multiply
there is no difference between signed and unsigned. */
return 1;
}
+/* Return true if all elements of VEC are equal. */
+
+bool
+rtvec_all_equal_p (const_rtvec vec)
+{
+ const_rtx first = RTVEC_ELT (vec, 0);
+ /* Optimize the important special case of a vector of constants.
+ The main use of this function is to detect whether every element
+ of CONST_VECTOR is the same. */
+ switch (GET_CODE (first))
+ {
+ CASE_CONST_UNIQUE:
+ for (int i = 1, n = GET_NUM_ELEM (vec); i < n; ++i)
+ if (first != RTVEC_ELT (vec, i))
+ return false;
+ return true;
+
+ default:
+ for (int i = 1, n = GET_NUM_ELEM (vec); i < n; ++i)
+ if (!rtx_equal_p (first, RTVEC_ELT (vec, i)))
+ return false;
+ return true;
+ }
+}
+
/* Return an indication of which type of insn should have X as a body.
In generator files, this can be UNKNOWN if the answer is only known
at (GCC) runtime. Otherwise the value is CODE_LABEL, INSN, CALL_INSN
extern rtx shallow_copy_rtx_stat (const_rtx MEM_STAT_DECL);
#define shallow_copy_rtx(a) shallow_copy_rtx_stat (a MEM_STAT_INFO)
extern int rtx_equal_p (const_rtx, const_rtx);
+extern bool rtvec_all_equal_p (const_rtvec);
+
+/* Return true if X is a vector constant with a duplicated element value. */
+
+inline bool
+const_vec_duplicate_p (const_rtx x)
+{
+ return GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0));
+}
+
+/* Return true if X is a vector constant with a duplicated element value.
+ Store the duplicated element in *ELT if so. */
+
+template <typename T>
+inline bool
+const_vec_duplicate_p (T x, T *elt)
+{
+ if (const_vec_duplicate_p (x))
+ {
+ *elt = CONST_VECTOR_ELT (x, 0);
+ return true;
+ }
+ return false;
+}
+
+/* If X is a vector constant with a duplicated element value, return that
+ element value, otherwise return X. */
+
+template <typename T>
+inline T
+unwrap_const_vec_duplicate (T x)
+{
+ if (const_vec_duplicate_p (x))
+ x = CONST_VECTOR_ELT (x, 0);
+ return x;
+}
/* In emit-rtl.c */
extern rtvec gen_rtvec_v (int, rtx *);