This patch enables MVE vmin/vmax instructions for auto-vectorization.
MVE target is included in expander smin<mode>3, umin<mode>3, smax<mode>3
and umax<mode>3 for vectorization. Related insns for vmin/vmax in mve.md
are modified to use smin, umin, smax and umax expressions instead of
unspec to support the expanders.
gcc/ChangeLog:
2020-10-22 Dennis Zhang <dennis.zhang@arm.com>
* config/arm/mve.md (mve_vmaxq_<supf><mode>): Replace with ...
(mve_vmaxq_s<mode>, mve_vmaxq_u<mode>): ... these new insns to
use smax/umax instead of VMAXQ.
(mve_vminq_<supf><mode>): Replace with ...
(mve_vminq_s<mode>, mve_vminq_u<mode>): ... these new insns to
use smin/umin instead of VMINQ.
(mve_vmaxnmq_f<mode>): Use smax instead of VMAXNMQ_F.
(mve_vminnmq_f<mode>): Use smin instead of VMINNMQ_F.
* config/arm/vec-common.md (smin<mode>3): Use the new mode macros
ARM_HAVE_<MODE>_ARITH.
(umin<mode>3, smax<mode>3, umax<mode>3): Likewise.
gcc/testsuite/ChangeLog:
* gcc.target/arm/simd/mve-vminmax_1.c: New test.
+2020-10-22 Dennis Zhang <dennis.zhang@arm.com>
+
+ * config/arm/mve.md (mve_vmaxq_<supf><mode>): Replace with ...
+ (mve_vmaxq_s<mode>, mve_vmaxq_u<mode>): ... these new insns to
+ use smax/umax instead of VMAXQ.
+ (mve_vminq_<supf><mode>): Replace with ...
+ (mve_vminq_s<mode>, mve_vminq_u<mode>): ... these new insns to
+ use smin/umin instead of VMINQ.
+ (mve_vmaxnmq_f<mode>): Use smax instead of VMAXNMQ_F.
+ (mve_vminnmq_f<mode>): Use smin instead of VMINNMQ_F.
+ * config/arm/vec-common.md (smin<mode>3): Use the new mode macros
+ ARM_HAVE_<MODE>_ARITH.
+ (umin<mode>3, smax<mode>3, umax<mode>3): Likewise.
+
2020-10-22 Dennis Zhang <dennis.zhang@arm.com>
* config/arm/mve.md (mve_vmulq<mode>): New entry for vmul instruction
;;
;; [vmaxq_u, vmaxq_s])
;;
-(define_insn "mve_vmaxq_<supf><mode>"
+(define_insn "mve_vmaxq_s<mode>"
[
(set (match_operand:MVE_2 0 "s_register_operand" "=w")
- (unspec:MVE_2 [(match_operand:MVE_2 1 "s_register_operand" "w")
- (match_operand:MVE_2 2 "s_register_operand" "w")]
- VMAXQ))
+ (smax:MVE_2 (match_operand:MVE_2 1 "s_register_operand" "w")
+ (match_operand:MVE_2 2 "s_register_operand" "w")))
+ ]
+ "TARGET_HAVE_MVE"
+ "vmax.%#<V_s_elem>\t%q0, %q1, %q2"
+ [(set_attr "type" "mve_move")
+])
+
+(define_insn "mve_vmaxq_u<mode>"
+ [
+ (set (match_operand:MVE_2 0 "s_register_operand" "=w")
+ (umax:MVE_2 (match_operand:MVE_2 1 "s_register_operand" "w")
+ (match_operand:MVE_2 2 "s_register_operand" "w")))
]
"TARGET_HAVE_MVE"
- "vmax.<supf>%#<V_sz_elem>\t%q0, %q1, %q2"
+ "vmax.%#<V_u_elem>\t%q0, %q1, %q2"
[(set_attr "type" "mve_move")
])
;;
;; [vminq_s, vminq_u])
;;
-(define_insn "mve_vminq_<supf><mode>"
+(define_insn "mve_vminq_s<mode>"
[
(set (match_operand:MVE_2 0 "s_register_operand" "=w")
- (unspec:MVE_2 [(match_operand:MVE_2 1 "s_register_operand" "w")
- (match_operand:MVE_2 2 "s_register_operand" "w")]
- VMINQ))
+ (smin:MVE_2 (match_operand:MVE_2 1 "s_register_operand" "w")
+ (match_operand:MVE_2 2 "s_register_operand" "w")))
]
"TARGET_HAVE_MVE"
- "vmin.<supf>%#<V_sz_elem>\t%q0, %q1, %q2"
+ "vmin.%#<V_s_elem>\t%q0, %q1, %q2"
+ [(set_attr "type" "mve_move")
+])
+
+(define_insn "mve_vminq_u<mode>"
+ [
+ (set (match_operand:MVE_2 0 "s_register_operand" "=w")
+ (umin:MVE_2 (match_operand:MVE_2 1 "s_register_operand" "w")
+ (match_operand:MVE_2 2 "s_register_operand" "w")))
+ ]
+ "TARGET_HAVE_MVE"
+ "vmin.%#<V_u_elem>\t%q0, %q1, %q2"
[(set_attr "type" "mve_move")
])
(define_insn "mve_vmaxnmq_f<mode>"
[
(set (match_operand:MVE_0 0 "s_register_operand" "=w")
- (unspec:MVE_0 [(match_operand:MVE_0 1 "s_register_operand" "w")
- (match_operand:MVE_0 2 "s_register_operand" "w")]
- VMAXNMQ_F))
+ (smax:MVE_0 (match_operand:MVE_0 1 "s_register_operand" "w")
+ (match_operand:MVE_0 2 "s_register_operand" "w")))
]
"TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT"
"vmaxnm.f%#<V_sz_elem> %q0, %q1, %q2"
(define_insn "mve_vminnmq_f<mode>"
[
(set (match_operand:MVE_0 0 "s_register_operand" "=w")
- (unspec:MVE_0 [(match_operand:MVE_0 1 "s_register_operand" "w")
- (match_operand:MVE_0 2 "s_register_operand" "w")]
- VMINNMQ_F))
+ (smin:MVE_0 (match_operand:MVE_0 1 "s_register_operand" "w")
+ (match_operand:MVE_0 2 "s_register_operand" "w")))
]
"TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT"
"vminnm.f%#<V_sz_elem> %q0, %q1, %q2"
[(set (match_operand:VALLW 0 "s_register_operand")
(smin:VALLW (match_operand:VALLW 1 "s_register_operand")
(match_operand:VALLW 2 "s_register_operand")))]
- "(TARGET_NEON && ((<MODE>mode != V2SFmode && <MODE>mode != V4SFmode)
- || flag_unsafe_math_optimizations))
- || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))"
-{
-})
+ "ARM_HAVE_<MODE>_ARITH"
+)
(define_expand "umin<mode>3"
[(set (match_operand:VINTW 0 "s_register_operand")
(umin:VINTW (match_operand:VINTW 1 "s_register_operand")
(match_operand:VINTW 2 "s_register_operand")))]
- "TARGET_NEON
- || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))"
-{
-})
+ "ARM_HAVE_<MODE>_ARITH"
+)
(define_expand "smax<mode>3"
[(set (match_operand:VALLW 0 "s_register_operand")
(smax:VALLW (match_operand:VALLW 1 "s_register_operand")
(match_operand:VALLW 2 "s_register_operand")))]
- "(TARGET_NEON && ((<MODE>mode != V2SFmode && <MODE>mode != V4SFmode)
- || flag_unsafe_math_optimizations))
- || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))"
-{
-})
+ "ARM_HAVE_<MODE>_ARITH"
+)
(define_expand "umax<mode>3"
[(set (match_operand:VINTW 0 "s_register_operand")
(umax:VINTW (match_operand:VINTW 1 "s_register_operand")
(match_operand:VINTW 2 "s_register_operand")))]
- "TARGET_NEON
- || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (<MODE>mode))"
-{
-})
+ "ARM_HAVE_<MODE>_ARITH"
+)
(define_expand "vec_perm<mode>"
[(match_operand:VE 0 "s_register_operand")
+2020-10-22 Dennis Zhang <dennis.zhang@arm.com>
+
+ * gcc.target/arm/simd/mve-vminmax_1.c: New test.
+
2020-10-22 Dennis Zhang <dennis.zhang@arm.com>
* gcc.target/arm/simd/mve-vmul_1.c: New test.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_1m_mve_ok } */
+/* { dg-options "-O3" } */
+/* { dg-add-options arm_v8_1m_mve } */
+
+#include <stdint.h>
+
+#define MAX(a, b) ((a) > (b)) ? (a) : (b)
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+
+#define TEST_BINOP(OP, TY, N) \
+ TY test_##OP##_##TY (TY * dest, TY * a, TY * b) \
+ { \
+ int i; \
+ for (i=0; i<N; i++) \
+ { \
+ dest[i] = OP (a[i], b[i]); \
+ } \
+ }
+
+/* Test vmax. */
+
+TEST_BINOP (MAX, int32_t, 4)
+/* { dg-final { scan-assembler-times {vmax\.s32\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MAX, uint32_t, 4)
+/* { dg-final { scan-assembler-times {vmax\.u32\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MAX, int16_t, 8)
+/* { dg-final { scan-assembler-times {vmax\.s16\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MAX, uint16_t, 8)
+/* { dg-final { scan-assembler-times {vmax\.u16\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MAX, int8_t, 16)
+/* { dg-final { scan-assembler-times {vmax\.s8\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MAX, uint8_t, 16)
+/* { dg-final { scan-assembler-times {vmax\.u8\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+/* Test vmin. */
+
+TEST_BINOP (MIN, int32_t, 4)
+/* { dg-final { scan-assembler-times {vmin\.s32\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MIN, uint32_t, 4)
+/* { dg-final { scan-assembler-times {vmin\.u32\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MIN, int16_t, 8)
+/* { dg-final { scan-assembler-times {vmin\.s16\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MIN, uint16_t, 8)
+/* { dg-final { scan-assembler-times {vmin\.u16\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MIN, int8_t, 16)
+/* { dg-final { scan-assembler-times {vmin\.s8\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+
+TEST_BINOP (MIN, uint8_t, 16)
+/* { dg-final { scan-assembler-times {vmin\.u8\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+