]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386: Use PUNPCKL?? to implement vector extend and zero_extend for TARGET_SSE2.
authorUros Bizjak <ubizjak@gmail.com>
Fri, 18 Aug 2023 17:06:38 +0000 (19:06 +0200)
committerUros Bizjak <ubizjak@gmail.com>
Fri, 18 Aug 2023 17:08:23 +0000 (19:08 +0200)
Implement vector extend and zero_extend functionality for TARGET_SSE2 using
PUNPCKL?? family of instructions. The code for e.g. zero-extend from V2SI to
V2DImode improves from:

        movd    %xmm0, %edx
        pshufd  $85, %xmm0, %xmm0
        movd    %xmm0, %eax
        movq    %rdx, (%rdi)
        movq    %rax, 8(%rdi)

to:
        pxor    %xmm1, %xmm1
        punpckldq       %xmm1, %xmm0
        movaps  %xmm0, (%rdi)

And the code for sign-extend from V2SI to V2DImode from:

        movd    %xmm0, %edx
        pshufd  $85, %xmm0, %xmm0
        movd    %xmm0, %eax
        movslq  %edx, %rdx
        cltq
        movq    %rdx, (%rdi)
        movq    %rax, 8(%rdi)

to:
        pxor    %xmm1, %xmm1
        pcmpgtd %xmm0, %xmm1
        punpckldq       %xmm1, %xmm0
        movaps  %xmm0, (%rdi)

PR target/111023

gcc/ChangeLog:

* config/i386/i386-expand.cc (ix86_split_mmx_punpck):
Also handle V2QImode.
(ix86_expand_sse_extend): New function.
* config/i386/i386-protos.h (ix86_expand_sse_extend): New prototype.
* config/i386/mmx.md (<any_extend:insn>v4qiv4hi2): Enable for
TARGET_SSE2.  Expand through ix86_expand_sse_extend for !TARGET_SSE4_1.
(<any_extend:insn>v2hiv2si2): Ditto.
(<any_extend:insn>v2qiv2hi2): Ditto.
* config/i386/sse.md (<any_extend:insn>v8qiv8hi2): Ditto.
(<any_extend:insn>v4hiv4si2): Ditto.
(<any_extend:insn>v2siv2di2): Ditto.

gcc/testsuite/ChangeLog:

* gcc.target/i386/pr111023-2.c: New test.
* gcc.target/i386/pr111023-4b.c: New test.
* gcc.target/i386/pr111023-8b.c: New test.
* gcc.target/i386/pr111023.c: New test.

gcc/config/i386/i386-expand.cc
gcc/config/i386/i386-protos.h
gcc/config/i386/mmx.md
gcc/config/i386/sse.md
gcc/testsuite/gcc.target/i386/pr111023-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr111023-4b.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr111023-8b.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr111023.c [new file with mode: 0644]

index 85e30552d6fabba26afa30eac539f5a89f4b720b..460d496ef226c059aadcc6c40266f53409db6f15 100644 (file)
@@ -1124,8 +1124,9 @@ ix86_split_mmx_punpck (rtx operands[], bool high_p)
 
   switch (mode)
     {
-    case E_V4QImode:
     case E_V8QImode:
+    case E_V4QImode:
+    case E_V2QImode:
       sse_mode = V16QImode;
       double_sse_mode = V32QImode;
       mask = gen_rtx_PARALLEL (VOIDmode,
@@ -5636,7 +5637,43 @@ ix86_expand_vec_perm (rtx operands[])
     }
 }
 
-/* Unpack OP[1] into the next wider integer vector type.  UNSIGNED_P is
+/* Extend SRC into next wider integer vector type.  UNSIGNED_P is
+   true if we should do zero extension, else sign extension.  */
+
+void
+ix86_expand_sse_extend (rtx dest, rtx src, bool unsigned_p)
+{
+  machine_mode imode = GET_MODE (src);
+  rtx ops[3];
+
+  switch (imode)
+    {
+    case E_V8QImode:
+    case E_V4QImode:
+    case E_V2QImode:
+    case E_V4HImode:
+    case E_V2HImode:
+    case E_V2SImode:
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  ops[0] = gen_reg_rtx (imode);
+
+  ops[1] = force_reg (imode, src);
+
+  if (unsigned_p)
+    ops[2] = force_reg (imode, CONST0_RTX (imode));
+  else
+    ops[2] = ix86_expand_sse_cmp (gen_reg_rtx (imode), GT, CONST0_RTX (imode),
+                                 src, pc_rtx, pc_rtx);
+
+  ix86_split_mmx_punpck (ops, false);
+  emit_move_insn (dest, lowpart_subreg (GET_MODE (dest), ops[0], imode));
+}
+
+/* Unpack SRC into the next wider integer vector type.  UNSIGNED_P is
    true if we should do zero extension, else sign extension.  HIGH_P is
    true if we want the N/2 high elements, else the low elements.  */
 
index fc2f1f13b78fd98709514d62ee3b9a3449e8f65c..9ffb125fc2b18a5b7ff06fc0ab76a3a7693fad9e 100644 (file)
@@ -155,6 +155,7 @@ extern bool ix86_expand_mask_vec_cmp (rtx, enum rtx_code, rtx, rtx);
 extern bool ix86_expand_int_vec_cmp (rtx[]);
 extern bool ix86_expand_fp_vec_cmp (rtx[]);
 extern void ix86_expand_sse_movcc (rtx, rtx, rtx, rtx);
+extern void ix86_expand_sse_extend (rtx, rtx, bool);
 extern void ix86_expand_sse_unpack (rtx, rtx, bool, bool);
 extern void ix86_expand_fp_spaceship (rtx, rtx, rtx);
 extern bool ix86_expand_int_addcc (rtx[]);
index 170432a71282e5acf66597db5701974454e29a06..ef5782229451f8fc6846e595dbef21fcbd000fee 100644 (file)
   [(set (match_operand:V4HI 0 "register_operand")
        (any_extend:V4HI
          (match_operand:V4QI 1 "register_operand")))]
-  "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE"
+  "TARGET_MMX_WITH_SSE"
 {
+  if (!TARGET_SSE4_1)
+    {
+      ix86_expand_sse_extend (operands[0], operands[1], <u_bool>);
+      DONE;
+    }
+
   rtx op1 = force_reg (V4QImode, operands[1]);
   op1 = lowpart_subreg (V8QImode, op1, V4QImode);
   emit_insn (gen_sse4_1_<code>v4qiv4hi2 (operands[0], op1));
   [(set (match_operand:V2SI 0 "register_operand")
        (any_extend:V2SI
          (match_operand:V2HI 1 "register_operand")))]
-  "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE"
+  "TARGET_MMX_WITH_SSE"
 {
+  if (!TARGET_SSE4_1)
+    {
+      ix86_expand_sse_extend (operands[0], operands[1], <u_bool>);
+      DONE;
+    }
+
   rtx op1 = force_reg (V2HImode, operands[1]);
   op1 = lowpart_subreg (V4HImode, op1, V2HImode);
   emit_insn (gen_sse4_1_<code>v2hiv2si2 (operands[0], op1));
   [(set (match_operand:V2HI 0 "register_operand")
        (any_extend:V2HI
          (match_operand:V2QI 1 "register_operand")))]
-  "TARGET_SSE4_1"
+  "TARGET_SSE2"
 {
+  if (!TARGET_SSE4_1)
+    {
+      ix86_expand_sse_extend (operands[0], operands[1], <u_bool>);
+      DONE;
+    }
+
   rtx op1 = force_reg (V2QImode, operands[1]);
   op1 = lowpart_subreg (V4QImode, op1, V2QImode);
   emit_insn (gen_sse4_1_<code>v2qiv2hi2 (operands[0], op1));
index 6784a8c53693b86a348be858455ddac659a7b747..87c3bf0702082b1335519c94ecc34111e0c25be6 100644 (file)
   [(set (match_operand:V8HI 0 "register_operand")
        (any_extend:V8HI
          (match_operand:V8QI 1 "nonimmediate_operand")))]
-  "TARGET_SSE4_1"
+  "TARGET_SSE4_1 || TARGET_MMX_WITH_SSE"
 {
+  if (!TARGET_SSE4_1)
+    {
+      rtx op1 = force_reg (V8QImode, operands[1]);
+      ix86_expand_sse_extend (operands[0], op1, <u_bool>);
+      DONE;
+    }
+
   if (!MEM_P (operands[1]))
     {
       rtx op1 = force_reg (V8QImode, operands[1]);
   [(set (match_operand:V4SI 0 "register_operand")
        (any_extend:V4SI
          (match_operand:V4HI 1 "nonimmediate_operand")))]
-  "TARGET_SSE4_1"
+  "TARGET_SSE4_1 || TARGET_MMX_WITH_SSE"
 {
+  if (!TARGET_SSE4_1)
+    {
+      rtx op1 = force_reg (V4HImode, operands[1]);
+      ix86_expand_sse_extend (operands[0], op1, <u_bool>);
+      DONE;
+    }
+
   if (!MEM_P (operands[1]))
     {
       rtx op1 = force_reg (V4HImode, operands[1]);
   [(set (match_operand:V2DI 0 "register_operand")
        (any_extend:V2DI
          (match_operand:V2SI 1 "nonimmediate_operand")))]
-  "TARGET_SSE4_1"
+  "TARGET_SSE4_1 || TARGET_MMX_WITH_SSE"
 {
+  if (!TARGET_SSE4_1)
+    {
+      rtx op1 = force_reg (V2SImode, operands[1]);
+      ix86_expand_sse_extend (operands[0], op1, <u_bool>);
+      DONE;
+    }
+
   if (!MEM_P (operands[1]))
     {
       rtx op1 = force_reg (V2SImode, operands[1]);
diff --git a/gcc/testsuite/gcc.target/i386/pr111023-2.c b/gcc/testsuite/gcc.target/i386/pr111023-2.c
new file mode 100644 (file)
index 0000000..6c69f94
--- /dev/null
@@ -0,0 +1,52 @@
+/* PR target/111023 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */
+
+typedef char v16qi __attribute__((vector_size (16)));
+typedef short v8hi __attribute__((vector_size (16)));
+typedef int v4si __attribute__((vector_size (16)));
+typedef long long v2di __attribute__((vector_size (16)));
+
+void
+v8hi_v8qi (v8hi *dst, v16qi src)
+{
+  short tem[8];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  tem[2] = src[2];
+  tem[3] = src[3];
+  tem[4] = src[4];
+  tem[5] = src[5];
+  tem[6] = src[6];
+  tem[7] = src[7];
+  dst[0] = *(v8hi *) tem;
+}
+
+/* { dg-final { scan-assembler "pcmpgtb" } } */
+/* { dg-final { scan-assembler "punpcklbw" } } */
+
+void
+v4si_v4hi (v4si *dst, v8hi src)
+{
+  int tem[4];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  tem[2] = src[2];
+  tem[3] = src[3];
+  dst[0] = *(v4si *) tem;
+}
+
+/* { dg-final { scan-assembler "pcmpgtw" } } */
+/* { dg-final { scan-assembler "punpcklwd" } } */
+
+void
+v2di_v2si (v2di *dst, v4si src)
+{
+  long long tem[2];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  dst[0] = *(v2di *) tem;
+}
+
+/* { dg-final { scan-assembler "pcmpgtd" } } */
+/* { dg-final { scan-assembler "punpckldq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr111023-4b.c b/gcc/testsuite/gcc.target/i386/pr111023-4b.c
new file mode 100644 (file)
index 0000000..061f6a1
--- /dev/null
@@ -0,0 +1,17 @@
+/* PR target/111023 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */
+
+typedef unsigned char v4qi __attribute__((vector_size (4)));
+typedef unsigned short v2hi __attribute__((vector_size (4)));
+
+void
+v2hi_v2qi (v2hi *dst, v4qi src)
+{
+  unsigned short tem[2];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  dst[0] = *(v2hi *) tem;
+}
+
+/* { dg-final { scan-assembler "punpcklbw" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr111023-8b.c b/gcc/testsuite/gcc.target/i386/pr111023-8b.c
new file mode 100644 (file)
index 0000000..26c5e27
--- /dev/null
@@ -0,0 +1,31 @@
+/* PR target/111023 */
+/* { dg-do compile  { target { ! ia32 } } } */
+/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */
+
+typedef unsigned char v8qi __attribute__((vector_size (8)));
+typedef unsigned short v4hi __attribute__((vector_size (8)));
+typedef unsigned int v2si __attribute__((vector_size (8)));
+
+void
+v4hi_v4qi (v4hi *dst, v8qi src)
+{
+  unsigned short tem[4];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  tem[2] = src[2];
+  tem[3] = src[3];
+  dst[0] = *(v4hi *) tem;
+}
+
+/* { dg-final { scan-assembler "punpcklbw" } } */
+
+void
+v2si_v2hi (v2si *dst, v4hi src)
+{
+  unsigned int tem[2];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  dst[0] = *(v2si *) tem;
+}
+
+/* { dg-final { scan-assembler "punpcklwd" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr111023.c b/gcc/testsuite/gcc.target/i386/pr111023.c
new file mode 100644 (file)
index 0000000..6144c37
--- /dev/null
@@ -0,0 +1,49 @@
+/* PR target/111023 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=icelake-server -ftree-vectorize -msse2 -mno-sse4.1" } */
+
+typedef unsigned char v16qi __attribute__((vector_size (16)));
+typedef unsigned short v8hi __attribute__((vector_size (16)));
+typedef unsigned int v4si __attribute__((vector_size (16)));
+typedef unsigned long long v2di __attribute__((vector_size (16)));
+
+void
+v8hi_v8qi (v8hi *dst, v16qi src)
+{
+  unsigned short tem[8];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  tem[2] = src[2];
+  tem[3] = src[3];
+  tem[4] = src[4];
+  tem[5] = src[5];
+  tem[6] = src[6];
+  tem[7] = src[7];
+  dst[0] = *(v8hi *) tem;
+}
+
+/* { dg-final { scan-assembler "punpcklbw" } } */
+
+void
+v4si_v4hi (v4si *dst, v8hi src)
+{
+  unsigned int tem[4];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  tem[2] = src[2];
+  tem[3] = src[3];
+  dst[0] = *(v4si *) tem;
+}
+
+/* { dg-final { scan-assembler "punpcklwd" } } */
+
+void
+v2di_v2si (v2di *dst, v4si src)
+{
+  unsigned long long tem[2];
+  tem[0] = src[0];
+  tem[1] = src[1];
+  dst[0] = *(v2di *) tem;
+}
+
+/* { dg-final { scan-assembler "punpckldq" } } */