When vectorizing the vectorization loading of the source operand, it was found
that during the processing of the half-region exchange index(such as [4,5,6,7,
0,1,2,3]). there was no direct match. By using the method of xvperm.w +
memory loading index, it can be optimized to xvpermi.d, thereby reducing
the number of instructions.
//test.c
int a[N], b[N], c[N];
void func () {
for (int i = 0; i < N; i += 8) {
c[i+0] = a[i+4]; c[i+1] = a[i+5];
c[i+2] = a[i+6]; c[i+3] = a[i+7];
c[i+4] = a[i+0]; c[i+5] = a[i+1];
c[i+6] = a[i+2]; c[i+7] = a[i+3];
}
}
before asm:
la.local $r15,.LC0 //{4,5,6,7,0,1,2,3}
la.local $r12,a
xvld $xr0,$r15,0
la.local $r13,c
la.local $r14,a+4096
.L2:
xvld $xr1,$r12,0
xvperm.w $xr4,$xr1,$xr0
...
after asm:
la.local $r12,a
la.local $r13,c
la.local $r14,a+4096
.L2:
xvld $xr3,$r12,0
xvpermi.d $xr3,$xr3,78
...
gcc/ChangeLog:
* config/loongarch/loongarch-builtins.cc (CODE_FOR_lsx_vpermi_w):
Add icode support.
* config/loongarch/loongarch.cc (loongarch_is_lasx_dword_perm): New
function.
(loongarch_is_lsx_word_perm): Dito.
(loongarch_expand_vec_perm_const): Impement the half-zone processing
function for a single source operation.
* config/loongarch/lsx.md (lsx_vpermi_w): Add mode support.
(@lsx_vpermi_w<LSX:mode>): Dito.
gcc/testsuite/ChangeLog:
* gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c: New
test.
* gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c: New
test.
* gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c: New
test.
* gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c: New
test.
---
gcc/config/loongarch/loongarch-builtins.cc | 1 +
gcc/config/loongarch/loongarch.cc | 86 ++++++++++++
gcc/config/loongarch/lsx.md | 14 +-
.../vector/lasx/vect-quad-perm-verify-float.c | 35 +++++
.../vector/lasx/vect-quad-perm-verify-int.c | 35 +++++
.../vector/lsx/vect-quad-perm-verify-char.c | 126 ++++++++++++++++++
.../vector/lsx/vect-quad-perm-verify-short.c | 86 ++++++++++++
7 files changed, 376 insertions(+), 7 deletions(-)
create mode 100644
gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
create mode 100644
gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
create mode 100644
gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
create mode 100644
gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c
diff --git a/gcc/config/loongarch/loongarch-builtins.cc
b/gcc/config/loongarch/loongarch-builtins.cc
index 14bd9d24741..a165329c53d 100644
--- a/gcc/config/loongarch/loongarch-builtins.cc
+++ b/gcc/config/loongarch/loongarch-builtins.cc
@@ -380,6 +380,7 @@ AVAIL_ALL (lasx_frecipe, ISA_HAS_LASX && ISA_HAS_FRECIPE)
#define CODE_FOR_lsx_vpcnt_h CODE_FOR_popcountv8hi2
#define CODE_FOR_lsx_vpcnt_w CODE_FOR_popcountv4si2
#define CODE_FOR_lsx_vpcnt_d CODE_FOR_popcountv2di2
+#define CODE_FOR_lsx_vpermi_w CODE_FOR_lsx_vpermi_wv4si
#define CODE_FOR_lsx_vxor_v CODE_FOR_xorv16qi3
#define CODE_FOR_lsx_vxori_b CODE_FOR_xorv16qi3
#define CODE_FOR_lsx_vsll_b CODE_FOR_vashlv16qi3
diff --git a/gcc/config/loongarch/loongarch.cc
b/gcc/config/loongarch/loongarch.cc
index 3001d552574..3b3cb9aa243 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -9671,6 +9671,86 @@ loongarch_is_elem_duplicate (struct expand_vec_perm_d *d)
c) Use other instructions to process op and put correct result into target.
*/
+/* Check if a constant LASX permutation can be implemented as a single
+ xvpermi.d instruction. This handles cases where all elements of each
+ result 64-bit dword come from the same source dword in the same order,
+ i.e., the permutation can be expressed as a dword-level shuffle.
+ Returns true if the pattern matches and emits the instruction. */
+
+static bool
+loongarch_is_lasx_dword_perm (struct expand_vec_perm_d *d)
+{
+ if (!ISA_HAS_LASX)
+ return false;
+ if (GET_MODE_SIZE (d->vmode) != 32 || !d->one_vector_p)
+ return false;
+
+ unsigned int nelt = d->nelt;
+ unsigned int nelts_per_dw = nelt / 4;
+
+ for (unsigned int dw = 0; dw < 4; dw++)
+ {
+ unsigned int base = dw * nelts_per_dw;
+ unsigned int sdw = d->perm[base] / nelts_per_dw;
+ for (unsigned int k = 0; k < nelts_per_dw; k++)
+ if (d->perm[base + k] != sdw * nelts_per_dw + k)
+ return false;
+ }
+
+ if (d->testing_p)
+ return true;
+
+ unsigned int imm = 0;
+ for (unsigned int dw = 0; dw < 4; dw++)
+ {
+ unsigned int base = dw * nelts_per_dw;
+ unsigned int sdw = d->perm[base] / nelts_per_dw;
+ imm |= sdw << (dw * 2);
+ }
+
+ emit_insn (gen_lasx_xvpermi_d (d->vmode, d->target, d->op0, GEN_INT (imm)));
+ return true;
+}
+
+static bool
+loongarch_is_lsx_word_perm (struct expand_vec_perm_d *d)
+{
+ if (!ISA_HAS_LSX)
+ return false;
+ if (GET_MODE_SIZE (d->vmode) != 16 || !d->one_vector_p)
+ return false;
+
+ unsigned int nelt = d->nelt;
+ unsigned int nelts_per_dw = nelt / 4;
+
+ if (nelts_per_dw == 0 || nelts_per_dw == 1)
+ return false;
+
+ for (unsigned int dw = 0; dw < 4; dw++)
+ {
+ unsigned int base = dw * nelts_per_dw;
+ unsigned int sdw = d->perm[base] / nelts_per_dw;
+ for (unsigned int k = 0; k < nelts_per_dw; k++)
+ if (d->perm[base + k] != sdw * nelts_per_dw + k)
+ return false;
+ }
+
+ if (d->testing_p)
+ return true;
+
+ unsigned int imm = 0;
+ for (unsigned int dw = 0; dw < 4; dw++)
+ {
+ unsigned int base = dw * nelts_per_dw;
+ unsigned int sdw = d->perm[base] / nelts_per_dw;
+ imm |= sdw << (dw * 2);
+ }
+
+ emit_insn (gen_lsx_vpermi_w (d->vmode, d->target, d->op0,
+ d->op0, GEN_INT (imm)));
+ return true;
+}
+
/* Implementation of constant vector permutation. This function identifies
recognized pattern of permutation selector argument, and use one or more
instruction (s) to finish the permutation job correctly. For unsupported
@@ -9714,6 +9794,9 @@ loongarch_expand_vec_perm_const (struct expand_vec_perm_d
*d)
return true;
}
+ if (loongarch_is_lsx_word_perm (d))
+ return true;
+
if (GET_MODE_SIZE (d->vmode) == 16)
return loongarch_expand_lsx_shuffle (d);
@@ -9782,6 +9865,9 @@ loongarch_expand_vec_perm_const (struct expand_vec_perm_d
*d)
goto expand_perm_const_end;
}
+ if (loongarch_is_lasx_dword_perm (d))
+ return true;
+
if (loongarch_is_elem_duplicate (d))
{
if (d->testing_p)
diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md
index 53eba3ffe6b..d1280ccd415 100644
--- a/gcc/config/loongarch/lsx.md
+++ b/gcc/config/loongarch/lsx.md
@@ -3180,16 +3180,16 @@ (define_insn "lsx_vssrarni_<lsxfmt_u>_<dlsxfmt>"
[(set_attr "type" "simd_shift")
(set_attr "mode" "<MODE>")])
-(define_insn "lsx_vpermi_w"
- [(set (match_operand:V4SI 0 "register_operand" "=f")
- (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "0")
- (match_operand:V4SI 2 "register_operand" "f")
- (match_operand 3 "const_uimm8_operand" "")]
- UNSPEC_LSX_VPERMI))]
+(define_insn "@lsx_vpermi_w<LSX:mode>"
+ [(set (match_operand:LSX 0 "register_operand" "=f")
+ (unspec:LSX[(match_operand:LSX 1 "register_operand" "0")
+ (match_operand:LSX 2 "register_operand" "f")
+ (match_operand 3 "const_uimm8_operand" "")]
+ UNSPEC_LSX_VPERMI))]
"ISA_HAS_LSX"
"vpermi.w\t%w0,%w2,%3"
[(set_attr "type" "simd_bit")
- (set_attr "mode" "V4SI")])
+ (set_attr "mode" "<MODE>")])
;; Delete one of two instructions that exactly play the same role.
(define_peephole2
diff --git
a/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
new file mode 100644
index 00000000000..7c901f3ffce
--- /dev/null
+++
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
@@ -0,0 +1,35 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlasx " } */
+/* { dg-final { scan-assembler-times "xvpermi.d" 12 } } */
+
+#define N 1024
+float a[N], b[N], c[N];
+
+void test_swap_halves() {
+ for (int i = 0; i < N; i += 8) {
+ c[i+0] = a[i+4]; c[i+1] = a[i+5];
+ c[i+2] = a[i+6]; c[i+3] = a[i+7];
+ c[i+4] = a[i+0]; c[i+5] = a[i+1];
+ c[i+6] = a[i+2]; c[i+7] = a[i+3];
+ }
+}
+
+void test_broadcast_low() {
+ for (int i = 0; i < N; i += 8) {
+ c[i+0] = a[i+0]; c[i+1] = a[i+1];
+ c[i+2] = a[i+2]; c[i+3] = a[i+3];
+ c[i+4] = a[i+0]; c[i+5] = a[i+1];
+ c[i+6] = a[i+2]; c[i+7] = a[i+3];
+ }
+}
+
+/* { dg-final { scan-assembler-times
"test_broadcast_high:.*\txvpermi\\.q.*test_broadcast_high" 1 } } */
+void test_broadcast_high() {
+ for (int i = 0; i < N; i += 8) {
+ c[i+0] = a[i+4]; c[i+1] = a[i+5];
+ c[i+2] = a[i+6]; c[i+3] = a[i+7];
+ c[i+4] = a[i+4]; c[i+5] = a[i+5];
+ c[i+6] = a[i+6]; c[i+7] = a[i+7];
+ }
+}
+
diff --git
a/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
new file mode 100644
index 00000000000..968bb67aedc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
@@ -0,0 +1,35 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlasx " } */
+/* { dg-final { scan-assembler-times "xvpermi.d" 12 } } */
+
+#define N 1024
+int a[N], b[N], c[N];
+
+void test_swap_halves() {
+ for (int i = 0; i < N; i += 8) {
+ c[i+0] = a[i+4]; c[i+1] = a[i+5];
+ c[i+2] = a[i+6]; c[i+3] = a[i+7];
+ c[i+4] = a[i+0]; c[i+5] = a[i+1];
+ c[i+6] = a[i+2]; c[i+7] = a[i+3];
+ }
+}
+
+void test_broadcast_low() {
+ for (int i = 0; i < N; i += 8) {
+ c[i+0] = a[i+0]; c[i+1] = a[i+1];
+ c[i+2] = a[i+2]; c[i+3] = a[i+3];
+ c[i+4] = a[i+0]; c[i+5] = a[i+1];
+ c[i+6] = a[i+2]; c[i+7] = a[i+3];
+ }
+}
+
+/* { dg-final { scan-assembler-times
"test_broadcast_high:.*\txvpermi\\.q.*test_broadcast_high" 1 } } */
+void test_broadcast_high() {
+ for (int i = 0; i < N; i += 8) {
+ c[i+0] = a[i+4]; c[i+1] = a[i+5];
+ c[i+2] = a[i+6]; c[i+3] = a[i+7];
+ c[i+4] = a[i+4]; c[i+5] = a[i+5];
+ c[i+6] = a[i+6]; c[i+7] = a[i+7];
+ }
+}
+
diff --git
a/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
new file mode 100644
index 00000000000..eb6e6681cbf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
@@ -0,0 +1,126 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlsx " } */
+/* { dg-final { scan-assembler-times "vpermi.w" 15 } } */
+
+#define N 1024
+char a[N], b[N], c[N];
+
+void
+test_swap_halves ()
+{
+ for (int i = 0; i < N; i += 16)
+ {
+ c[i + 0] = a[i + 8];
+ c[i + 1] = a[i + 9];
+ c[i + 2] = a[i + 10];
+ c[i + 3] = a[i + 11];
+ c[i + 4] = a[i + 12];
+ c[i + 5] = a[i + 13];
+ c[i + 6] = a[i + 14];
+ c[i + 7] = a[i + 15];
+ c[i + 8] = a[i + 0];
+ c[i + 9] = a[i + 1];
+ c[i + 10] = a[i + 2];
+ c[i + 11] = a[i + 3];
+ c[i + 12] = a[i + 4];
+ c[i + 13] = a[i + 5];
+ c[i + 14] = a[i + 6];
+ c[i + 15] = a[i + 7];
+ }
+}
+
+void
+test_broadcast_low ()
+{
+ for (int i = 0; i < N; i += 16)
+ {
+ c[i + 0] = a[i + 0];
+ c[i + 1] = a[i + 1];
+ c[i + 2] = a[i + 2];
+ c[i + 3] = a[i + 3];
+ c[i + 4] = a[i + 4];
+ c[i + 5] = a[i + 5];
+ c[i + 6] = a[i + 6];
+ c[i + 7] = a[i + 7];
+ c[i + 8] = a[i + 0];
+ c[i + 9] = a[i + 1];
+ c[i + 10] = a[i + 2];
+ c[i + 11] = a[i + 3];
+ c[i + 12] = a[i + 4];
+ c[i + 13] = a[i + 5];
+ c[i + 14] = a[i + 6];
+ c[i + 15] = a[i + 7];
+ }
+}
+
+void
+test_broadcast_high ()
+{
+ for (int i = 0; i < N; i += 16)
+ {
+ c[i + 0] = a[i + 8];
+ c[i + 1] = a[i + 9];
+ c[i + 2] = a[i + 10];
+ c[i + 3] = a[i + 11];
+ c[i + 4] = a[i + 12];
+ c[i + 5] = a[i + 13];
+ c[i + 6] = a[i + 14];
+ c[i + 7] = a[i + 15];
+ c[i + 8] = a[i + 8];
+ c[i + 9] = a[i + 9];
+ c[i + 10] = a[i + 10];
+ c[i + 11] = a[i + 11];
+ c[i + 12] = a[i + 12];
+ c[i + 13] = a[i + 13];
+ c[i + 14] = a[i + 14];
+ c[i + 15] = a[i + 15];
+ }
+}
+
+void
+test_reverse_words ()
+{
+ for (int i = 0; i < N; i += 16)
+ {
+ c[i + 0] = a[i + 7];
+ c[i + 1] = a[i + 6];
+ c[i + 2] = a[i + 5];
+ c[i + 3] = a[i + 4];
+ c[i + 4] = a[i + 3];
+ c[i + 5] = a[i + 2];
+ c[i + 6] = a[i + 1];
+ c[i + 7] = a[i + 0];
+ c[i + 8] = a[i + 15];
+ c[i + 9] = a[i + 14];
+ c[i + 10] = a[i + 13];
+ c[i + 11] = a[i + 12];
+ c[i + 12] = a[i + 11];
+ c[i + 13] = a[i + 10];
+ c[i + 14] = a[i + 9];
+ c[i + 15] = a[i + 8];
+ }
+}
+
+void
+test_reverse_words1 ()
+{
+ for (int i = 0; i < N; i += 16)
+ {
+ c[i + 0] = a[i + 8];
+ c[i + 1] = a[i + 9];
+ c[i + 2] = a[i + 10];
+ c[i + 3] = a[i + 11];
+ c[i + 4] = a[i + 0];
+ c[i + 5] = a[i + 1];
+ c[i + 6] = a[i + 2];
+ c[i + 7] = a[i + 3];
+ c[i + 8] = a[i + 12];
+ c[i + 9] = a[i + 13];
+ c[i + 10] = a[i + 14];
+ c[i + 11] = a[i + 15];
+ c[i + 12] = a[i + 4];
+ c[i + 13] = a[i + 5];
+ c[i + 14] = a[i + 6];
+ c[i + 15] = a[i + 7];
+ }
+}
diff --git
a/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c
new file mode 100644
index 00000000000..a9ab014339e
--- /dev/null
+++
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c
@@ -0,0 +1,86 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlsx " } */
+/* { dg-final { scan-assembler-times "vpermi.w" 15 } } */
+
+#define N 1024
+short a[N], b[N], c[N];
+
+void
+test_swap_halves ()
+{
+ for (int i = 0; i < N; i += 8)
+ {
+ c[i + 0] = a[i + 4];
+ c[i + 1] = a[i + 5];
+ c[i + 2] = a[i + 6];
+ c[i + 3] = a[i + 7];
+ c[i + 4] = a[i + 0];
+ c[i + 5] = a[i + 1];
+ c[i + 6] = a[i + 2];
+ c[i + 7] = a[i + 3];
+ }
+}
+
+void
+test_broadcast_low ()
+{
+ for (int i = 0; i < N; i += 8)
+ {
+ c[i + 0] = a[i + 0];
+ c[i + 1] = a[i + 1];
+ c[i + 2] = a[i + 2];
+ c[i + 3] = a[i + 3];
+ c[i + 4] = a[i + 0];
+ c[i + 5] = a[i + 1];
+ c[i + 6] = a[i + 2];
+ c[i + 7] = a[i + 3];
+ }
+}
+
+void
+test_broadcast_high ()
+{
+ for (int i = 0; i < N; i += 8)
+ {
+ c[i + 0] = a[i + 4];
+ c[i + 1] = a[i + 5];
+ c[i + 2] = a[i + 6];
+ c[i + 3] = a[i + 7];
+ c[i + 4] = a[i + 4];
+ c[i + 5] = a[i + 5];
+ c[i + 6] = a[i + 6];
+ c[i + 7] = a[i + 7];
+ }
+}
+
+void
+test_reverse_words ()
+{
+ for (int i = 0; i < N; i += 8)
+ {
+ c[i + 0] = a[i + 3];
+ c[i + 1] = a[i + 2];
+ c[i + 2] = a[i + 1];
+ c[i + 3] = a[i + 0];
+ c[i + 4] = a[i + 7];
+ c[i + 5] = a[i + 6];
+ c[i + 6] = a[i + 5];
+ c[i + 7] = a[i + 4];
+ }
+}
+
+void
+test_reverse_words1 ()
+{
+ for (int i = 0; i < N; i += 8)
+ {
+ c[i + 0] = a[i + 0];
+ c[i + 1] = a[i + 1];
+ c[i + 2] = a[i + 4];
+ c[i + 3] = a[i + 5];
+ c[i + 4] = a[i + 2];
+ c[i + 5] = a[i + 3];
+ c[i + 6] = a[i + 6];
+ c[i + 7] = a[i + 7];
+ }
+}
--
2.20.1