From: Richard Earnshaw <[email protected]>
Generalize the SVE vector extraction patterns to handle partial vectors
as well as full vectors. This allows us to handle extractions that
are now exposed by optimizing vec_select to dup operations.
gcc/ChangeLog:
* config/aarch64/aarch64-sve.md (@aarch64_vec_duplicate_vq<mode>_be):
Iterate over SVE_ALL.
(vec_extract<mode><Vel>): Likewise.
(vec_extract<mode><v64>): Likewise.
(@aarch64_sve_dupq_lane<mode>): Likewise.
(@aarch64_sve_get_neonq_<mode>): Likewise.
(*vec_extract<mode><Vel>_v128): Likewise. Adjust calculations for
partial vectors.
(*vec_extract<mode><Vel>_dup): Likewise.
(*vec_extract<mode><Vel>_ext): Likewise.
* config/aarch64/iterators.md (elem_bits): Add partial vector modes.
(VEL_INT): Likewise.
(V128): Likewise.
(V_INT_EQUIV): Likewise.
(v_int_equiv): Likewise.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sve/vec_lane_1.c: New test.
---
gcc/config/aarch64/aarch64-sve.md | 34 +++---
gcc/config/aarch64/iterators.md | 58 +++++++++-
.../gcc.target/aarch64/sve/vec_lane_1.c | 103 ++++++++++++++++++
3 files changed, 176 insertions(+), 19 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vec_lane_1.c
diff --git a/gcc/config/aarch64/aarch64-sve.md
b/gcc/config/aarch64/aarch64-sve.md
index d0b3612f340a9..30fcc9d1a00d5 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -2880,8 +2880,8 @@
;; lsb into the register lsb. We therefore have to describe this in rtl
;; terms as a reverse of the V128 vector followed by a duplicate.
(define_insn "@aarch64_vec_duplicate_vq<mode>_be"
- [(set (match_operand:SVE_FULL 0 "register_operand" "=w")
- (vec_duplicate:SVE_FULL
+ [(set (match_operand:SVE_ALL 0 "register_operand" "=w")
+ (vec_duplicate:SVE_ALL
(vec_select:<V128>
(match_operand:<V128> 1 "register_operand" "w")
(match_operand 2 "descending_int_parallel"))))]
@@ -3142,7 +3142,7 @@
(define_expand "vec_extract<mode><Vel>"
[(set (match_operand:<VEL> 0 "register_operand")
(vec_select:<VEL>
- (match_operand:SVE_FULL 1 "register_operand")
+ (match_operand:SVE_ALL 1 "register_operand")
(parallel [(match_operand:SI 2 "nonmemory_operand")])))]
"TARGET_SVE"
{
@@ -3229,7 +3229,7 @@
(define_insn_and_split "*vec_extract<mode><Vel>_0"
[(set (match_operand:<VEL> 0 "aarch64_simd_nonimmediate_operand" "=r, w,
Utv")
(vec_select:<VEL>
- (match_operand:SVE_FULL 1 "register_operand" "w, 0, w")
+ (match_operand:SVE_ALL 1 "register_operand" "w, 0, w")
(parallel [(const_int 0)])))]
"TARGET_SVE"
{
@@ -3263,12 +3263,14 @@
(define_insn "*vec_extract<mode><Vel>_v128"
[(set (match_operand:<VEL> 0 "aarch64_simd_nonimmediate_operand" "=r, w,
Utv")
(vec_select:<VEL>
- (match_operand:SVE_FULL 1 "register_operand" "w, w, w")
+ (match_operand:SVE_ALL 1 "register_operand" "w, w, w")
(parallel [(match_operand:SI 2 "const_int_operand")])))]
"TARGET_SVE
- && IN_RANGE (INTVAL (operands[2]) * GET_MODE_SIZE (<VEL>mode), 1, 15)"
+ && IN_RANGE (INTVAL (operands[2]) * <container_bits> / 8, 1, 15)"
{
operands[1] = gen_rtx_REG (<V128>mode, REGNO (operands[1]));
+ operands[2] = GEN_INT (INTVAL (operands[2])
+ * <container_bits> / <elem_bits>);
switch (which_alternative)
{
case 0:
@@ -3289,12 +3291,14 @@
(define_insn "*vec_extract<mode><Vel>_dup"
[(set (match_operand:<VEL> 0 "register_operand" "=w")
(vec_select:<VEL>
- (match_operand:SVE_FULL 1 "register_operand" "w")
+ (match_operand:SVE_ALL 1 "register_operand" "w")
(parallel [(match_operand:SI 2 "const_int_operand")])))]
"TARGET_SVE
- && IN_RANGE (INTVAL (operands[2]) * GET_MODE_SIZE (<VEL>mode), 16, 63)"
+ && IN_RANGE (INTVAL (operands[2]) * <container_bits> / 8, 16, 63)"
{
operands[0] = gen_rtx_REG (<MODE>mode, REGNO (operands[0]));
+ operands[2] = GEN_INT (INTVAL (operands[2])
+ * <container_bits> / <elem_bits>);
return "dup\t%0.<Vetype>, %1.<Vetype>[%2]";
}
[(set_attr "sve_type" "sve_int_general")]
@@ -3305,12 +3309,12 @@
(define_insn "*vec_extract<mode><Vel>_ext"
[(set (match_operand:<VEL> 0 "register_operand" "=w, ?&w")
(vec_select:<VEL>
- (match_operand:SVE_FULL 1 "register_operand" "0, w")
+ (match_operand:SVE_ALL 1 "register_operand" "0, w")
(parallel [(match_operand:SI 2 "const_int_operand")])))]
- "TARGET_SVE && INTVAL (operands[2]) * GET_MODE_SIZE (<VEL>mode) >= 64"
+ "TARGET_SVE && INTVAL (operands[2]) * <container_bits> / 8 >= 64"
{
operands[0] = gen_rtx_REG (<MODE>mode, REGNO (operands[0]));
- operands[2] = GEN_INT (INTVAL (operands[2]) * GET_MODE_SIZE (<VEL>mode));
+ operands[2] = GEN_INT (INTVAL (operands[2]) * <container_bits> / 8);
return (which_alternative == 0
? "ext\t%0.b, %0.b, %0.b, #%2"
: "movprfx\t%0, %1\;ext\t%0.b, %0.b, %1.b, #%2");
@@ -10415,10 +10419,10 @@
;; for big-endian targets. In this fused pattern the two reverses cancel
;; each other out.
(define_insn "@aarch64_sve_dupq_lane<mode>"
- [(set (match_operand:SVE_FULL 0 "register_operand" "=w")
- (vec_duplicate:SVE_FULL
+ [(set (match_operand:SVE_ALL 0 "register_operand" "=w")
+ (vec_duplicate:SVE_ALL
(vec_select:<V128>
- (match_operand:SVE_FULL 1 "register_operand" "w")
+ (match_operand:SVE_ALL 1 "register_operand" "w")
(match_operand 2 "ascending_int_parallel"))))]
"TARGET_SVE
&& (INTVAL (XVECEXP (operands[2], 0, 0))
@@ -12898,7 +12902,7 @@
(define_insn_and_split "@aarch64_sve_get_neonq_<mode>"
[(set (match_operand:<V128> 0 "register_operand" "=w")
(vec_select:<V128>
- (match_operand:SVE_FULL 1 "register_operand" "w")
+ (match_operand:SVE_ALL 1 "register_operand" "w")
(match_operand 2 "descending_int_parallel")))]
"TARGET_SVE
&& BYTES_BIG_ENDIAN
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index f69bf88a47d47..600521a2991ab 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -1659,7 +1659,13 @@
(VNx4SF "32") (VNx8SF "32") (VNx16SF "32")
(VNx2DI "64") (VNx4DI "64") (VNx8DI "64")
(VNx2DF "64") (VNx4DF "64") (VNx8DF "64")
- (VNx1TI "128")])
+ (VNx1TI "128")
+ (VNx8QI "8") (VNx4QI "8") (VNx2QI "8")
+ (VNx4HI "16") (VNx2HI "16")
+ (VNx4HF "16") (VNx2HF "16")
+ (VNx4BF "16") (VNx2BF "16")
+ (VNx2SI "32") (VNx2SF "32")
+])
;; The number of bits in a vector container.
(define_mode_attr container_bits [(VNx16QI "8")
@@ -2031,19 +2037,42 @@
(define_mode_attr VEL_INT [(VNx16QI "QI")
(VNx8HI "HI") (VNx8HF "HI") (VNx8BF "HI")
(VNx4SI "SI") (VNx4SF "SI")
- (VNx2DI "DI") (VNx2DF "DI")])
+ (VNx2DI "DI") (VNx2DF "DI")
+ (VNx8QI "QI")
+ (VNx4HI "HI") (VNx4HF "HI") (VNx4BF "HI")
+ (VNx2SI "SI") (VNx2SF "SI")
+ (VNx1DI "DI")
+ (VNx4QI "QI")
+ (VNx2HI "HI")
+ (VNx2HF "HI") (VNx2BF "HI")
+ (VNx2QI "QI")
+ ])
;; Gives the mode of the 128-bit lowpart of an SVE vector.
(define_mode_attr V128 [(VNx16QI "V16QI")
(VNx8HI "V8HI") (VNx8HF "V8HF") (VNx8BF "V8BF")
(VNx4SI "V4SI") (VNx4SF "V4SF")
- (VNx2DI "V2DI") (VNx2DF "V2DF")])
+ (VNx2DI "V2DI") (VNx2DF "V2DF")
+ (VNx8QI "V16QI")
+ (VNx4HI "V8HI") (VNx4HF "V8HF") (VNx4BF "V8BF")
+ (VNx2SI "V4SI") (VNx2SF "V4SF")
+ (VNx1DI "V2DI")
+ (VNx4QI "V16QI") (VNx2QI "V16QI")
+ (VNx2HI "V8HI") (VNx2HF "V8HF") (VNx2BF "V8BF")
+])
;; ...and again in lower case.
(define_mode_attr v128 [(VNx16QI "v16qi")
(VNx8HI "v8hi") (VNx8HF "v8hf") (VNx8BF "v8bf")
(VNx4SI "v4si") (VNx4SF "v4sf")
- (VNx2DI "v2di") (VNx2DF "v2df")])
+ (VNx2DI "v2di") (VNx2DF "v2df")
+ (VNx8QI "v16qi")
+ (VNx4HI "v8hi") (VNx4HF "v8hf") (VNx4BF "v8bf")
+ (VNx2SI "v4si") (VNx2SF "v4sf")
+ (VNx1DI "v2di")
+ (VNx4QI "v16qi") (VNx2QI "v16qi")
+ (VNx2HI "v8hi") (VNx2HF "v8hf") (VNx2BF "v8bf")
+])
;; Gives the mode of the 64-bit lowpart of an SVE vector.
(define_mode_attr V64 [(VNx16QI "V8QI")
@@ -2542,6 +2571,15 @@
(VNx4SI "VNx4SI") (VNx4SF "VNx4SI")
(VNx2DI "VNx2DI") (VNx2DF "VNx2DI")
(VNx8SF "VNx8SI") (VNx16SF "VNx16SI")
+ (VNx8QI "VNx8QI")
+ (VNx4HI "VNx4HI") (VNx4HF "VNx4HI")
+ (VNx4BF "VNx4HI")
+ (VNx2SI "VNx2SI") (VNx2SF "VNx2SI")
+ (VNx1DI "VNx1DI")
+ (VNx4QI "VNx4QI")
+ (VNx2HI "VNx2HI") (VNx2HF "VNx2HI")
+ (VNx2BF "VNx2HI")
+ (VNx2QI "VNx2QI")
])
;; Lower case mode with floating-point values replaced by like-sized integers.
@@ -2554,12 +2592,24 @@
(V2SF "v2si") (V4SF "v4si")
(DF "di") (V2DF "v2di")
(SF "si")
+ (HF "hi") (BF "hi")
(VNx16QI "vnx16qi")
(VNx8HI "vnx8hi") (VNx8HF "vnx8hi")
(VNx8BF "vnx8hi")
+ (VNx16BF "vnx16hi")
+ (VNx32BF "vnx32hi")
(VNx4SI "vnx4si") (VNx4SF "vnx4si")
(VNx2DI "vnx2di") (VNx2DF "vnx2di")
(VNx8SF "vnx8si") (VNx16SF "vnx16si")
+ (VNx8QI "vnx8qi")
+ (VNx4HI "vnx4hi") (VNx4HF "vnx4hi")
+ (VNx4BF "vnx4hi")
+ (VNx2SI "vnx2si") (VNx2SF "vnx2si")
+ (VNx1DI "vnx1di")
+ (VNx4QI "vnx4qi")
+ (VNx2HI "vnx2hi") (VNx2HF "vnx2hi")
+ (VNx2BF "vnx2hi")
+ (VNx2QI "vnx2qi")
])
;; Mode with floating-point values replaced by 128-bit vector integers.
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vec_lane_1.c
b/gcc/testsuite/gcc.target/aarch64/sve/vec_lane_1.c
new file mode 100644
index 0000000000000..c90bd1d725783
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/vec_lane_1.c
@@ -0,0 +1,103 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv8.2-a+sve -fdump-rtl-expand -Wno-attributes" }
*/
+/* { dg-final { check-function-bodies "**" "" } } */
+
+typedef unsigned char partial_qi __attribute__((mode(VNx8QI)));
+typedef float partial_sf __attribute__((mode(VNx2SF)));
+
+__attribute__((noipa))
+unsigned char
+extract_0_qi (partial_qi *v)
+{
+ partial_qi x = *v;
+ asm ("": "+w"(x): : "memory");
+ return (x)[0];
+}
+/*
+** extract_0_qi:
+** ptrue (p[0-9]+)\.b, all
+** ld1b z([0-9]+)\.h, \1/z, \[x0\]
+** umov w0, v\2.b\[0\]
+** ret
+*/
+
+__attribute__((noipa))
+unsigned char
+extract_1_qi (partial_qi *v)
+{
+ partial_qi x = *v;
+ asm ("": "+w"(x): : "memory");
+ return (x)[1];
+}
+/*
+** extract_1_qi:
+** ptrue (p[0-9]+)\.b, all
+** ld1b z([0-9]+)\.h, \1/z, \[x0\]
+** umov w0, v\2.b\[2\]
+** ret
+*/
+
+__attribute__((noipa))
+unsigned char
+extract_3_qi (partial_qi *v)
+{
+ partial_qi x = *v;
+ asm ("": : "w"(x) : "memory");
+ return (x)[3];
+}
+/*
+** extract_3_qi:
+** ptrue (p[0-9]+)\.b, all
+** ld1b z([0-9]+)\.h, \1/z, \[x0\]
+** umov w0, v\2.b\[6\]
+** ret
+*/
+
+__attribute__((noipa))
+unsigned char
+extract_7_qi (partial_qi *v)
+{
+ partial_qi x = *v;
+ asm ("": : "w"(x) : "memory");
+ return (x)[7];
+}
+/*
+** extract_7_qi:
+** ptrue (p[0-9]+)\.b, all
+** ld1b z([0-9]+)\.h, \1/z, \[x0\]
+** umov w0, v\2.b\[14\]
+** ret
+*/
+
+__attribute__((noipa))
+unsigned char
+extract_8_qi (partial_qi *v)
+{
+ partial_qi x = *v;
+ asm ("": : "w"(x) : "memory");
+ return (x)[8];
+}
+/*
+** extract_8_qi: { xfail *-*-* }
+** ptrue (p[0-9]+)\.b, all
+** ld1b (z[0-9]+)\.h, \1/z, \[x0\]
+** dup z([0-9]+)\.b, \2.b\[16\]
+** umov w0, v\3\.b\[0\]
+** ret
+*/
+
+__attribute__((noipa))
+float
+extract_1_sf (partial_sf *v)
+{
+ partial_sf x = *v;
+ asm ("": : "w"(x) : "memory");
+ return (x)[1];
+}
+/*
+** extract_1_sf:
+** ptrue (p[0-9]+)\.b, all
+** ld1w z([0-9]+)\.d, \1/z, \[x0\]
+** dup s0, v\2.s\[2\]
+** ret
+*/
--
2.56.0