From: Stefan Schulze Frielinghaus <[email protected]>
This patch adds insn pattern for instruction VMAL which matches
PLUS(MULT(a, b), c) over integer vector modes and TI mode. The 64- and
128-bit element modes become available with VXE3/z17.
In order to ensure that the pattern is selected, RTX costing has to be
tweaked. First of all constant vectors never end up as immediates.
Costing for loading those via a single instruction (vzero, vone, vgm,
vgbm, vrepi) is set to COSTS_N_INSNS(1) and otherwise they have to be
loaded from constant pool and are therefore slightly penalized reflected
by costs COSTS_N_INSNS(2).
Costs for multiply-and-add are the same as for multiply only.
gcc/ChangeLog:
* config/s390/s390.cc (legitimate_reload_vector_constant_p):
Move.
(s390_rtx_costs): Add costs for VML and VMAL.
(s390_legitimate_constant_p): Utilize
legitimate_reload_vector_constant_p.
* config/s390/vector.md (*vmal<mode>): New insn pattern.
gcc/testsuite/ChangeLog:
* gcc.target/s390/vector/vmal-1.c: New test.
* gcc.target/s390/vector/vmal-2.c: New test.
---
gcc/config/s390/s390.cc | 87 ++++++---
gcc/config/s390/vector.md | 16 ++
gcc/testsuite/gcc.target/s390/vector/vmal-1.c | 85 ++++++++
gcc/testsuite/gcc.target/s390/vector/vmal-2.c | 181 ++++++++++++++++++
4 files changed, 344 insertions(+), 25 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/s390/vector/vmal-1.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/vmal-2.c
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index 36a49e5d22b..ba576680229 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -3966,6 +3966,21 @@ s390_insn_cost (rtx_insn *insn, bool speed)
return pattern_cost (PATTERN (insn), speed);
}
+/* Returns true if the constant value OP is a legitimate vector operand
+ during and after reload.
+ This function accepts all constants which can be loaded directly
+ into an VR. */
+
+static bool
+legitimate_reload_vector_constant_p (rtx op)
+{
+ return TARGET_VX && (satisfies_constraint_j00 (op)
+ || satisfies_constraint_jm1 (op)
+ || satisfies_constraint_jzz (op)
+ || satisfies_constraint_jxx (op)
+ || satisfies_constraint_jyy (op));
+}
+
/* Compute a (partial) cost for rtx X. Return true if the complete
cost has been computed, and false if subexpressions should be
scanned. In either case, *TOTAL contains the cost result. The
@@ -3978,6 +3993,7 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
int opno ATTRIBUTE_UNUSED,
int *total, bool speed ATTRIBUTE_UNUSED)
{
+ constexpr int vml_vmal_costs = COSTS_N_INSNS (5);
int code = GET_CODE (x);
switch (code)
{
@@ -3990,6 +4006,16 @@ s390_rtx_costs (rtx x, machine_mode mode, int outer_code,
case MEM:
*total = 0;
return true;
+
+ case CONST_VECTOR:
+ /* Constant vectors never end up as immediates. Penalize vectors which
+ cannot be loaded by a single instruction (vzero, vone, vgm, vgbm,
+ vrepi) and therefore go through the constant pool. */
+ *total = COSTS_N_INSNS (1);
+ if (!legitimate_reload_vector_constant_p (x))
+ *total += COSTS_N_INSNS (1);
+ return true;
+
case SET:
{
rtx dst = SET_DEST (x);
@@ -4161,12 +4187,43 @@ s390_rtx_costs (rtx x, machine_mode mode, int
outer_code,
case XOR:
case NEG:
case NOT:
- case PLUS:
case MINUS:
*total = COSTS_N_INSNS (1);
return false;
+ case PLUS:
+ /* Check for VECTOR MULTIPLY AND ADD. */
+ if (TARGET_VX
+ && (GET_MODE_CLASS (mode) == MODE_VECTOR_INT || mode == TImode)
+ /* VMALG/Q become available with z17. */
+ && (GET_MODE_UNIT_SIZE (mode) < 8 || TARGET_VXE3)
+ && GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ *total = vml_vmal_costs;
+ *total += rtx_cost (XEXP (x, 1), mode, PLUS, 1, speed);
+ *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, MULT, 0, speed);
+ *total += rtx_cost (XEXP (XEXP (x, 0), 1), mode, MULT, 1, speed);
+ return true;
+ }
+ *total = COSTS_N_INSNS (1);
+ return false;
+
case MULT:
+ if (TARGET_VX
+ && (GET_MODE_CLASS (mode) == MODE_VECTOR_INT || mode == TImode)
+ /* VMLG/Q become available with z17. */
+ && (GET_MODE_UNIT_SIZE (mode) < 8 || TARGET_VXE3))
+ {
+ /* During expand_mult we may emit a synthetic multiplication
+ depending on the costs. For example, for mode V16QI and
+ multiplicand 123 the sequence VREPI+VML competes with
+ VESL+VS+VESL+VS. The downside of the synthetic multiplication is
+ that on RTL level it is hard to reconstruct the fact that the
+ sequence was a multiplication which may prohibit the combination
+ with a PLUS into a VMAL. */
+ *total = vml_vmal_costs;
+ return false;
+ }
switch (mode)
{
case E_SImode:
@@ -4509,15 +4566,10 @@ legitimate_pic_operand_p (rtx op)
static bool
s390_legitimate_constant_p (machine_mode mode, rtx op)
{
- if (TARGET_VX && GET_CODE (op) == CONST_VECTOR)
- {
- if (!satisfies_constraint_j00 (op)
- && !satisfies_constraint_jm1 (op)
- && !satisfies_constraint_jzz (op)
- && !satisfies_constraint_jxx (op)
- && !satisfies_constraint_jyy (op))
- return 0;
- }
+ if (TARGET_VX
+ && GET_CODE (op) == CONST_VECTOR
+ && !legitimate_reload_vector_constant_p (op))
+ return 0;
if (mode == HFmode)
return satisfies_constraint_j00 (op);
@@ -4700,21 +4752,6 @@ legitimate_reload_fp_constant_p (rtx op)
return false;
}
-/* Returns true if the constant value OP is a legitimate vector operand
- during and after reload.
- This function accepts all constants which can be loaded directly
- into an VR. */
-
-static bool
-legitimate_reload_vector_constant_p (rtx op)
-{
- return TARGET_VX && (satisfies_constraint_j00 (op)
- || satisfies_constraint_jm1 (op)
- || satisfies_constraint_jzz (op)
- || satisfies_constraint_jxx (op)
- || satisfies_constraint_jyy (op));
-}
-
/* Given an rtx OP being reloaded into a reg required to be in class RCLASS,
return the class of reg to actually use. */
diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md
index acca6c4ea34..f3b9636e398 100644
--- a/gcc/config/s390/vector.md
+++ b/gcc/config/s390/vector.md
@@ -67,6 +67,11 @@
; All integer vector modes supported in a vector register + TImode
(define_mode_iterator VIT [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI
V2SI V4SI V1DI V2DI V1TI TI])
(define_mode_iterator VIT_VXE3 [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI
V1SI V2SI V4SI V1DI V2DI (V1TI "TARGET_VXE3") (TI "TARGET_VXE3")])
+(define_mode_iterator VIT_VXE3_DT [V1QI V2QI V4QI V8QI V16QI
+ V1HI V2HI V4HI V8HI
+ V1SI V2SI V4SI
+ (V1DI "TARGET_VXE3") (V2DI "TARGET_VXE3")
+ (V1TI "TARGET_VXE3") (TI "TARGET_VXE3")])
(define_mode_iterator VI [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI
V2SI V4SI V1DI V2DI])
(define_mode_iterator VI_VXE3 [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI
V1SI V2SI V4SI V1DI (V2DI "TARGET_VXE3")])
(define_mode_iterator VI_QHS [V1QI V2QI V4QI V8QI V16QI V1HI V2HI V4HI V8HI
V1SI V2SI V4SI])
@@ -2020,6 +2025,17 @@
operands[5] = s390_expand_merge_perm_const (<vec_double>mode, true);
})
+; vmalb, vmalhw, vmalf, vmalg, vmalq
+(define_insn "*vmal<mode>"
+ [(set (match_operand:VIT_VXE3_DT 0 "register_operand"
"=v")
+ (plus:VIT_VXE3_DT (mult:VIT_VXE3_DT
+ (match_operand:VIT_VXE3_DT 1 "register_operand" "v")
+ (match_operand:VIT_VXE3_DT 2 "general_operand"
"v"))
+ (match_operand:VIT_VXE3_DT 3 "general_operand"
"v")))]
+ "TARGET_VX"
+ "vmal<bhfgq><w>\t%v0,%v1,%v2,%v3"
+ [(set_attr "op_type" "VRR")])
+
; vec_widen_ushiftl_hi
; vec_widen_ushiftl_lo
; vec_widen_sshiftl_hi
diff --git a/gcc/testsuite/gcc.target/s390/vector/vmal-1.c
b/gcc/testsuite/gcc.target/s390/vector/vmal-1.c
new file mode 100644
index 00000000000..a2a25850f49
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/vmal-1.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=z13" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Basic tests for VMAL where all operands are in registers (except for the
+ scalar TI mode test). VMALG/Q become available with TARGET_VXE3/z17. */
+
+typedef signed char v16qi __attribute__ ((vector_size (16)));
+typedef short v8hi __attribute__ ((vector_size (16)));
+typedef int v4si __attribute__ ((vector_size (16)));
+typedef long v2di __attribute__ ((vector_size (16)));
+typedef __int128 v1ti __attribute__ ((vector_size (16)));
+
+/*
+** test_v16qi:
+** vmalb %v24,%v26,%v28,%v24
+** br %r14
+*/
+
+v16qi test_v16qi (v16qi a, v16qi b, v16qi c)
+{
+ return a + b * c;
+}
+
+/*
+** test_v8hi:
+** vmalhw %v24,%v26,%v28,%v24
+** br %r14
+*/
+
+v8hi test_v8hi (v8hi a, v8hi b, v8hi c)
+{
+ return a + b * c;
+}
+
+/*
+** test_v4si:
+** vmalf %v24,%v26,%v28,%v24
+** br %r14
+*/
+
+v4si test_v4si (v4si a, v4si b, v4si c)
+{
+ return a + b * c;
+}
+
+/*
+** test_v2di:
+** vmalg %v24,%v26,%v28,%v24
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+v2di test_v2di (v2di a, v2di b, v2di c)
+{
+ return a + b * c;
+}
+
+/*
+** test_v1ti:
+** vmalq %v24,%v26,%v28,%v24
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+v1ti test_v1ti (v1ti a, v1ti b, v1ti c)
+{
+ return a + b * c;
+}
+
+/*
+** test_ti:
+** vl .*
+** vl .*
+** vl .*
+** vmalq .*
+** vst .*
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+__int128 test_ti (__int128 a, __int128 b, __int128 c)
+{
+ return a + b * c;
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/vmal-2.c
b/gcc/testsuite/gcc.target/s390/vector/vmal-2.c
new file mode 100644
index 00000000000..f84534fd8ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/vmal-2.c
@@ -0,0 +1,181 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=z13" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Tests for VMAL with a constant multiplicand. If the constant is small, then
+ we compete with a synthetic multiplication which in turn means those tests
+ are subject to costing and therefore may be a bit fragile. */
+
+typedef signed char v16qi __attribute__ ((vector_size (16)));
+typedef short v8hi __attribute__ ((vector_size (16)));
+typedef int v4si __attribute__ ((vector_size (16)));
+typedef long v2di __attribute__ ((vector_size (16)));
+typedef unsigned long uv2di __attribute__ ((vector_size (16)));
+typedef __int128 v1ti __attribute__ ((vector_size (16)));
+
+#define CST_VEC (uv2di){0xBADC0FFEE0DDF00D, 0xBADC0FFEE0DDF00D}
+
+/*
+** test_v16qi_plus_vrepi:
+** veslb (%v[0-9]+),%v26,5
+** vsb (%v[0-9]+),\1,%v26
+** veslb (%v[0-9]+),\2,2
+** vsb (%v[0-9]+),\3,%v26
+** vab %v24,\4,%v24
+** br %r14
+*/
+
+v16qi test_v16qi_plus_vrepi (v16qi a, v16qi b)
+{
+ return a + b * 123;
+}
+
+/*
+** test_v16qi_plus_constpool:
+** larl .*
+** vl (%v[0-9]+),.*
+** vmalb %v24,%v26,\1,%v24
+** br %r14
+*/
+
+v16qi test_v16qi_plus_constpool (v16qi a, v16qi b)
+{
+ return a + b * (v16qi)CST_VEC;
+}
+
+/*
+** test_v8hi_plus_vrepi:
+** vrepi (%v[0-9]+),1234,1
+** vmalhw %v24,%v26,\1,%v24
+** br %r14
+*/
+
+v8hi test_v8hi_plus_vrepi (v8hi a, v8hi b)
+{
+ return a + b * 1234;
+}
+
+/*
+** test_v8hi_plus_constpool:
+** larl .*
+** vl (%v[0-9]+),.*
+** vmalhw %v24,%v26,\1,%v24
+** br %r14
+*/
+
+v8hi test_v8hi_plus_constpool (v8hi a, v8hi b)
+{
+ return a + b * (v8hi)CST_VEC;
+}
+
+/*
+** test_v4si_plus_vrepi:
+** vrepi (%v[0-9]+),1234,2
+** vmalf %v24,%v26,\1,%v24
+** br %r14
+*/
+
+v4si test_v4si_plus_vrepi (v4si a, v4si b)
+{
+ return a + b * 1234;
+}
+
+/*
+** test_v4si_plus_constpool:
+** larl .*
+** vl (%v[0-9]+),.*
+** vmalf %v24,%v26,\1,%v24
+** br %r14
+*/
+
+v4si test_v4si_plus_constpool (v4si a, v4si b)
+{
+ return a + b * (v4si)CST_VEC;
+}
+
+/*
+** test_v2di_plus_vrepi:
+** vrepi (%v[0-9]+),1234,3
+** vmalg %v24,%v26,\1,%v24
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+v2di test_v2di_plus_vrepi (v2di a, v2di b)
+{
+ return a + b * 1234;
+}
+
+/*
+** test_v2di_plus_constpool:
+** larl .*
+** vl (%v[0-9]+),.*
+** vmalg %v24,%v26,\1,%v24
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+v2di test_v2di_plus_constpool (v2di a, v2di b)
+{
+ return a + b * (v2di)CST_VEC;
+}
+
+/*
+** test_v1ti_plus_vrepi:
+** vrepi (%v[0-9]+),-86,0
+** vmalq %v24,%v26,\1,%v24
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+v1ti test_v1ti_plus_vrepi (v1ti a, v1ti b)
+{
+ return a + b * ((__int128)0xaaaaaaaaaaaaaaaa << 64 |
(__int128)0xaaaaaaaaaaaaaaaa);
+}
+
+/*
+** test_v1ti_plus_constpool:
+** larl .*
+** vl (%v[0-9]+),.*
+** vmalq %v24,%v26,\1,%v24
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+v1ti test_v1ti_plus_constpool (v1ti a, v1ti b)
+{
+ return a + b * ((__int128)0xBADC0FFEE0DDF00D << 64 |
(__int128)0xBADC0FFEE0DDF00D);
+}
+
+/*
+** test_int128_plus_vrepi:
+** (?:vl|vrepi) .*
+** (?:vl|vrepi) .*
+** (?:vl|vrepi) .*
+** vmalq (%v[0-9]+),.*
+** vst \1,0\(%r2\),3
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+__int128 test_int128_plus_vrepi (__int128 a, __int128 b)
+{
+ return a + b * ((__int128)0xaaaaaaaaaaaaaaaa << 64 |
(__int128)0xaaaaaaaaaaaaaaaa);
+}
+
+/*
+** test_int128_plus_constpool:
+** larl .*
+** vl .*
+** vl .*
+** vl .*
+** vmalq (%v[0-9]+),.*
+** vst \1,0\(%r2\),3
+** br %r14
+*/
+
+__attribute__ ((target ("arch=z17")))
+__int128 test_int128_plus_constpool (__int128 a, __int128 b)
+{
+ return a + b * ((__int128)0xBADC0FFEE0DDF00D << 64 |
(__int128)0xBADC0FFEE0DDF00D);
+}
--
2.55.0