https://gcc.gnu.org/g:15cabcf0bd5d964181d43fb6b8c7daeebf874e24

commit r17-4079-g15cabcf0bd5d964181d43fb6b8c7daeebf874e24
Author: Roger Sayle <[email protected]>
Date:   Thu Sep 10 13:30:10 2026 +0100

    i386: More uses of insertps to implement VEC_PERM_EXPR on x86 SSE.
    
    This patch makes more use of SSE 4.1's insertps instruction to implement
    some vector permutations for V4SI and V4SF vectors.  While expanding
    VEC_PERM_EXPR, the i386 backend currently attempts (and fails) to
    recognize (via recog) RTL of the form:
    
       (set (reg:V4SI 100)
            (vec_select:V4SI (vec_concat:V8SI (reg/v:V4SI 99)
                    (const_vector:V4SI [
                            (const_int 0 [0]) repeated x4
                        ]))
                (parallel [
                        (const_int 0 [0])
                        (const_int 5 [0x5])
                        (const_int 6 [0x6])
                        (const_int 7 [0x7])
                    ])))
    
    This is extracting an element from one vector and inserting it
    (somewhere) in a vector of zeros.  It turns out all 16 cases
    (4 source positions x 4 destination positions) can be supported
    by adding four additional define_insns to the machine description
    [which unfortunately have identical output templates/attributes].
    
    As a motivating example:
    
    typedef int v4si __attribute__ ((__vector_size__ (16)));
    
    v4si i00(v4si x)
    {
      return (v4si){x[0],0,0,0};
    }
    
    which currently with -O2 -msse4.1 generates three instructions:
    
    i00:    movdqa  %xmm0, %xmm1
            pxor    %xmm0, %xmm0
            pblendw $3, %xmm1, %xmm0
            ret
    
    with this patch, we now generate a single instruction:
    
    i00:    insertps        $14, %xmm0, %xmm0
            ret
    
    The deeper motivation is that (as shown by the recent sse2-stv-1.c
    issue) the STV2 pass doesn't yet consider (zero_extend:DI (reg:SI))
    to be a candidate.  Clearly the insertps (above) can be used to
    perform zero extension in/on SSE registers, instead of transferring
    values to a GPR, performing the extension, and transferring it back.
    
    2026-09-10  Roger Sayle  <[email protected]>
                Hongtao Liu  <[email protected]>
    
    gcc/ChangeLog
            * config/i386/predicates.md (insertps_parallel): New predicate.
            * config/i386/sse.md (sse4_1_insertps_<mode>_perm): New
            define_insn to implement V4SI or V4SF permute using insertps.
            (*sse2_insertps_<mode>_perm): Emulate the above insn on SSE2
            by splitting to one or two of pslldq, psrldq and pshufd.
    
    gcc/testsuite/ChangeLog
            * gcc.target/i386/sse4_1-insertps-8.c: New test case.
            * gcc.target/i386/sse4_1-insertps-9.c: Likewise.
            * gcc.target/i386/vperm-v4sf-3-sse4.c: Likewise.
            * gcc.target/i386/vperm-v4sf-3.c: Likewise.
            * gcc.target/i386/vperm-v4si-3-sse4.c: Likewise.
            * gcc.target/i386/vperm-v4si-3.c: Likewise.

Diff:
---
 gcc/config/i386/predicates.md                     |  24 +++++
 gcc/config/i386/sse.md                            | 105 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/sse4_1-insertps-8.c |  31 +++++++
 gcc/testsuite/gcc.target/i386/sse4_1-insertps-9.c |  31 +++++++
 gcc/testsuite/gcc.target/i386/vperm-v4sf-3-sse4.c |   6 ++
 gcc/testsuite/gcc.target/i386/vperm-v4sf-3.c      |  74 +++++++++++++++
 gcc/testsuite/gcc.target/i386/vperm-v4si-3-sse4.c |   6 ++
 gcc/testsuite/gcc.target/i386/vperm-v4si-3.c      |  73 +++++++++++++++
 8 files changed, 350 insertions(+)

diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 289bf807e110..d295edd023de 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -2047,6 +2047,30 @@
   return true;
 })
 
+;; Return true if OP is a parallel for an insertps vec_select,
+;; where one of the two operands of the vec_concat is const0_operand.
+(define_predicate "insertps_parallel"
+  (and (match_code "parallel")
+       (match_code "const_int" "a"))
+{
+  int i;
+
+  if (XVECLEN (op, 0) != 4)
+    return false;
+
+  /* One element in [0..3], and the other 3 in [4..7].  */
+  bool found = false;
+  for (i = 0; i < 4; ++i)
+    if (INTVAL (XVECEXP (op, 0, i)) < 4)
+      {
+       if (found)
+         return false;
+       found = true;
+      }
+
+  return found;
+})
+
 ;; Return true if OP is a const vector with duplicate value.
 (define_predicate "const_vector_duplicate_operand"
   (match_code "const_vector")
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index eb3b8eb2fe05..a19472d63aec 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -13088,6 +13088,111 @@
    (set_attr "prefix" "orig")
    (set_attr "mode" "V4SF")])
 
+;; Use sse4_1_insertps_v4s[if] to permute to a one non-zero vector.
+(define_insn "*sse4_1_insertps_<mode>_perm"
+  [(set (match_operand:VI4F_128 0 "register_operand" "=x,v")
+       (vec_select:VI4F_128
+         (vec_concat:<ssedoublevecmode>
+           (match_operand:VI4F_128 1 "register_operand" "0,v")
+           (match_operand:VI4F_128 2 "const0_operand"))
+         (match_parallel 3 "insertps_parallel"
+           [(match_operand 4 "const_int_operand")])))]
+  "TARGET_SSE4_1"
+{
+  rtx op3 = operands[3];
+  int src, dst;
+
+  for (dst = 0; dst < 4; dst++)
+    {
+      src = INTVAL (XVECEXP (op3, 0, dst));
+      if (src < 4)
+       break;
+    }
+
+  if (TARGET_AVX10_2 && src == 0 && dst == 0)
+    return "vmovd\t{%1, %0|%0, %1}";
+  operands[3] = GEN_INT ((src << 6) + (dst << 4) + (15 - (1 << dst)));
+  switch (which_alternative)
+    {
+    case 0:
+      return "insertps\t{%3, %1, %0|%0, %1, %3}";
+    case 1:
+      return "vinsertps\t{%3, %1, %1, %0|%0, %1, %1, %3}";
+    default:
+      gcc_unreachable ();
+    }
+}
+  [(set_attr "isa" "noavx,avx")
+   (set_attr "type" "sselog")
+   (set_attr "prefix_data16" "1,*")
+   (set_attr "prefix_extra" "1")
+   (set_attr "length_immediate" "1")
+   (set_attr "prefix" "orig,maybe_evex")
+   (set_attr "mode" "V4SF")])
+
+;; Emulate the above insn on SSE2 using two of pslldq, psrldq and pshufd.
+(define_insn_and_split "*sse2_insertps_<mode>_perm"
+  [(set (match_operand:VI4F_128 0 "register_operand")
+       (vec_select:VI4F_128
+         (vec_concat:<ssedoublevecmode>
+           (match_operand:VI4F_128 1 "register_operand")
+           (match_operand:VI4F_128 2 "const0_operand"))
+         (match_parallel 3 "insertps_parallel"
+           [(match_operand 4 "const_int_operand")])))]
+  "TARGET_SSE2 && !TARGET_SSE4_1 && ix86_pre_reload_split ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  rtx op3 = operands[3];
+  int src, dst;
+
+  for (dst = 0; dst < 4; dst++)
+    {
+      src = INTVAL (XVECEXP (op3, 0, dst));
+      if (src < 4)
+       break;
+    }
+
+  if (src == 0 && dst == 3)
+    emit_insn (gen_vec_shl_<mode> (operands[0], operands[1], GEN_INT (96)));
+  else if (src == 3 && dst == 0)
+    emit_insn (gen_vec_shr_<mode> (operands[0], operands[1], GEN_INT (96)));
+  else
+    {
+      rtx tmp1 = gen_reg_rtx (<MODE>mode);
+      if (src == 0 || dst == 0)
+       {
+         emit_insn (gen_vec_shl_<mode> (tmp1, operands[1],
+                                        GEN_INT ((3 - src) * 32)));
+         emit_insn (gen_vec_shr_<mode> (operands[0], tmp1,
+                                        GEN_INT ((3 - dst) * 32)));
+       }
+      else
+       {
+         emit_insn (gen_vec_shr_<mode> (tmp1, operands[1],
+                                        GEN_INT (src * 32)));
+         if (src == 3 || dst == 3)
+           emit_insn (gen_vec_shl_<mode> (operands[0], tmp1,
+                                          GEN_INT (dst * 32)));
+         else /* (src == 1 || src == 2) && (dst == 1 || dst == 2).  */
+           {
+             rtx tmp2 = gen_lowpart (V4SImode, tmp1);
+             rtx tmp3 = <MODE>mode == V4SImode ? operands[0]
+                                               : gen_reg_rtx (V4SImode);
+             emit_insn (gen_sse2_pshufd_1 (tmp3, tmp2,
+                                           GEN_INT (3),
+                                           GEN_INT (dst == 1 ? 0 : 3),
+                                           GEN_INT (dst == 2 ? 0 : 3),
+                                           GEN_INT (3)));
+             if (<MODE>mode != V4SImode)
+               emit_move_insn (operands[0], gen_lowpart (<MODE>mode, tmp3));
+           }
+       }
+    }
+  DONE;
+})
+
 (define_split
   [(set (match_operand:VI4F_128 0 "memory_operand")
        (vec_merge:VI4F_128
diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-insertps-8.c 
b/gcc/testsuite/gcc.target/i386/sse4_1-insertps-8.c
new file mode 100644
index 000000000000..5ba57600260a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse4_1-insertps-8.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse4.1 -mno-avx" } */
+
+typedef int v4si __attribute__ ((__vector_size__ (16)));
+
+v4si i00(v4si x) { return (v4si){x[0],0,0,0}; }
+v4si i10(v4si x) { return (v4si){x[1],0,0,0}; }
+v4si i20(v4si x) { return (v4si){x[2],0,0,0}; }
+v4si i30(v4si x) { return (v4si){x[3],0,0,0}; }
+
+v4si i01(v4si x) { return (v4si){0,x[0],0,0}; }
+v4si i11(v4si x) { return (v4si){0,x[1],0,0}; }
+v4si i21(v4si x) { return (v4si){0,x[2],0,0}; }
+v4si i31(v4si x) { return (v4si){0,x[3],0,0}; }
+
+v4si i02(v4si x) { return (v4si){0,0,x[0],0}; }
+v4si i12(v4si x) { return (v4si){0,0,x[1],0}; }
+v4si i22(v4si x) { return (v4si){0,0,x[2],0}; }
+v4si i32(v4si x) { return (v4si){0,0,x[3],0}; }
+
+v4si i03(v4si x) { return (v4si){0,0,0,x[0]}; }
+v4si i13(v4si x) { return (v4si){0,0,0,x[1]}; }
+v4si i23(v4si x) { return (v4si){0,0,0,x[2]}; }
+v4si i33(v4si x) { return (v4si){0,0,0,x[3]}; }
+
+/* { dg-final { scan-assembler-times "\tv?insertps\t" 14 } } */
+/* { dg-final { scan-assembler-times "\tv?pslldq\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tv?psrldq\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tv?movdqa\t" } } */
+/* { dg-final { scan-assembler-not "\tv?movss\t" } } */
+/* { dg-final { scan-assembler-not "\tv?pxor\t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-insertps-9.c 
b/gcc/testsuite/gcc.target/i386/sse4_1-insertps-9.c
new file mode 100644
index 000000000000..76d25d724bdf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse4_1-insertps-9.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse4.1 -mno-avx" } */
+
+typedef float v4sf __attribute__ ((__vector_size__ (16)));
+
+v4sf f00(v4sf x) { return (v4sf){x[0],0.0f,0.0f,0.0f}; }
+v4sf f10(v4sf x) { return (v4sf){x[1],0.0f,0.0f,0.0f}; }
+v4sf f20(v4sf x) { return (v4sf){x[2],0.0f,0.0f,0.0f}; }
+v4sf f30(v4sf x) { return (v4sf){x[3],0.0f,0.0f,0.0f}; }
+
+v4sf f01(v4sf x) { return (v4sf){0.0f,x[0],0.0f,0.0f}; }
+v4sf f11(v4sf x) { return (v4sf){0.0f,x[1],0.0f,0.0f}; }
+v4sf f21(v4sf x) { return (v4sf){0.0f,x[2],0.0f,0.0f}; }
+v4sf f31(v4sf x) { return (v4sf){0.0f,x[3],0.0f,0.0f}; }
+
+v4sf f02(v4sf x) { return (v4sf){0.0f,0.0f,x[0],0.0f}; }
+v4sf f12(v4sf x) { return (v4sf){0.0f,0.0f,x[1],0.0f}; }
+v4sf f22(v4sf x) { return (v4sf){0.0f,0.0f,x[2],0.0f}; }
+v4sf f32(v4sf x) { return (v4sf){0.0f,0.0f,x[3],0.0f}; }
+
+v4sf f03(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[0]}; }
+v4sf f13(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[1]}; }
+v4sf f23(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[2]}; }
+v4sf f33(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[3]}; }
+
+/* { dg-final { scan-assembler-times "\tv?insertps\t" 14 } } */
+/* { dg-final { scan-assembler-times "\tv?pslldq\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tv?psrldq\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tv?movdqa\t" } } */
+/* { dg-final { scan-assembler-not "\tv?movss\t" } } */
+/* { dg-final { scan-assembler-not "\tv?pxor\t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/vperm-v4sf-3-sse4.c 
b/gcc/testsuite/gcc.target/i386/vperm-v4sf-3-sse4.c
new file mode 100644
index 000000000000..d79e54513903
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/vperm-v4sf-3-sse4.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-require-effective-target sse4 } */
+/* { dg-options "-O -msse4.1" } */
+#include "isa-check.h"
+#define CHECK_ISA
+#include "vperm-v4sf-3.c"
diff --git a/gcc/testsuite/gcc.target/i386/vperm-v4sf-3.c 
b/gcc/testsuite/gcc.target/i386/vperm-v4sf-3.c
new file mode 100644
index 000000000000..6ed939bef32f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/vperm-v4sf-3.c
@@ -0,0 +1,74 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+typedef float v4sf __attribute__ ((__vector_size__ (16)));
+
+v4sf f00(v4sf x) { return (v4sf){x[0],0.0f,0.0f,0.0f}; }
+v4sf f10(v4sf x) { return (v4sf){x[1],0.0f,0.0f,0.0f}; }
+v4sf f20(v4sf x) { return (v4sf){x[2],0.0f,0.0f,0.0f}; }
+v4sf f30(v4sf x) { return (v4sf){x[3],0.0f,0.0f,0.0f}; }
+
+v4sf f01(v4sf x) { return (v4sf){0.0f,x[0],0.0f,0.0f}; }
+v4sf f11(v4sf x) { return (v4sf){0.0f,x[1],0.0f,0.0f}; }
+v4sf f21(v4sf x) { return (v4sf){0.0f,x[2],0.0f,0.0f}; }
+v4sf f31(v4sf x) { return (v4sf){0.0f,x[3],0.0f,0.0f}; }
+
+v4sf f02(v4sf x) { return (v4sf){0.0f,0.0f,x[0],0.0f}; }
+v4sf f12(v4sf x) { return (v4sf){0.0f,0.0f,x[1],0.0f}; }
+v4sf f22(v4sf x) { return (v4sf){0.0f,0.0f,x[2],0.0f}; }
+v4sf f32(v4sf x) { return (v4sf){0.0f,0.0f,x[3],0.0f}; }
+
+v4sf f03(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[0]}; }
+v4sf f13(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[1]}; }
+v4sf f23(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[2]}; }
+v4sf f33(v4sf x) { return (v4sf){0.0f,0.0f,0.0f,x[3]}; }
+
+
+typedef v4sf (*fun_t)(v4sf);
+typedef struct {
+  fun_t fun;
+  float a0, a1, a2, a3;
+  float b0, b1, b2, b3;
+} test_t;
+
+const test_t tests[16] = {
+  { f00,  1.0f, 0.0f, 0.0f, 0.0f,  4.0f, 0.0f, 0.0f, 0.0f },
+  { f10,  2.0f, 0.0f, 0.0f, 0.0f,  3.0f, 0.0f, 0.0f, 0.0f },
+  { f20,  3.0f, 0.0f, 0.0f, 0.0f,  2.0f, 0.0f, 0.0f, 0.0f },
+  { f30,  4.0f, 0.0f, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f, 0.0f },
+  { f01,  0.0f, 1.0f, 0.0f, 0.0f,  0.0f, 4.0f, 0.0f, 0.0f },
+  { f11,  0.0f, 2.0f, 0.0f, 0.0f,  0.0f, 3.0f, 0.0f, 0.0f },
+  { f21,  0.0f, 3.0f, 0.0f, 0.0f,  0.0f, 2.0f, 0.0f, 0.0f },
+  { f31,  0.0f, 4.0f, 0.0f, 0.0f,  0.0f, 1.0f, 0.0f, 0.0f },
+  { f02,  0.0f, 0.0f, 1.0f, 0.0f,  0.0f, 0.0f, 4.0f, 0.0f },
+  { f12,  0.0f, 0.0f, 2.0f, 0.0f,  0.0f, 0.0f, 3.0f, 0.0f },
+  { f22,  0.0f, 0.0f, 3.0f, 0.0f,  0.0f, 0.0f, 2.0f, 0.0f },
+  { f32,  0.0f, 0.0f, 4.0f, 0.0f,  0.0f, 0.0f, 1.0f, 0.0f },
+  { f03,  0.0f, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f, 0.0f, 4.0f },
+  { f13,  0.0f, 0.0f, 0.0f, 2.0f,  0.0f, 0.0f, 0.0f, 3.0f },
+  { f23,  0.0f, 0.0f, 0.0f, 3.0f,  0.0f, 0.0f, 0.0f, 2.0f },
+  { f33,  0.0f, 0.0f, 0.0f, 4.0f,  0.0f, 0.0f, 0.0f, 1.0f }
+};
+
+int main()
+{
+#ifdef CHECK_ISA
+  check_isa ();
+#endif
+
+  int i;
+  v4sf a = (v4sf){ 1.0f, 2.0f, 3.0f, 4.0f };
+  v4sf b = (v4sf){ 4.0f, 3.0f, 2.0f, 1.0f };
+  for (i = 0; i < 16; i++) {
+  const test_t *p = &tests[i];
+    v4sf o1 = (*p->fun)(a);
+    if (o1[0] != p->a0 || o1[1] != p->a1 || o1[2] != p->a2 || o1[3] != p->a3)
+      __builtin_abort ();
+
+    v4sf o2 = (*p->fun)(b);
+    if (o2[0] != p->b0 || o2[1] != p->b1 || o2[2] != p->b2 || o2[3] != p->b3)
+      __builtin_abort ();
+  }
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/i386/vperm-v4si-3-sse4.c 
b/gcc/testsuite/gcc.target/i386/vperm-v4si-3-sse4.c
new file mode 100644
index 000000000000..75cca2fc232e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/vperm-v4si-3-sse4.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-require-effective-target sse4 } */
+/* { dg-options "-O -msse4.1" } */
+#include "isa-check.h"
+#define CHECK_ISA
+#include "vperm-v4si-3.c"
diff --git a/gcc/testsuite/gcc.target/i386/vperm-v4si-3.c 
b/gcc/testsuite/gcc.target/i386/vperm-v4si-3.c
new file mode 100644
index 000000000000..2ad9bf1d7f09
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/vperm-v4si-3.c
@@ -0,0 +1,73 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+typedef int v4si __attribute__ ((__vector_size__ (16)));
+
+v4si i00(v4si x) { return (v4si){x[0],0,0,0}; }
+v4si i10(v4si x) { return (v4si){x[1],0,0,0}; }
+v4si i20(v4si x) { return (v4si){x[2],0,0,0}; }
+v4si i30(v4si x) { return (v4si){x[3],0,0,0}; }
+
+v4si i01(v4si x) { return (v4si){0,x[0],0,0}; }
+v4si i11(v4si x) { return (v4si){0,x[1],0,0}; }
+v4si i21(v4si x) { return (v4si){0,x[2],0,0}; }
+v4si i31(v4si x) { return (v4si){0,x[3],0,0}; }
+
+v4si i02(v4si x) { return (v4si){0,0,x[0],0}; }
+v4si i12(v4si x) { return (v4si){0,0,x[1],0}; }
+v4si i22(v4si x) { return (v4si){0,0,x[2],0}; }
+v4si i32(v4si x) { return (v4si){0,0,x[3],0}; }
+
+v4si i03(v4si x) { return (v4si){0,0,0,x[0]}; }
+v4si i13(v4si x) { return (v4si){0,0,0,x[1]}; }
+v4si i23(v4si x) { return (v4si){0,0,0,x[2]}; }
+v4si i33(v4si x) { return (v4si){0,0,0,x[3]}; }
+
+typedef v4si (*fun_t)(v4si);
+typedef struct {
+  fun_t fun;
+  int a0, a1, a2, a3;
+  int b0, b1, b2, b3;
+} test_t;
+
+const test_t tests[16] = {
+  { i00,  1, 0, 0, 0,  4, 0, 0, 0 },
+  { i10,  2, 0, 0, 0,  3, 0, 0, 0 },
+  { i20,  3, 0, 0, 0,  2, 0, 0, 0 },
+  { i30,  4, 0, 0, 0,  1, 0, 0, 0 },
+  { i01,  0, 1, 0, 0,  0, 4, 0, 0 },
+  { i11,  0, 2, 0, 0,  0, 3, 0, 0 },
+  { i21,  0, 3, 0, 0,  0, 2, 0, 0 },
+  { i31,  0, 4, 0, 0,  0, 1, 0, 0 },
+  { i02,  0, 0, 1, 0,  0, 0, 4, 0 },
+  { i12,  0, 0, 2, 0,  0, 0, 3, 0 },
+  { i22,  0, 0, 3, 0,  0, 0, 2, 0 },
+  { i32,  0, 0, 4, 0,  0, 0, 1, 0 },
+  { i03,  0, 0, 0, 1,  0, 0, 0, 4 },
+  { i13,  0, 0, 0, 2,  0, 0, 0, 3 },
+  { i23,  0, 0, 0, 3,  0, 0, 0, 2 },
+  { i33,  0, 0, 0, 4,  0, 0, 0, 1 }
+};
+
+int main()
+{
+#ifdef CHECK_ISA
+  check_isa ();
+#endif
+
+  int i;
+  v4si a = (v4si){ 1, 2, 3, 4 };
+  v4si b = (v4si){ 4, 3, 2, 1 };
+  for (i = 0; i < 16; i++) {
+  const test_t *p = &tests[i];
+    v4si o1 = (*p->fun)(a);
+    if (o1[0] != p->a0 || o1[1] != p->a1 || o1[2] != p->a2 || o1[3] != p->a3)
+      __builtin_abort ();
+
+    v4si o2 = (*p->fun)(b);
+    if (o2[0] != p->b0 || o2[1] != p->b1 || o2[2] != p->b2 || o2[3] != p->b3)
+      __builtin_abort ();
+  }
+  return 0;
+}
+

Reply via email to