@@ -13059,6 +13059,133 @@
(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_0"
+ [(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"))
+ (parallel [(match_operand:SI 3 "const_0_to_3_operand")
+ (const_int 5)
+ (const_int 6)
+ (const_int 7)])))]
+ "TARGET_SSE4_1"
+{
+ if (TARGET_AVX10_2 && operands[3] == const0_rtx)
+ return "vmovd\t{%1, %0|%0, %1}";
+ operands[3] = GEN_INT ((INTVAL (operands[3]) << 6) + 14);
+ 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")])
+
+(define_insn "*sse4_1_insertps_<mode>_perm_1"
+ [(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"))
+ (parallel [(const_int 4)
+ (match_operand:SI 3 "const_0_to_3_operand")
+ (const_int 6)
+ (const_int 7)])))]
+ "TARGET_SSE4_1"
+{
+ operands[3] = GEN_INT ((INTVAL (operands[3]) << 6) + (16 + 13));
+ 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")])
+
+(define_insn "*sse4_1_insertps_<mode>_perm_2"
+ [(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"))
+ (parallel [(const_int 4)
+ (const_int 5)
+ (match_operand:SI 3 "const_0_to_3_operand")
+ (const_int 7)])))]
+ "TARGET_SSE4_1"
+{
+ operands[3] = GEN_INT ((INTVAL (operands[3]) << 6) + (32 + 11));
+ 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")])
+
+(define_insn "*sse4_1_insertps_<mode>_perm_3"
+ [(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"))
+ (parallel [(const_int 4)
+ (const_int 5)
+ (const_int 6)
+ (match_operand:SI 3 "const_0_to_3_operand")])))]
+ "TARGET_SSE4_1"
+{
+ operands[3] = GEN_INT ((INTVAL (operands[3]) << 6) + (48 + 7));
+ 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")])
+
(define_split
[(set (match_operand:VI4F_128 0 "memory_operand")
(vec_merge:VI4F_128
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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"
new file mode 100644
@@ -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;
+}
+
new file mode 100644
@@ -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"
new file mode 100644
@@ -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;
+}
+