diff options
Diffstat (limited to 'gcc/config/rs6000/predicates.md')
-rw-r--r-- | gcc/config/rs6000/predicates.md | 63 |
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") |