"vpdi\t%v0,%v1,%v2,4"
[(set_attr "op_type" "VRR")])
+; Second DW of op1 and first DW of op2 (when interpreted as 2-element vector).
+(define_insn "@vpdi4_2<mode>"
+ [(set (match_operand:V_HW_4 0 "register_operand" "=v")
+ (vec_select:V_HW_4
+ (vec_concat:<vec_2x_nelts>
+ (match_operand:V_HW_4 1 "register_operand" "v")
+ (match_operand:V_HW_4 2 "register_operand" "v"))
+ (parallel [(const_int 2) (const_int 3) (const_int 4) (const_int 5)])))]
+ "TARGET_VX"
+ "vpdi\t%v0,%v1,%v2,4"
+ [(set_attr "op_type" "VRR")])
(define_insn "*vmrhb"
[(set (match_operand:V16QI 0 "register_operand" "=v")
"<vec_shifts_mnem><bhfgq>\t%v0,%v1,%Y2"
[(set_attr "op_type" "VRS")])
+; verllg for V4SI/V4SF. This swaps the first and the second two
+; elements of a vector and is only valid in that context.
+(define_expand "rotl<mode>3_di"
+ [
+ (set (match_dup 2)
+ (subreg:V2DI (match_operand:V_HW_4 1) 0))
+ (set (match_dup 3)
+ (rotate:V2DI
+ (match_dup 2)
+ (const_int 32)))
+ (set (match_operand:V_HW_4 0)
+ (subreg:V_HW_4 (match_dup 3) 0))]
+ "TARGET_VX"
+ {
+ operands[2] = gen_reg_rtx (V2DImode);
+ operands[3] = gen_reg_rtx (V2DImode);
+ })
; Shift each element by corresponding vector element
vster<bhfgq>\t%v1,%v0"
[(set_attr "op_type" "*,VRX,VRX")])
+; Swapping v2df/v2di can be done via vpdi on z13 and z14.
+(define_split
+ [(set (match_operand:V_HW_2 0 "register_operand" "")
+ (unspec:V_HW_2 [(match_operand:V_HW_2 1 "register_operand" "")]
+ UNSPEC_VEC_ELTSWAP))]
+ "TARGET_VX && can_create_pseudo_p ()"
+ [(set (match_operand:V_HW_2 0 "register_operand" "=v")
+ (vec_select:V_HW_2
+ (vec_concat:<vec_2x_nelts>
+ (match_operand:V_HW_2 1 "register_operand" "v")
+ (match_dup 1))
+ (parallel [(const_int 1) (const_int 2)])))]
+)
+
+
+; Swapping v4df/v4si can be done via vpdi and rot.
+(define_split
+ [(set (match_operand:V_HW_4 0 "register_operand" "")
+ (unspec:V_HW_4 [(match_operand:V_HW_4 1 "register_operand" "")]
+ UNSPEC_VEC_ELTSWAP))]
+ "TARGET_VX && can_create_pseudo_p ()"
+ [(set (match_dup 2)
+ (vec_select:V_HW_4
+ (vec_concat:<vec_2x_nelts>
+ (match_dup 1)
+ (match_dup 1))
+ (parallel [(const_int 2) (const_int 3) (const_int 4) (const_int 5)])))
+ (set (match_dup 3)
+ (subreg:V2DI (match_dup 2) 0))
+ (set (match_dup 4)
+ (rotate:V2DI
+ (match_dup 3)
+ (const_int 32)))
+ (set (match_operand:V_HW_4 0)
+ (subreg:V_HW_4 (match_dup 4) 0))]
+{
+ operands[2] = gen_reg_rtx (<MODE>mode);
+ operands[3] = gen_reg_rtx (V2DImode);
+ operands[4] = gen_reg_rtx (V2DImode);
+})
+
; z15 has instructions for doing element reversal from mem to reg
; or the other way around. For reg to reg or on pre z15 machines
; we have to emulate it with vector permute.
--- /dev/null
+/* Test that we use vpdi in order to reverse vectors
+ with two elements instead of creating a literal-pool entry
+ and permuting with vperm. */
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-O2 -march=z14 -mzarch -mzvector -fno-unroll-loops" } */
+
+/* { dg-final { scan-assembler-times "vpdi\t" 4 } } */
+/* { dg-final { scan-assembler-times "verllg\t" 2 } } */
+/* { dg-final { scan-assembler-times "vperm" 0 } } */
+
+#include <vecintrin.h>
+
+vector double reved (vector double a)
+{
+ return vec_reve (a);
+}
+
+vector long long revel (vector long long a)
+{
+ return vec_reve (a);
+}
+
+vector float revef (vector float a)
+{
+ return vec_reve (a);
+}
+
+vector int revei (vector int a)
+{
+ return vec_reve (a);
+}