RISC-V: Add RVV vwmacc/vwmaccu/vwmaccsu combine lowering optmization

Fix according to comments from Robin of V1 patch.

This patch add combine optimization for following case:
__attribute__ ((noipa)) void
vwmaccsu (int16_t *__restrict dst, int8_t *__restrict a, uint8_t *__restrict b,
	  int n)
{
  for (int i = 0; i < n; i++)
    dst[i] += (int16_t) a[i] * (int16_t) b[i];
}

Before this patch:
...
vsext.vf2
vzext.vf2
vmadd.vv
..

After this patch:
...
vwmaccsu.vv
...

gcc/ChangeLog:

	* config/riscv/autovec-opt.md (*<optab>_fma<mode>): New pattern.
	(*single_<optab>mult_plus<mode>): Ditto.
	(*double_<optab>mult_plus<mode>): Ditto.
	(*sign_zero_extend_fma): Ditto.
	(*zero_sign_extend_fma): Ditto.
	* config/riscv/riscv-protos.h (enum insn_type): New enum.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/autovec/widen/widen-8.c: New test.
	* gcc.target/riscv/rvv/autovec/widen/widen-9.c: New test.
	* gcc.target/riscv/rvv/autovec/widen/widen-complicate-5.c: New test.
	* gcc.target/riscv/rvv/autovec/widen/widen-complicate-6.c: New test.
	* gcc.target/riscv/rvv/autovec/widen/widen_run-8.c: New test.
	* gcc.target/riscv/rvv/autovec/widen/widen_run-9.c: New test.
This commit is contained in:
Juzhe-Zhong 2023-06-06 20:04:33 +08:00 committed by Pan Li
parent 4ede915d5d
commit 88604bd17c
8 changed files with 346 additions and 0 deletions

View file

@ -170,3 +170,163 @@
}
[(set_attr "type" "vmalu")
(set_attr "mode" "<MODE>")])
;; =========================================================================
;; == Widening Ternary arithmetic
;; =========================================================================
;; -------------------------------------------------------------------------
;; ---- [INT] VWMACC
;; -------------------------------------------------------------------------
;; Includes:
;; - vwmacc.vv
;; - vwmaccu.vv
;; -------------------------------------------------------------------------
;; Combine ext + ext + fma ===> widen fma.
;; Most of circumstantces, LoopVectorizer will generate the following IR:
;; vect__8.64_40 = (vector([4,4]) int) vect__7.63_41;
;; vect__11.68_35 = (vector([4,4]) int) vect__10.67_36;
;; vect__13.70_33 = .FMA (vect__11.68_35, vect__8.64_40, vect__4.60_45);
(define_insn_and_split "*<optab>_fma<mode>"
[(set (match_operand:VWEXTI 0 "register_operand")
(plus:VWEXTI
(mult:VWEXTI
(any_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
(any_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
(match_operand:VWEXTI 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
riscv_vector::emit_vlmax_ternary_insn (code_for_pred_widen_mul_plus (<CODE>, <MODE>mode),
riscv_vector::RVV_WIDEN_TERNOP, operands);
DONE;
}
[(set_attr "type" "viwmuladd")
(set_attr "mode" "<V_DOUBLE_TRUNC>")])
;; This helps to match ext + fma.
(define_insn_and_split "*single_<optab>mult_plus<mode>"
[(set (match_operand:VWEXTI 0 "register_operand")
(plus:VWEXTI
(mult:VWEXTI
(any_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
(match_operand:VWEXTI 3 "register_operand"))
(match_operand:VWEXTI 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
rtx tmp = gen_reg_rtx (<MODE>mode);
rtx ext_ops[] = {tmp, operands[2]};
riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ext_ops);
rtx dst = expand_ternary_op (<MODE>mode, fma_optab, tmp, operands[3],
operands[1], operands[0], 0);
emit_move_insn (operands[0], dst);
DONE;
}
[(set_attr "type" "viwmuladd")
(set_attr "mode" "<V_DOUBLE_TRUNC>")])
;; Combine ext + ext + mult + plus ===> widen fma.
;; We have some special cases generated by LoopVectorizer:
;; vect__8.18_46 = (vector([8,8]) signed short) vect__7.17_47;
;; vect__11.22_41 = (vector([8,8]) signed short) vect__10.21_42;
;; vect__12.23_40 = vect__11.22_41 * vect__8.18_46;
;; vect__14.25_38 = vect__13.24_39 + vect__5.14_51;
;; This situation doesn't generate FMA IR.
(define_insn_and_split "*double_<optab>mult_plus<mode>"
[(set (match_operand:VWEXTI 0 "register_operand")
(if_then_else:VWEXTI
(unspec:<VM>
[(match_operand:<VM> 1 "vector_mask_operand")
(match_operand 6 "vector_length_operand")
(match_operand 7 "const_int_operand")
(match_operand 8 "const_int_operand")
(match_operand 9 "const_int_operand")
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
(plus:VWEXTI
(if_then_else:VWEXTI
(unspec:<VM>
[(match_dup 1)
(match_dup 6)
(match_dup 7)
(match_dup 8)
(match_dup 9)
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
(mult:VWEXTI
(any_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 4 "register_operand"))
(any_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 5 "register_operand")))
(match_operand:VWEXTI 2 "vector_undef_operand"))
(match_operand:VWEXTI 3 "register_operand"))
(match_dup 2)))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
emit_insn (gen_pred_widen_mul_plus (<CODE>, <MODE>mode, operands[0],
operands[1], operands[3], operands[4],
operands[5], operands[6], operands[7],
operands[8], operands[9]));
DONE;
}
[(set_attr "type" "viwmuladd")
(set_attr "mode" "<V_DOUBLE_TRUNC>")])
;; Combine sign_extend + zero_extend + fma ===> widen fma (su).
(define_insn_and_split "*sign_zero_extend_fma"
[(set (match_operand:VWEXTI 0 "register_operand")
(plus:VWEXTI
(mult:VWEXTI
(sign_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
(zero_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
(match_operand:VWEXTI 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
riscv_vector::emit_vlmax_ternary_insn (code_for_pred_widen_mul_plussu (<MODE>mode),
riscv_vector::RVV_WIDEN_TERNOP, operands);
DONE;
}
[(set_attr "type" "viwmuladd")
(set_attr "mode" "<V_DOUBLE_TRUNC>")])
;; This helps to match zero_extend + sign_extend + fma.
(define_insn_and_split "*zero_sign_extend_fma"
[(set (match_operand:VWEXTI 0 "register_operand")
(plus:VWEXTI
(mult:VWEXTI
(zero_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))
(sign_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
(match_operand:VWEXTI 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
rtx ops[] = {operands[0], operands[1], operands[3], operands[2]};
riscv_vector::emit_vlmax_ternary_insn (code_for_pred_widen_mul_plussu (<MODE>mode),
riscv_vector::RVV_WIDEN_TERNOP, ops);
DONE;
}
[(set_attr "type" "viwmuladd")
(set_attr "mode" "<V_DOUBLE_TRUNC>")])

View file

@ -143,6 +143,7 @@ enum insn_type
RVV_CMP_MU_OP = RVV_CMP_OP + 2, /* +2 means mask and maskoff operand. */
RVV_UNOP_MU = RVV_UNOP + 2, /* Likewise. */
RVV_TERNOP = 5,
RVV_WIDEN_TERNOP = 4,
RVV_SCALAR_MOV_OP = 4, /* +1 for VUNDEF according to vector.md. */
};
enum vlmul_type

View file

@ -0,0 +1,27 @@
/* { dg-do compile } */
/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */
#include <stdint-gcc.h>
#define TEST_TYPE(TYPE1, TYPE2) \
__attribute__ ((noipa)) void vwmacc_##TYPE1_##TYPE2 (TYPE1 *__restrict dst, \
TYPE2 *__restrict a, \
TYPE2 *__restrict b, \
int n) \
{ \
for (int i = 0; i < n; i++) \
dst[i] += (TYPE1) a[i] * (TYPE1) b[i]; \
}
#define TEST_ALL() \
TEST_TYPE (int16_t, int8_t) \
TEST_TYPE (uint16_t, uint8_t) \
TEST_TYPE (int32_t, int16_t) \
TEST_TYPE (uint32_t, uint16_t) \
TEST_TYPE (int64_t, int32_t) \
TEST_TYPE (uint64_t, uint32_t)
TEST_ALL ()
/* { dg-final { scan-assembler-times {\tvwmacc\.vv} 3 } } */
/* { dg-final { scan-assembler-times {\tvwmaccu\.vv} 3 } } */

View file

@ -0,0 +1,23 @@
/* { dg-do compile } */
/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */
#include <stdint-gcc.h>
#define TEST_TYPE(TYPE1, TYPE2, TYPE3) \
__attribute__ ((noipa)) void vwmacc_##TYPE1_##TYPE2 (TYPE1 *__restrict dst, \
TYPE2 *__restrict a, \
TYPE3 *__restrict b, \
int n) \
{ \
for (int i = 0; i < n; i++) \
dst[i] += (TYPE1) a[i] * (TYPE1) b[i]; \
}
#define TEST_ALL() \
TEST_TYPE (int16_t, int8_t, uint8_t) \
TEST_TYPE (int32_t, int16_t, uint16_t) \
TEST_TYPE (int64_t, int32_t, uint32_t)
TEST_ALL ()
/* { dg-final { scan-assembler-times {\tvwmaccsu\.vv} 3 } } */

View file

@ -0,0 +1,32 @@
/* { dg-do compile } */
/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */
#include <stdint-gcc.h>
#define TEST_TYPE(TYPE1, TYPE2) \
__attribute__ ((noipa)) void vwadd_##TYPE1_##TYPE2 ( \
TYPE1 *__restrict dst, TYPE1 *__restrict dst2, TYPE1 *__restrict dst3, \
TYPE1 *__restrict dst4, TYPE2 *__restrict a, TYPE2 *__restrict b, \
TYPE2 *__restrict a2, TYPE2 *__restrict b2, int n) \
{ \
for (int i = 0; i < n; i++) \
{ \
dst[i] += (TYPE1) a[i] * (TYPE1) b[i]; \
dst2[i] += (TYPE1) a2[i] * (TYPE1) b[i]; \
dst3[i] += (TYPE1) a2[i] * (TYPE1) a[i]; \
dst4[i] += (TYPE1) a[i] * (TYPE1) b2[i]; \
} \
}
#define TEST_ALL() \
TEST_TYPE (int16_t, int8_t) \
TEST_TYPE (uint16_t, uint8_t) \
TEST_TYPE (int32_t, int16_t) \
TEST_TYPE (uint32_t, uint16_t) \
TEST_TYPE (int64_t, int32_t) \
TEST_TYPE (uint64_t, uint32_t)
TEST_ALL ()
/* { dg-final { scan-assembler-times {\tvwmacc\.vv} 12 } } */
/* { dg-final { scan-assembler-times {\tvwmaccu\.vv} 12 } } */

View file

@ -0,0 +1,30 @@
/* { dg-do compile } */
/* { dg-additional-options "-march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=scalable" } */
#include <stdint-gcc.h>
#define TEST_TYPE(TYPE1, TYPE2, TYPE3) \
__attribute__ ((noipa)) void vwadd_##TYPE1_##TYPE2 ( \
TYPE1 *__restrict dst, TYPE1 *__restrict dst2, TYPE1 *__restrict dst3, \
TYPE1 *__restrict dst4, TYPE2 *__restrict a, TYPE3 *__restrict b, \
TYPE3 *__restrict a2, TYPE2 *__restrict b2, int n) \
{ \
for (int i = 0; i < n; i++) \
{ \
dst[i] += (TYPE1) a[i] * (TYPE1) b[i]; \
dst2[i] += (TYPE1) a2[i] * (TYPE1) b[i]; \
dst3[i] += (TYPE1) a2[i] * (TYPE1) a[i]; \
dst4[i] += (TYPE1) a[i] * (TYPE1) b2[i]; \
} \
}
#define TEST_ALL() \
TEST_TYPE (int16_t, int8_t, uint8_t) \
TEST_TYPE (int32_t, int16_t, uint16_t) \
TEST_TYPE (int64_t, int32_t, uint32_t)
TEST_ALL ()
/* { dg-final { scan-assembler-times {\tvwmaccsu\.vv} 6 } } */
/* { dg-final { scan-assembler-times {\tvwmacc\.vv} 3 } } */
/* { dg-final { scan-assembler-times {\tvwmaccu\.vv} 3 } } */

View file

@ -0,0 +1,38 @@
/* { dg-do run { target { riscv_vector } } } */
/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */
#include <assert.h>
#include "widen-8.c"
#define SZ 512
#define RUN(TYPE1, TYPE2, LIMIT) \
TYPE2 a##TYPE2[SZ]; \
TYPE2 b##TYPE2[SZ]; \
TYPE1 dst##TYPE1[SZ]; \
TYPE1 dst2##TYPE1[SZ]; \
for (int i = 0; i < SZ; i++) \
{ \
a##TYPE2[i] = LIMIT + i % 8723; \
b##TYPE2[i] = LIMIT + i & 1964; \
dst##TYPE1[i] = LIMIT + i & 628; \
dst2##TYPE1[i] = LIMIT + i & 628; \
} \
vwmacc_##TYPE1_##TYPE2 (dst##TYPE1, a##TYPE2, b##TYPE2, SZ); \
for (int i = 0; i < SZ; i++) \
assert (dst##TYPE1[i] \
== ((TYPE1) a##TYPE2[i] * (TYPE1) b##TYPE2[i]) + dst2##TYPE1[i]);
#define RUN_ALL() \
RUN (int16_t, int8_t, -128) \
RUN (uint16_t, uint8_t, 255) \
RUN (int32_t, int16_t, -32768) \
RUN (uint32_t, uint16_t, 65535) \
RUN (int64_t, int32_t, -2147483648) \
RUN (uint64_t, uint32_t, 4294967295)
int
main ()
{
RUN_ALL ()
}

View file

@ -0,0 +1,35 @@
/* { dg-do run { target { riscv_vector } } } */
/* { dg-additional-options "--param=riscv-autovec-preference=scalable" } */
#include <assert.h>
#include "widen-9.c"
#define SZ 512
#define RUN(TYPE1, TYPE2, TYPE3, LIMIT) \
TYPE2 a##TYPE2[SZ]; \
TYPE3 b##TYPE3[SZ]; \
TYPE1 dst##TYPE1[SZ]; \
TYPE1 dst2##TYPE1[SZ]; \
for (int i = 0; i < SZ; i++) \
{ \
a##TYPE2[i] = LIMIT + i % 8723; \
b##TYPE3[i] = LIMIT + i & 1964; \
dst##TYPE1[i] = LIMIT + i & 728; \
dst2##TYPE1[i] = LIMIT + i & 728; \
} \
vwmacc_##TYPE1_##TYPE2 (dst##TYPE1, a##TYPE2, b##TYPE3, SZ); \
for (int i = 0; i < SZ; i++) \
assert (dst##TYPE1[i] \
== ((TYPE1) a##TYPE2[i] * (TYPE1) b##TYPE3[i]) + dst2##TYPE1[i]);
#define RUN_ALL() \
RUN (int16_t, int8_t, uint8_t, -128) \
RUN (int32_t, int16_t, uint16_t, -32768) \
RUN (int64_t, int32_t, uint32_t, -2147483648)
int
main ()
{
RUN_ALL ()
}