aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/predicates.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/predicates.md')
-rw-r--r--gcc/config/rs6000/predicates.md63
1 files changed, 63 insertions, 0 deletions
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 5cc80dea66c..46c8f40f270 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -709,6 +709,69 @@
return op == CONST0_RTX (mode) || op == CONSTM1_RTX (mode);
})
+;; Return 1 if the operand is a V2DI or V4SI const_vector, where each element
+;; is the same constant, and the constant can be used for a shift operation.
+;; This is to prevent sub-optimal code, that needs to load up the constant and
+;; then zero extend it 32 or 64-bit vectors or load up the constant from the
+;; literal pool.
+;;
+;; For V4SImode, we only recognize shifts by 16..31 on ISA 3.0, since shifts by
+;; 1..15 can be handled by the normal VSPLTISW and vector shift instruction.
+;; For V2DImode, we do this all of the time, since there is no convenient
+;; instruction to load up a vector long long splatted constant.
+;;
+;; If we can use XXSPLTIB, then allow constants up to 63. If not, we restrict
+;; the constant to 0..15 that can be loaded with VSPLTISW. V4SI shifts are
+;; only optimized for ISA 3.0 when the shift value is >= 16 and <= 31. Values
+;; between 0 and 15 can use a normal VSPLTISW to load the value, and it doesn't
+;; need this optimization.
+(define_predicate "vector_shift_constant"
+ (match_code "const_vector,vec_duplicate")
+{
+ unsigned HOST_WIDE_INT min_value;
+
+ if (mode == V2DImode)
+ {
+ min_value = 0;
+ if (!TARGET_P8_VECTOR)
+ return 0;
+ }
+ else if (mode == V4SImode)
+ {
+ min_value = 16;
+ if (!TARGET_P9_VECTOR)
+ return 0;
+ }
+ else
+ return 0;
+
+ unsigned HOST_WIDE_INT max_value = TARGET_P9_VECTOR ? 63 : 15;
+
+ if (GET_CODE (op) == CONST_VECTOR)
+ {
+ unsigned HOST_WIDE_INT first = UINTVAL (CONST_VECTOR_ELT (op, 0));
+ unsigned nunits = GET_MODE_NUNITS (mode);
+ unsigned i;
+
+ if (!IN_RANGE (first, min_value, max_value))
+ return 0;
+
+ for (i = 1; i < nunits; i++)
+ if (first != UINTVAL (CONST_VECTOR_ELT (op, i)))
+ return 0;
+
+ return 1;
+ }
+ else
+ {
+ rtx op0 = XEXP (op, 0);
+ if (!CONST_INT_P (op0))
+ return 0;
+
+ return IN_RANGE (UINTVAL (op0), min_value, max_value);
+ }
+})
+
;; Return 1 if operand is 0.0.
(define_predicate "zero_fp_constant"
(and (match_code "const_double")