"A signed 34-bit integer constant if prefixed instructions are supported."
(match_operand 0 "cint34_operand"))
+;; KF/TF scalar than can be loaded with LXVKQ
+(define_constraint "eQ"
+ "An IEEE 128-bit constant that can be loaded with the LXVKQ instruction."
+ (match_operand 0 "lxvkq_operand"))
+
;; Floating-point constraints. These two are defined so that insn
;; length attributes can be calculated exactly.
if (xxspltidp_operand (op, mode))
return 1;
+ /* If we have the ISA 3.1 LXVKQ instruction, see if the constant can be loaded
+ with that instruction. */
+ if (lxvkq_operand (op, mode))
+ return 1;
+
/* Otherwise consider floating point constants hard, so that the
constant gets pushed to memory during the early RTL phases. This
has the advantage that double precision constants that can be
return xxspltidp_constant_p (op, mode, &value);
})
+;; Return 1 if the operand is an IEEE 128-bit special constant that can be
+;; loaded with the LXVKQ instruction.
+(define_predicate "lxvkq_operand"
+ (match_code "const_double")
+{
+ int immediate = 0;
+ return lxvkq_constant_p (op, mode, &immediate);
+})
+
;; Return 1 if the operand is a CONST_VECTOR and can be loaded into a
;; vector register without using memory.
(define_predicate "easy_vector_constant"
extern int easy_altivec_constant (rtx, machine_mode);
extern bool xxspltib_constant_p (rtx, machine_mode, int *, int *);
extern bool xxspltidp_constant_p (rtx, machine_mode, HOST_WIDE_INT *);
+extern bool lxvkq_constant_p (rtx, machine_mode, int *);
extern int vspltis_shifted (rtx);
extern HOST_WIDE_INT const_vector_elt_as_int (rtx, unsigned int);
extern bool macho_lo_sum_memory_operand (rtx, machine_mode);
return true;
}
+/* Return true if OP is of the given MODE is one of the 18 special values that
+ can be generated with the LXVKQ instruction.
+
+ Return the constant that will go in the LXVKQ instruction. */
+
+/* LXVKQ immediates. */
+enum {
+ LXVKQ_ONE = 1,
+ LXVKQ_TWO = 2,
+ LXVKQ_THREE = 3,
+ LXVKQ_FOUR = 4,
+ LXVKQ_FIVE = 5,
+ LXVKQ_SIX = 6,
+ LXVKQ_SEVEN = 7,
+ LXVKQ_INF = 8,
+ LXVKQ_NAN = 9,
+ LXVKQ_NEG_ZERO = 16,
+ LXVKQ_NEG_ONE = 17,
+ LXVKQ_NEG_TWO = 18,
+ LXVKQ_NEG_THREE = 19,
+ LXVKQ_NEG_FOUR = 20,
+ LXVKQ_NEG_FIVE = 21,
+ LXVKQ_NEG_SIX = 22,
+ LXVKQ_NEG_SEVEN = 23,
+ LXVKQ_NEG_INF = 24
+};
+
+bool
+lxvkq_constant_p (rtx op,
+ machine_mode mode,
+ int *imm_p)
+{
+ *imm_p = -1;
+
+ if (!TARGET_LXVKQ || !TARGET_POWER10 || !TARGET_VSX || !TARGET_FLOAT128_HW)
+ return false;
+
+ if (mode == VOIDmode)
+ mode = GET_MODE (op);
+
+ if (!FLOAT128_IEEE_P (mode))
+ return false;
+
+ if (!CONST_DOUBLE_P (op))
+ return false;
+
+ /* All of the values generated can be expressed as SFmode values, so if it
+ doesn't fit in SFmode, exit. */
+ const struct real_value *rv = CONST_DOUBLE_REAL_VALUE (op);
+ if (!exact_real_truncate (SFmode, rv))
+ return 0;
+
+ /* Special values (infinity, nan, -0.0. */
+ if (real_isinf (rv))
+ {
+ *imm_p = real_isneg (rv) ? LXVKQ_NEG_INF : LXVKQ_INF;
+ return true;
+ }
+
+ if (real_isnan (rv) && !real_isneg (rv))
+ {
+ *imm_p = LXVKQ_NAN;
+ return true;
+ }
+
+ if (real_isnegzero (rv))
+ {
+ *imm_p = LXVKQ_NEG_ZERO;
+ return true;
+ }
+
+ /* The other values are all integers 1..7, and -1..-7. */
+ if (!real_isinteger (rv, mode))
+ return false;
+
+ HOST_WIDE_INT value = real_to_integer (rv);
+ switch (value)
+ {
+ default:
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ *imm_p = LXVKQ_ONE + (value - 1);
+ return true;
+
+ case -1:
+ case -2:
+ case -3:
+ case -4:
+ case -5:
+ case -6:
+ case -7:
+ *imm_p = LXVKQ_NEG_ONE + (-value - 1);
+ return true;
+ }
+
+ /* We can't load the value with LXVKQ. */
+ return false;
+}
+
const char *
output_vec_const_move (rtx *operands)
{
int xxspltib_value = 256;
HOST_WIDE_INT xxspltidp_value = 0;
int num_insns = -1;
+ int lxvkq_immediate = 0;
if (zero_constant (vec, mode))
{
return "xxspltidp %x0,%2";
}
+ if (lxvkq_constant_p (vec, mode, &lxvkq_immediate))
+ {
+ operands[2] = GEN_INT (lxvkq_immediate);
+ return "lxvkq %x0,%2";
+ }
+
if (TARGET_P9_VECTOR
&& xxspltib_constant_p (vec, mode, &num_insns, &xxspltib_value))
{
int src_regno;
bool dest_gpr_p, dest_fp_p, dest_vmx_p, dest_vsx_p;
bool src_gpr_p, src_fp_p, src_vmx_p, src_vsx_p;
+ int lxvkq_immediate = 0;
if (REG_P (dest))
{
}
/* Constants. */
+ else if (dest_vmx_p
+ && CONST_DOUBLE_P (src)
+ && lxvkq_constant_p (src, mode, &lxvkq_immediate))
+ {
+ operands[2] = GEN_INT (lxvkq_immediate);
+ return "lxvkq %x0,%2";
+ }
+
else if (dest_regno >= 0
&& (CONST_INT_P (src)
|| CONST_WIDE_INT_P (src)
mxxspltidp
Target Undocumented Var(TARGET_XXSPLTIDP) Init(1) Save
Generate (do not generate) XXSPLTIDP instructions.
+
+mlxvkq
+Target Undocumented Var(TARGET_LXVKQ) Init(1) Save
+Generate (do not generate) LXVKQ instructions.
;; instruction). But generate XXLXOR/XXLORC if it will avoid a register move.
;; VSX store VSX load VSX move VSX->GPR GPR->VSX LQ (GPR)
-;; XXSPLTIDP
+;; XXSPLTIDP LXVKQ
;; STQ (GPR) GPR load GPR store GPR move XXSPLTIB VSPLTISW
;; VSX 0/-1 VMX const GPR const LVX (VMX) STVX (VMX)
(define_insn "vsx_mov<mode>_64bit"
[(set (match_operand:VSX_M 0 "nonimmediate_operand"
"=ZwO, wa, wa, r, we, ?wQ,
- wa,
+ wa, wa,
?&r, ??r, ??Y, <??r>, wa, v,
?wa, v, <??r>, wZ, v")
(match_operand:VSX_M 1 "input_operand"
"wa, ZwO, wa, we, r, r,
- eF,
+ eF, eQ,
wQ, Y, r, r, wE, jwM,
?jwM, W, <nW>, v, wZ"))]
}
[(set_attr "type"
"vecstore, vecload, vecsimple, mtvsr, mfvsr, load,
- vecperm,
+ vecperm, vecperm,
store, load, store, *, vecsimple, vecsimple,
vecsimple, *, *, vecstore, vecload")
(set_attr "num_insns"
"*, *, *, 2, *, 2,
- *,
+ *, *,
2, 2, 2, 2, *, *,
*, 5, 2, *, *")
(set_attr "max_prefixed_insns"
"*, *, *, *, *, 2,
- *,
+ *, *,
2, 2, 2, 2, *, *,
*, *, *, *, *")
(set_attr "length"
"*, *, *, 8, *, 8,
- *,
+ *, *,
8, 8, 8, 8, *, *,
*, 20, 8, *, *")
(set_attr "isa"
"<VSisa>, <VSisa>, <VSisa>, *, *, *,
- p10,
+ p10, p10,
*, *, *, *, p9v, *,
<VSisa>, *, *, *, *")])
;; VSX store VSX load VSX move GPR load GPR store GPR move
-;; XXSPLTIDP
+;; XXSPLTIDP LXVKQ
;; XXSPLTIB VSPLTISW VSX 0/-1 VMX const GPR const
;; LVX (VMX) STVX (VMX)
(define_insn "*vsx_mov<mode>_32bit"
[(set (match_operand:VSX_M 0 "nonimmediate_operand"
"=ZwO, wa, wa, ??r, ??Y, <??r>,
- wa,
+ wa, wa,
wa, v, ?wa, v, <??r>,
wZ, v")
(match_operand:VSX_M 1 "input_operand"
"wa, ZwO, wa, Y, r, r,
- eF,
+ eF, eQ,
wE, jwM, ?jwM, W, <nW>,
v, wZ"))]
}
[(set_attr "type"
"vecstore, vecload, vecsimple, load, store, *,
- vecperm,
+ vecperm, vecperm,
vecsimple, vecsimple, vecsimple, *, *,
vecstore, vecload")
(set_attr "length"
"*, *, *, 16, 16, 16,
- *,
+ *, *,
*, *, *, 20, 16,
*, *")
(set_attr "isa"
"<VSisa>, <VSisa>, <VSisa>, *, *, *,
- p10,
+ p10, p10,
p9v, *, <VSisa>, *, *,
*, *")])
--- /dev/null
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
+
+/* Test whether the LXVKQ instruction is generated to load special IEEE 128-bit
+ constants. */
+
+_Float128
+return_0 (void)
+{
+ return 0.0f128; /* XXSPLTIB 34,0. */
+}
+
+_Float128
+return_1 (void)
+{
+ return 1.0f128; /* LXVKQ 34,1. */
+}
+
+_Float128
+return_2 (void)
+{
+ return 2.0f128; /* LXVKQ 34,2. */
+}
+
+_Float128
+return_3 (void)
+{
+ return 3.0f128; /* LXVKQ 34,3. */
+}
+
+_Float128
+return_4 (void)
+{
+ return 4.0f128; /* LXVKQ 34,4. */
+}
+
+_Float128
+return_5 (void)
+{
+ return 5.0f128; /* LXVKQ 34,5. */
+}
+
+_Float128
+return_6 (void)
+{
+ return 6.0f128; /* LXVKQ 34,6. */
+}
+
+_Float128
+return_7 (void)
+{
+ return 7.0f128; /* LXVKQ 34,7. */
+}
+
+_Float128
+return_m0 (void)
+{
+ return -0.0f128; /* LXVKQ 34,16. */
+}
+
+_Float128
+return_m1 (void)
+{
+ return -1.0f128; /* LXVKQ 34,17. */
+}
+
+_Float128
+return_m2 (void)
+{
+ return -2.0f128; /* LXVKQ 34,18. */
+}
+
+_Float128
+return_m3 (void)
+{
+ return -3.0f128; /* LXVKQ 34,19. */
+}
+
+_Float128
+return_m4 (void)
+{
+ return -4.0f128; /* LXVKQ 34,20. */
+}
+
+_Float128
+return_m5 (void)
+{
+ return -5.0f128; /* LXVKQ 34,21. */
+}
+
+_Float128
+return_m6 (void)
+{
+ return -6.0f128; /* LXVKQ 34,22. */
+}
+
+_Float128
+return_m7 (void)
+{
+ return -7.0f128; /* LXVKQ 34,23. */
+}
+
+_Float128
+return_inf (void)
+{
+ return __builtin_inff128 (); /* LXVKQ 34,8. */
+}
+
+_Float128
+return_minf (void)
+{
+ return - __builtin_inff128 (); /* LXVKQ 34,24. */
+}
+
+_Float128
+return_nan (void)
+{
+ return __builtin_nanf128 (""); /* LXVKQ 34,9. */
+}
+
+/* Note, the following NaNs should not generate a LXVKQ instruction. */
+_Float128
+return_mnan (void)
+{
+ return - __builtin_nanf128 (""); /* PLXV 34,... */
+}
+
+_Float128
+return_nan2 (void)
+{
+ return __builtin_nanf128 ("1"); /* PLXV 34,... */
+}
+
+_Float128
+return_nans (void)
+{
+ return __builtin_nansf128 (""); /* PLXV 34,... */
+}
+
+/* { dg-final { scan-assembler-times {\mlxvkq\M} 18 } } */
+/* { dg-final { scan-assembler-times {\mplxv\M} 3 } } */
+/* { dg-final { scan-assembler-times {\mxxspltib\M} 1 } } */
+