]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Add vectorized binops and insn_expander helpers.
authorRobin Dapp <rdapp@ventanamicro.com>
Mon, 24 Apr 2023 06:27:52 +0000 (08:27 +0200)
committerRobin Dapp <rdapp@ventanamicro.com>
Thu, 11 May 2023 12:23:26 +0000 (14:23 +0200)
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>
gcc/config/riscv/autovec.md
gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv-v.cc

index 99dc4f046b0c041e1be8c5c67c41f4bf3101219f..e249f4be7044155937581ccd7fac9e73de4621df 100644 (file)
     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;
+})
index e8a728ae226f4e566952ffa865fe77b082d2b07d..4d0589e502c4b08e6b9f1e77dbfb100d5afe936e 100644 (file)
@@ -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);
index 381e6601a174ddd426a0cca2d43bef05407214c8..8f46226d57138a24008e830164e5724fc5f8a4ba 100644 (file)
@@ -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,37 +235,41 @@ 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.set_dest_and_mask (mask, dest, mask_mode);
 
-  e.add_output_operand (dest, mode);
+  e.add_input_operand (src, GET_MODE (src));
 
-  if (mask)
-    e.add_input_operand (mask, GET_MODE (mask));
-  else
-    e.add_all_one_mask_operand (mask_mode);
+  e.set_len_and_policy (len, vlmax_p);
 
-  e.add_vundef_operand (mode);
+  e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src));
+}
 
-  e.add_input_operand (src, GET_MODE (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);
 
-  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);
-    }
+  gcc_assert (VECTOR_MODE_P (GET_MODE (src1))
+             || VECTOR_MODE_P (GET_MODE (src2)));
 
-  if (GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
-    e.add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ());
+  if (VECTOR_MODE_P (GET_MODE (src1)))
+    e.add_input_operand (src1, GET_MODE (src1));
+  else
+    e.add_input_operand (src1, scalar_mode);
 
-  if (vlmax_p)
-    e.add_avl_type_operand (avl_type::VLMAX);
+  if (VECTOR_MODE_P (GET_MODE (src2)))
+    e.add_input_operand (src2, GET_MODE (src2));
   else
-    e.add_avl_type_operand (avl_type::NONVLMAX);
+    e.add_input_operand (src2, scalar_mode);
 
-  e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src));
+  e.set_len_and_policy (len, vlmax_p);
+
+  e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src1) || MEM_P (src2));
 }
 
 void
@@ -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);
     }
 }