From b75c9e10379481b1b1e9dfdcc6aa81c9ba58cb1a Mon Sep 17 00:00:00 2001 From: Robin Dapp Date: Mon, 24 Apr 2023 08:27:52 +0200 Subject: [PATCH] RISC-V: Add vectorized binops and insn_expander helpers. This patch adds basic binary integer operations support. It is based on Michael Collison's work and makes use of the existing helpers in riscv-c.cc. It introduces emit_nonvlmax_binop which, in turn, uses emit_pred_binop. Setting the destination as well as the mask and the length are factored out into separate functions. gcc/ChangeLog: * config/riscv/autovec.md (3): Add integer binops. * config/riscv/riscv-protos.h (emit_nonvlmax_binop): Declare. * config/riscv/riscv-v.cc (emit_pred_op): New function. (set_expander_dest_and_mask): New function. (emit_pred_binop): New function. (emit_nonvlmax_binop): New function. Co-authored-by: Michael Collison --- gcc/config/riscv/autovec.md | 37 ++++++++ gcc/config/riscv/riscv-protos.h | 2 + gcc/config/riscv/riscv-v.cc | 156 ++++++++++++++++++-------------- 3 files changed, 127 insertions(+), 68 deletions(-) diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index 99dc4f046b0..e249f4be704 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -82,3 +82,40 @@ DONE; } ) + +;; ======================================================================== +;; == Vector operations +;; ========================================================================= + +;; ------------------------------------------------------------------------- +;; ---- [INT] Binary operations +;; ------------------------------------------------------------------------- +;; Includes: +;; - vadd.vv/vsub.vv/... +;; - vadd.vi/vsub.vi/... +;; ------------------------------------------------------------------------- + +(define_expand "3" + [(set (match_operand:VI 0 "register_operand") + (any_int_binop:VI + (match_operand:VI 1 "") + (match_operand:VI 2 "")))] + "TARGET_VECTOR" +{ + if (!register_operand (operands[2], mode)) + { + rtx cst; + gcc_assert (const_vec_duplicate_p(operands[2], &cst)); + riscv_vector::emit_nonvlmax_binop (code_for_pred_scalar + (, mode), + operands[0], operands[1], cst, + NULL, mode, + mode); + } + else + riscv_vector::emit_nonvlmax_binop (code_for_pred + (, mode), + operands[0], operands[1], operands[2], + NULL, mode); + DONE; +}) diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index e8a728ae226..4d0589e502c 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -169,6 +169,8 @@ void emit_hard_vlmax_vsetvl (machine_mode, rtx); void emit_vlmax_op (unsigned, rtx, rtx, machine_mode); void emit_vlmax_op (unsigned, rtx, rtx, rtx, machine_mode); void emit_nonvlmax_op (unsigned, rtx, rtx, rtx, machine_mode); +void emit_nonvlmax_binop (unsigned, rtx, rtx, rtx, rtx, machine_mode, + machine_mode = VOIDmode); enum vlmul_type get_vlmul (machine_mode); unsigned int get_ratio (machine_mode); unsigned int get_nf (machine_mode); diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 381e6601a17..8f46226d571 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -53,7 +53,7 @@ namespace riscv_vector { template class insn_expander { public: - insn_expander () : m_opno (0) {} + insn_expander () : m_opno (0), has_dest(false) {} void add_output_operand (rtx x, machine_mode mode) { create_output_operand (&m_ops[m_opno++], x, mode); @@ -84,6 +84,44 @@ public: add_input_operand (gen_int_mode (type, Pmode), Pmode); } + void set_dest_and_mask (rtx mask, rtx dest, machine_mode mask_mode) + { + dest_mode = GET_MODE (dest); + has_dest = true; + + add_output_operand (dest, dest_mode); + + if (mask) + add_input_operand (mask, GET_MODE (mask)); + else + add_all_one_mask_operand (mask_mode); + + add_vundef_operand (dest_mode); + } + + void set_len_and_policy (rtx len, bool vlmax_p) + { + gcc_assert (has_dest); + gcc_assert (len || vlmax_p); + + if (len) + add_input_operand (len, Pmode); + else + { + rtx vlmax = gen_reg_rtx (Pmode); + emit_vlmax_vsetvl (dest_mode, vlmax); + add_input_operand (vlmax, Pmode); + } + + if (GET_MODE_CLASS (dest_mode) != MODE_VECTOR_BOOL) + add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ()); + + if (vlmax_p) + add_avl_type_operand (avl_type::VLMAX); + else + add_avl_type_operand (avl_type::NONVLMAX); + } + void expand (enum insn_code icode, bool temporary_volatile_p = false) { if (temporary_volatile_p) @@ -97,6 +135,8 @@ public: private: int m_opno; + bool has_dest; + machine_mode dest_mode; expand_operand m_ops[MAX_OPERANDS]; }; @@ -195,39 +235,43 @@ emit_pred_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len, machine_mode mask_mode, bool vlmax_p) { insn_expander<8> e; - machine_mode mode = GET_MODE (dest); - - e.add_output_operand (dest, mode); - - if (mask) - e.add_input_operand (mask, GET_MODE (mask)); - else - e.add_all_one_mask_operand (mask_mode); - - e.add_vundef_operand (mode); + e.set_dest_and_mask (mask, dest, mask_mode); e.add_input_operand (src, GET_MODE (src)); - if (len) - e.add_input_operand (len, Pmode); - else - { - rtx vlmax = gen_reg_rtx (Pmode); - emit_vlmax_vsetvl (mode, vlmax); - e.add_input_operand (vlmax, Pmode); - } - - if (GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL) - e.add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ()); - - if (vlmax_p) - e.add_avl_type_operand (avl_type::VLMAX); - else - e.add_avl_type_operand (avl_type::NONVLMAX); + e.set_len_and_policy (len, vlmax_p); e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src)); } +/* Emit an RVV binop. If one of SRC1 and SRC2 is a scalar operand, its mode is + specified using SCALAR_MODE. */ +static void +emit_pred_binop (unsigned icode, rtx mask, rtx dest, rtx src1, rtx src2, + rtx len, machine_mode mask_mode, machine_mode scalar_mode, + bool vlmax_p) +{ + insn_expander<9> e; + e.set_dest_and_mask (mask, dest, mask_mode); + + gcc_assert (VECTOR_MODE_P (GET_MODE (src1)) + || VECTOR_MODE_P (GET_MODE (src2))); + + if (VECTOR_MODE_P (GET_MODE (src1))) + e.add_input_operand (src1, GET_MODE (src1)); + else + e.add_input_operand (src1, scalar_mode); + + if (VECTOR_MODE_P (GET_MODE (src2))) + e.add_input_operand (src2, GET_MODE (src2)); + else + e.add_input_operand (src2, scalar_mode); + + e.set_len_and_policy (len, vlmax_p); + + e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src1) || MEM_P (src2)); +} + void emit_vlmax_op (unsigned icode, rtx dest, rtx src, machine_mode mask_mode) { @@ -248,49 +292,25 @@ emit_nonvlmax_op (unsigned icode, rtx dest, rtx src, rtx len, emit_pred_op (icode, NULL_RTX, dest, src, len, mask_mode, false); } -/* Emit binary operations. */ - -static void -emit_binop (unsigned icode, rtx *ops, machine_mode mask_mode, - machine_mode scalar_mode) +void +emit_nonvlmax_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len, + machine_mode mask_mode, machine_mode scalar_mode) { - insn_expander<9> e; - machine_mode mode = GET_MODE (ops[0]); - e.add_output_operand (ops[0], mode); - e.add_all_one_mask_operand (mask_mode); - e.add_vundef_operand (mode); - if (VECTOR_MODE_P (GET_MODE (ops[1]))) - e.add_input_operand (ops[1], GET_MODE (ops[1])); - else - e.add_input_operand (ops[1], scalar_mode); - if (VECTOR_MODE_P (GET_MODE (ops[2]))) - e.add_input_operand (ops[2], GET_MODE (ops[2])); - else - e.add_input_operand (ops[2], scalar_mode); - rtx vlmax = gen_reg_rtx (Pmode); - emit_vlmax_vsetvl (mode, vlmax); - e.add_input_operand (vlmax, Pmode); - e.add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ()); - e.add_avl_type_operand (avl_type::VLMAX); - e.expand ((enum insn_code) icode, false); + emit_pred_binop (icode, NULL_RTX, dest, src1, src2, len, mask_mode, + scalar_mode, len ? false : true); } /* Emit vid.v instruction. */ static void -emit_index_op (rtx target, machine_mode mask_mode) +emit_index_op (rtx dest, machine_mode mask_mode) { insn_expander<7> e; - machine_mode mode = GET_MODE (target); - e.add_output_operand (target, mode); - e.add_all_one_mask_operand (mask_mode); - e.add_vundef_operand (mode); - rtx vlmax = gen_reg_rtx (Pmode); - emit_vlmax_vsetvl (mode, vlmax); - e.add_input_operand (vlmax, Pmode); - e.add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ()); - e.add_avl_type_operand (avl_type::VLMAX); - e.expand (code_for_pred_series (mode), false); + e.set_dest_and_mask (NULL, dest, mask_mode); + + e.set_len_and_policy (NULL, true); + + e.expand (code_for_pred_series (GET_MODE (dest)), false); } /* Expand series const vector. */ @@ -324,15 +344,15 @@ expand_vec_series (rtx dest, rtx base, rtx step) /* Emit logical left shift operation. */ int shift = exact_log2 (INTVAL (step)); rtx shift_amount = gen_int_mode (shift, Pmode); - rtx ops[3] = {step_adj, vid, shift_amount}; insn_code icode = code_for_pred_scalar (ASHIFT, mode); - emit_binop (icode, ops, mask_mode, Pmode); + emit_nonvlmax_binop (icode, step_adj, vid, shift_amount, + NULL, mask_mode, Pmode); } else { - rtx ops[3] = {step_adj, vid, step}; insn_code icode = code_for_pred_scalar (MULT, mode); - emit_binop (icode, ops, mask_mode, inner_mode); + emit_nonvlmax_binop (icode, step_adj, vid, step, + NULL, mask_mode, inner_mode); } } @@ -346,9 +366,9 @@ expand_vec_series (rtx dest, rtx base, rtx step) else { rtx result = gen_reg_rtx (mode); - rtx ops[3] = {result, step_adj, base}; insn_code icode = code_for_pred_scalar (PLUS, mode); - emit_binop (icode, ops, mask_mode, inner_mode); + emit_nonvlmax_binop (icode, result, step_adj, base, + NULL, mask_mode, inner_mode); emit_move_insn (dest, result); } }