[v2] RISC-V: Add vectorized binops and insn_expander helpers.

Message ID c510c333-a863-6aa0-5a40-5177d5b45094@gmail.com
State Accepted
Headers
Series [v2] RISC-V: Add vectorized binops and insn_expander helpers. |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Robin Dapp May 11, 2023, 10:26 a.m. UTC
  Changes from v1:

 - Rebase against Juzhe's vec_series patch.
 - Get rid of redundant scalar mode setting.


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     |  37 ++++++++
 gcc/config/riscv/riscv-protos.h |   2 +
 gcc/config/riscv/riscv-v.cc     | 148 ++++++++++++++++++--------------
 3 files changed, 123 insertions(+), 64 deletions(-)
  

Comments

juzhe.zhong@rivai.ai May 11, 2023, 10:34 a.m. UTC | #1
LGTM. You should commit it now. Then I can rebase vec_init patch.



juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-11 18:26
To: 钟居哲; gcc-patches; kito.cheng; Michael Collison; palmer; Jeff Law
CC: rdapp.gcc
Subject: [PATCH v2] RISC-V: Add vectorized binops and insn_expander helpers.
Changes from v1:
 
- Rebase against Juzhe's vec_series patch.
- Get rid of redundant scalar mode setting.
 
 
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     |  37 ++++++++
gcc/config/riscv/riscv-protos.h |   2 +
gcc/config/riscv/riscv-v.cc     | 148 ++++++++++++++++++--------------
3 files changed, 123 insertions(+), 64 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 @@ (define_expand "@vec_series<mode>"
     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;
+})
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 <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);
     }
}
-- 
2.40.0
  
Robin Dapp May 11, 2023, 10:36 a.m. UTC | #2
> LGTM. You should commit it now. Then I can rebase vec_init patch.

Would need an ACK/OK from Kito at least :)
  
juzhe.zhong@rivai.ai May 11, 2023, 10:38 a.m. UTC | #3
I just saw Kito has LGTM in V1 patch. 
Let's wait for Kito LGTM for V2.



juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-11 18:36
To: juzhe.zhong@rivai.ai; gcc-patches; kito.cheng; collison; palmer; jeffreyalaw
Subject: Re: [PATCH v2] RISC-V: Add vectorized binops and insn_expander helpers.
> LGTM. You should commit it now. Then I can rebase vec_init patch.
 
Would need an ACK/OK from Kito at least :)
  
Kito Cheng May 11, 2023, 11:09 a.m. UTC | #4
LGTM for v2 as well :)

juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai> 於 2023年5月11日 週四 18:39 寫道:

> I just saw Kito has LGTM in V1 patch.
> Let's wait for Kito LGTM for V2.
>
>
>
> juzhe.zhong@rivai.ai
>
> From: Robin Dapp
> Date: 2023-05-11 18:36
> To: juzhe.zhong@rivai.ai; gcc-patches; kito.cheng; collison; palmer;
> jeffreyalaw
> Subject: Re: [PATCH v2] RISC-V: Add vectorized binops and insn_expander
> helpers.
> > LGTM. You should commit it now. Then I can rebase vec_init patch.
>
> Would need an ACK/OK from Kito at least :)
>
>
  

Patch

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 @@  (define_expand "@vec_series<mode>"
     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;
+})
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 <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);
     }
 }