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 (<optab><mode>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 <collison@rivosinc.com>
This commit is contained in:
parent
af595613ac
commit
b75c9e1037
3 changed files with 127 additions and 68 deletions
|
@ -82,3 +82,40 @@
|
|||
DONE;
|
||||
}
|
||||
)
|
||||
|
||||
;; ========================================================================
|
||||
;; == Vector operations
|
||||
;; =========================================================================
|
||||
|
||||
;; -------------------------------------------------------------------------
|
||||
;; ---- [INT] Binary operations
|
||||
;; -------------------------------------------------------------------------
|
||||
;; Includes:
|
||||
;; - vadd.vv/vsub.vv/...
|
||||
;; - vadd.vi/vsub.vi/...
|
||||
;; -------------------------------------------------------------------------
|
||||
|
||||
(define_expand "<optab><mode>3"
|
||||
[(set (match_operand:VI 0 "register_operand")
|
||||
(any_int_binop:VI
|
||||
(match_operand:VI 1 "<binop_rhs1_predicate>")
|
||||
(match_operand:VI 2 "<binop_rhs2_predicate>")))]
|
||||
"TARGET_VECTOR"
|
||||
{
|
||||
if (!register_operand (operands[2], <MODE>mode))
|
||||
{
|
||||
rtx cst;
|
||||
gcc_assert (const_vec_duplicate_p(operands[2], &cst));
|
||||
riscv_vector::emit_nonvlmax_binop (code_for_pred_scalar
|
||||
(<CODE>, <MODE>mode),
|
||||
operands[0], operands[1], cst,
|
||||
NULL, <VM>mode,
|
||||
<VEL>mode);
|
||||
}
|
||||
else
|
||||
riscv_vector::emit_nonvlmax_binop (code_for_pred
|
||||
(<CODE>, <MODE>mode),
|
||||
operands[0], operands[1], operands[2],
|
||||
NULL, <VM>mode);
|
||||
DONE;
|
||||
})
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace riscv_vector {
|
|||
template <int MAX_OPERANDS> 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue