diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md index d9863c76654..3aaee54f02a 100644 --- a/gcc/config/riscv/autovec-opt.md +++ b/gcc/config/riscv/autovec-opt.md @@ -18,67 +18,6 @@ ;; along with GCC; see the file COPYING3. If not see ;; . -;; We don't have vwmul.wv instruction like vwadd.wv in RVV. -;; This pattern is an intermediate RTL IR as a pseudo vwmul.wv to enhance -;; optimization of instructions combine. -(define_insn_and_split "@pred_single_widen_mul" - [(set (match_operand:VWEXTI 0 "register_operand" "=&vr,&vr") - (if_then_else:VWEXTI - (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 5 "vector_length_operand" " rK, rK") - (match_operand 6 "const_int_operand" " i, i") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (reg:SI VL_REGNUM) - (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (mult:VWEXTI - (any_extend:VWEXTI - (match_operand: 4 "register_operand" " vr, vr")) - (match_operand:VWEXTI 3 "register_operand" " vr, vr")) - (match_operand:VWEXTI 2 "vector_merge_operand" " vu, 0")))] - "TARGET_VECTOR && can_create_pseudo_p ()" - "#" - "&& 1" - [(const_int 0)] - { - insn_code icode = code_for_pred_vf2 (, mode); - rtx tmp = gen_reg_rtx (mode); - rtx ops[] = {tmp, operands[4]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ops); - - emit_insn (gen_pred (MULT, mode, operands[0], operands[1], operands[2], - operands[3], tmp, operands[5], operands[6], - operands[7], operands[8])); - DONE; - } - [(set_attr "type" "viwmul") - (set_attr "mode" "")]) - -;; This pattern it to enchance the instruction combine optimizations for complicate -;; sign and unsigned widening multiplication operations. -(define_insn "*pred_widen_mulsu" - [(set (match_operand:VWEXTI 0 "register_operand" "=&vr,&vr") - (if_then_else:VWEXTI - (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 5 "vector_length_operand" " rK, rK") - (match_operand 6 "const_int_operand" " i, i") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (reg:SI VL_REGNUM) - (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE) - (mult:VWEXTI - (zero_extend:VWEXTI - (match_operand: 4 "register_operand" " vr, vr")) - (sign_extend:VWEXTI - (match_operand: 3 "register_operand" " vr, vr"))) - (match_operand:VWEXTI 2 "vector_merge_operand" " vu, 0")))] - "TARGET_VECTOR" - "vwmulsu.vv\t%0,%3,%4%p1" - [(set_attr "type" "viwmul") - (set_attr "mode" "")]) - ;; ----------------------------------------------------------------------------- ;; ---- Integer Compare Instructions Simplification ;; ----------------------------------------------------------------------------- @@ -406,45 +345,6 @@ [(set_attr "type" "vimovvx") (set_attr "mode" "")]) -;; We don't have vfwmul.wv instruction like vfwadd.wv in RVV. -;; This pattern is an intermediate RTL IR as a pseudo vfwmul.wv to enhance -;; optimization of instructions combine. -(define_insn_and_split "*pred_single_widen_mul" - [(set (match_operand:VWEXTF 0 "register_operand" "=&vr, &vr") - (if_then_else:VWEXTF - (unspec: - [(match_operand: 1 "vector_mask_operand" "vmWc1,vmWc1") - (match_operand 5 "vector_length_operand" " rK, rK") - (match_operand 6 "const_int_operand" " i, i") - (match_operand 7 "const_int_operand" " i, i") - (match_operand 8 "const_int_operand" " i, i") - (match_operand 9 "const_int_operand" " i, i") - (reg:SI VL_REGNUM) - (reg:SI VTYPE_REGNUM) - (reg:SI FRM_REGNUM)] UNSPEC_VPREDICATE) - (mult:VWEXTF - (float_extend:VWEXTF - (match_operand: 4 "register_operand" " vr, vr")) - (match_operand:VWEXTF 3 "register_operand" " vr, vr")) - (match_operand:VWEXTF 2 "vector_merge_operand" " vu, 0")))] - "TARGET_VECTOR && can_create_pseudo_p ()" - "#" - "&& 1" - [(const_int 0)] - { - insn_code icode = code_for_pred_extend (mode); - rtx tmp = gen_reg_rtx (mode); - rtx ops[] = {tmp, operands[4]}; - riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, ops); - - emit_insn (gen_pred (MULT, mode, operands[0], operands[1], operands[2], - operands[3], tmp, operands[5], operands[6], - operands[7], operands[8], operands[9])); - DONE; - } - [(set_attr "type" "vfwmul") - (set_attr "mode" "")]) - ;; ------------------------------------------------------------------------- ;; ---- [FP] VFWMACC ;; ------------------------------------------------------------------------- @@ -845,7 +745,7 @@ DONE; }) -;; Combine FP sign_extend/zero_extend(vf2) and vcond_mask +;; Combine FP extend(vf2) and vcond_mask (define_insn_and_split "*cond_extend" [(set (match_operand:VWEXTF_ZVFHMIN 0 "register_operand") (if_then_else:VWEXTF_ZVFHMIN @@ -1003,3 +903,195 @@ riscv_vector::expand_cond_len_unop (icode, ops); DONE; }) + +;; ============================================================================= +;; Combine extend + binop to widen_binop +;; ============================================================================= + +(define_insn_and_split "*dual_widen_" + [(set (match_operand:VWEXTI 0 "register_operand") + (any_widen_binop:VWEXTI + (any_extend:VWEXTI + (match_operand: 1 "register_operand")) + (any_extend:VWEXTI + (match_operand: 2 "register_operand"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_dual_widen (, + , + mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); + DONE; +}) + +(define_insn_and_split "*single_widen_sub" + [(set (match_operand:VWEXTI 0 "register_operand") + (minus:VWEXTI + (match_operand:VWEXTI 1 "register_operand") + (any_extend:VWEXTI + (match_operand: 2 "register_operand"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_single_widen_sub (, + mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); + DONE; +}) + +(define_insn_and_split "*single_widen_add" + [(set (match_operand:VWEXTI 0 "register_operand") + (plus:VWEXTI + (any_extend:VWEXTI + (match_operand: 2 "register_operand")) + (match_operand:VWEXTI 1 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_single_widen_add (, + mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); + DONE; +}) + +;; This combine pattern does not correspond to an single instruction, +;; i.e. there is no vwmul.wv instruction. This is a temporary pattern +;; produced by a combine pass and if there is no further combine into +;; vwmul.vv pattern, then fall back to extend pattern and vmul.vv pattern. +(define_insn_and_split "*single_widen_mult" + [(set (match_operand:VWEXTI 0 "register_operand") + (mult:VWEXTI + (any_extend:VWEXTI + (match_operand: 2 "register_operand")) + (match_operand:VWEXTI 1 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code extend_icode = code_for_pred_vf2 (, mode); + rtx tmp = gen_reg_rtx (mode); + rtx extend_ops[] = {tmp, operands[2]}; + riscv_vector::emit_vlmax_insn (extend_icode, riscv_vector::UNARY_OP, extend_ops); + + rtx ops[] = {operands[0], operands[1], tmp}; + insn_code icode = code_for_pred (MULT, mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops); + DONE; +}) + +(define_insn_and_split "*dual_widen_mulsu" + [(set (match_operand:VWEXTI 0 "register_operand") + (mult:VWEXTI + (sign_extend:VWEXTI + (match_operand: 1 "register_operand")) + (zero_extend:VWEXTI + (match_operand: 2 "register_operand"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_widen_mulsu (mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); + DONE; +}) + +(define_insn_and_split "*dual_widen_mulus" + [(set (match_operand:VWEXTI 0 "register_operand") + (mult:VWEXTI + (zero_extend:VWEXTI + (match_operand: 2 "register_operand")) + (sign_extend:VWEXTI + (match_operand: 1 "register_operand"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_widen_mulsu (mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); + DONE; +}) + +(define_insn_and_split "*dual_widen_" + [(set (match_operand:VWEXTF 0 "register_operand") + (any_widen_binop:VWEXTF + (float_extend:VWEXTF + (match_operand: 1 "register_operand")) + (float_extend:VWEXTF + (match_operand: 2 "register_operand"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_dual_widen (, mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_FRM_DYN, operands); + DONE; +}) + +(define_insn_and_split "*single_widen_add" + [(set (match_operand:VWEXTF 0 "register_operand") + (plus:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand")) + (match_operand:VWEXTF 1 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_single_widen_add (mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_FRM_DYN, operands); + DONE; +}) + +(define_insn_and_split "*single_widen_sub" + [(set (match_operand:VWEXTF 0 "register_operand") + (minus:VWEXTF + (match_operand:VWEXTF 1 "register_operand") + (float_extend:VWEXTF + (match_operand: 2 "register_operand"))))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code icode = code_for_pred_single_widen_sub (mode); + riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_FRM_DYN, operands); + DONE; +}) + +;; This combine pattern does not correspond to an single instruction, +;; i.e. there is no vfwmul.wv instruction. This is a temporary pattern +;; produced by a combine pass and if there is no further combine into +;; vfwmul.vv pattern, then fall back to extend pattern and vfmul.vv pattern. +(define_insn_and_split "*single_widen_mult" + [(set (match_operand:VWEXTF 0 "register_operand") + (mult:VWEXTF + (float_extend:VWEXTF + (match_operand: 2 "register_operand")) + (match_operand:VWEXTF 1 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + insn_code extend_icode = code_for_pred_extend (mode); + rtx tmp = gen_reg_rtx (mode); + rtx extend_ops[] = {tmp, operands[2]}; + riscv_vector::emit_vlmax_insn (extend_icode, riscv_vector::UNARY_OP, extend_ops); + + rtx ops[] = {operands[0], operands[1], tmp}; + riscv_vector::emit_vlmax_insn (code_for_pred (MULT, mode), + riscv_vector::BINARY_OP_FRM_DYN, ops); + DONE; +}) diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index c220fda312e..98cd0c07625 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -419,12 +419,15 @@ ;; - vadd.vi/vsub.vi/... ;; ------------------------------------------------------------------------- -(define_expand "3" +(define_insn_and_split "3" [(set (match_operand:VI 0 "register_operand") (any_int_binop_no_shift:VI (match_operand:VI 1 "") (match_operand:VI 2 "")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { riscv_vector::emit_vlmax_insn (code_for_pred (, mode), riscv_vector::BINARY_OP, operands); @@ -937,11 +940,14 @@ ;; Includes: ;; - vneg.v/vnot.v ;; ------------------------------------------------------------------------------- -(define_expand "2" +(define_insn_and_split "2" [(set (match_operand:VI 0 "register_operand") (any_int_unop:VI (match_operand:VI 1 "register_operand")))] - "TARGET_VECTOR" + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred (, mode); riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands); @@ -952,10 +958,14 @@ ;; - [INT] ABS expansion to vmslt and vneg. ;; ------------------------------------------------------------------------------- -(define_expand "abs2" +(define_insn_and_split "abs2" [(set (match_operand:VI 0 "register_operand") - (match_operand:VI 1 "register_operand"))] - "TARGET_VECTOR" + (abs:VI + (match_operand:VI 1 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { rtx zero = gen_const_vec_duplicate (mode, GEN_INT (0)); machine_mode mask_mode = riscv_vector::get_mask_mode (mode); @@ -1457,12 +1467,15 @@ ;; - vfadd.vv/vfsub.vv/... ;; - vfadd.vf/vfsub.vf/... ;; ------------------------------------------------------------------------- -(define_expand "3" - [(match_operand:VF 0 "register_operand") - (any_float_binop:VF - (match_operand:VF 1 "register_operand") - (match_operand:VF 2 "register_operand"))] - "TARGET_VECTOR" +(define_insn_and_split "3" + [(set (match_operand:VF 0 "register_operand") + (any_float_binop:VF + (match_operand:VF 1 "register_operand") + (match_operand:VF 2 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { riscv_vector::emit_vlmax_insn (code_for_pred (, mode), riscv_vector::BINARY_OP_FRM_DYN, operands); @@ -1474,12 +1487,15 @@ ;; - vfmin.vv/vfmax.vv ;; - vfmin.vf/vfmax.vf ;; ------------------------------------------------------------------------- -(define_expand "3" - [(match_operand:VF 0 "register_operand") - (any_float_binop_nofrm:VF - (match_operand:VF 1 "register_operand") - (match_operand:VF 2 "register_operand"))] - "TARGET_VECTOR" +(define_insn_and_split "3" + [(set (match_operand:VF 0 "register_operand") + (any_float_binop_nofrm:VF + (match_operand:VF 1 "register_operand") + (match_operand:VF 2 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { riscv_vector::emit_vlmax_insn (code_for_pred (, mode), riscv_vector::BINARY_OP, operands); @@ -1537,22 +1553,30 @@ ;; - vmulhu.vv ;; ------------------------------------------------------------------------- -(define_expand "smul3_highpart" - [(match_operand:VFULLI 0 "register_operand") - (match_operand:VFULLI 1 "register_operand") - (match_operand:VFULLI 2 "register_operand")] - "TARGET_VECTOR" +(define_insn_and_split "smul3_highpart" + [(set (match_operand:VFULLI 0 "register_operand") + (smul_highpart:VFULLI + (match_operand:VFULLI 1 "register_operand") + (match_operand:VFULLI 2 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_mulh (UNSPEC_VMULHS, mode); riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); DONE; }) -(define_expand "umul3_highpart" - [(match_operand:VFULLI 0 "register_operand") - (match_operand:VFULLI 1 "register_operand") - (match_operand:VFULLI 2 "register_operand")] - "TARGET_VECTOR" +(define_insn_and_split "umul3_highpart" + [(set (match_operand:VFULLI 0 "register_operand") + (umul_highpart:VFULLI + (match_operand:VFULLI 1 "register_operand") + (match_operand:VFULLI 2 "register_operand")))] + "TARGET_VECTOR && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] { insn_code icode = code_for_pred_mulh (UNSPEC_VMULHU, mode); riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, operands); diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr111232.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr111232.c new file mode 100644 index 00000000000..de815c5fac9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr111232.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=scalable -Ofast -fno-schedule-insns -fno-schedule-insns2" } */ + +#include + +int16_t +foo (int8_t *restrict x, int8_t *restrict y, int n) +{ + int16_t result = 0; + + for (int i = 0; i < n; i++) + { + result += (x[i] * y[i]); + } + return result; +} + +/* { dg-final { scan-assembler {\tvwmacc\.vv\tv[0-9]+,v[0-9]+,v[0-9]+} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-4.c index c29a74c4f8b..26f27ea6283 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-4.c @@ -16,8 +16,11 @@ #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_TYPE (int64_t, int32_t, uint32_t) \ + TEST_TYPE (int16_t, uint8_t, int8_t) \ + TEST_TYPE (int32_t, uint16_t, int16_t) \ + TEST_TYPE (int64_t, uint32_t, int32_t) TEST_ALL () -/* { dg-final { scan-assembler-times {\tvwmulsu\.vv} 3 } } */ +/* { dg-final { scan-assembler-times {\tvwmulsu\.vv} 6 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-complicate-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-complicate-4.c index 15fdefc550b..aeac4cb79c2 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-complicate-4.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/widen/widen-complicate-4.c @@ -21,11 +21,14 @@ #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_TYPE (int64_t, int32_t, uint32_t) \ + TEST_TYPE (int16_t, uint8_t, int8_t) \ + TEST_TYPE (int32_t, uint16_t, int16_t) \ + TEST_TYPE (int64_t, uint32_t, int32_t) TEST_ALL () -/* { dg-final { scan-assembler-times {\tvwmulsu\.vv} 6 } } */ -/* { dg-final { scan-assembler-times {\tvwmul\.vv} 3 } } */ -/* { dg-final { scan-assembler-times {\tvwmulu\.vv} 3 } } */ +/* { dg-final { scan-assembler-times {\tvwmulsu\.vv} 12 } } */ +/* { dg-final { scan-assembler-times {\tvwmul\.vv} 6 } } */ +/* { dg-final { scan-assembler-times {\tvwmulu\.vv} 6 } } */ /* { dg-final { scan-assembler-not {\tvmul} } } */