[V2] RISC-V: Add conditional autovec convert(INT<->INT) patterns

Message ID 20230825020520.3485365-1-lehua.ding@rivai.ai
State Unresolved
Headers
Series [V2] RISC-V: Add conditional autovec convert(INT<->INT) patterns |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Lehua Ding Aug. 25, 2023, 2:05 a.m. UTC
  V2 changes: Address comments from Robin.

Hi,

This patch adds conditional sign/zero extension and truncation autovec
patterns by combining convert and vcond_mask patterns.

For quad truncation, two vncvt instructions are generated. This patch
combine the second vncvt and vmerge to form a masked vncvt, while the
first vncvt remains unchanged. Of course, it is possible to convert the
first vncvt to the mask type as well, but I don't think it is necessary.
It is a similar story with 8x truncation.

--
Best,
Lehua

gcc/ChangeLog:

	* config/riscv/autovec-opt.md (*cond_<optab><v_double_trunc><mode>):
	Add combine pattern.
	(*cond_<optab><v_quad_trunc><mode>): Ditto.
	(*cond_<optab><v_oct_trunc><mode>): Ditto.
	(*cond_trunc<mode><v_double_trunc>): Ditto.
	* config/riscv/autovec.md (<optab><v_quad_trunc><mode>2):
	Change define_expand to define_insn_and_split.
	(<optab><v_oct_trunc><mode>2): Ditto.
	* config/riscv/riscv-protos.h (emit_vlmax_masked_insn): Exported.
	* config/riscv/riscv-v.cc (emit_vlmax_masked_insn): Ditto.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/autovec/binop/narrow-3.c: Adjust.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c: New test.
	* gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c: New test.
---
 gcc/config/riscv/autovec-opt.md               | 69 +++++++++++++++++++
 gcc/config/riscv/autovec.md                   | 37 ++++------
 gcc/config/riscv/riscv-protos.h               |  1 +
 gcc/config/riscv/riscv-v.cc                   |  2 +-
 .../riscv/rvv/autovec/binop/narrow-3.c        |  2 +-
 .../rvv/autovec/cond/cond_convert_int2int-1.h | 47 +++++++++++++
 .../rvv/autovec/cond/cond_convert_int2int-2.h | 46 +++++++++++++
 .../cond/cond_convert_int2int-rv32-1.c        | 14 ++++
 .../cond/cond_convert_int2int-rv32-2.c        | 14 ++++
 .../cond/cond_convert_int2int-rv64-1.c        | 14 ++++
 .../cond/cond_convert_int2int-rv64-2.c        | 14 ++++
 .../autovec/cond/cond_convert_int2int_run-1.c | 31 +++++++++
 .../autovec/cond/cond_convert_int2int_run-2.c | 30 ++++++++
 13 files changed, 296 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c
  

Comments

Robin Dapp Aug. 25, 2023, 6:48 a.m. UTC | #1
Hi Lehua,

thanks, LGTM.

One thing maybe for the next patches:  It seems to me that we lump all of
the COND_... tests into the cond subdirectory when IMHO they would also
fit into the respective directories of their operations (binop, unop etc).
Right now we will have a lot of rather unrelated tests (or just related
by their use of COND_) in one dir.  What do you think?  

Regards
 Robin
  
Lehua Ding Aug. 25, 2023, 7:26 a.m. UTC | #2
Hi Robin,

There is one issue with this patch and the next few patches, the mask 
policy for the generated vsetvl should be mu, which is currently done 
wrong. I'm going to clear the expand_cond_len* functions before sending 
the next version of these patches. Then these patches can directly use 
expand_cond_len_unary instead of emit_vlmax_*.

> One thing maybe for the next patches: It seems to me that we lump all of 
> the COND_... tests into the cond subdirectory when IMHO they would also 
> fit into the respective directories of their operations (binop, unop 
> etc). Right now we will have a lot of rather unrelated tests (or just 
> related by their use of COND_) in one dir. What do you think?

I have no idea about it, I will add some more testcases for cond 
widen-binop testcases and it looks like there are too many files in the 
cond directory. Maybe it's better to subdivide unop, binop and ternop 
directories in the cond directory since all these testcases are designed 
to test the conditional patterns.
  

Patch

diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md
index 8247eb87ddb..f3ef3a839df 100644
--- a/gcc/config/riscv/autovec-opt.md
+++ b/gcc/config/riscv/autovec-opt.md
@@ -723,3 +723,72 @@ 
                                  riscv_vector::RVV_BINOP, operands);
   DONE;
 })
+
+;; Combine sign_extend/zero_extend(vf2) and vcond_mask
+(define_insn_and_split "*cond_<optab><v_double_trunc><mode>"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+        (if_then_else:VWEXTI
+          (match_operand:<VM> 1 "register_operand")
+          (any_extend:VWEXTI (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+          (match_operand:VWEXTI 2 "register_operand")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_masked_insn (icode, riscv_vector::RVV_UNOP_M, operands);
+  DONE;
+})
+
+;; Combine sign_extend/zero_extend(vf4) and vcond_mask
+(define_insn_and_split "*cond_<optab><v_quad_trunc><mode>"
+  [(set (match_operand:VQEXTI 0 "register_operand")
+        (if_then_else:VQEXTI
+          (match_operand:<VM> 1 "register_operand")
+          (any_extend:VQEXTI (match_operand:<V_QUAD_TRUNC> 3 "register_operand"))
+          (match_operand:VQEXTI 2 "register_operand")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  insn_code icode = code_for_pred_vf4 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_masked_insn (icode, riscv_vector::RVV_UNOP_M, operands);
+  DONE;
+})
+
+;; Combine sign_extend/zero_extend(vf8) and vcond_mask
+(define_insn_and_split "*cond_<optab><v_oct_trunc><mode>"
+  [(set (match_operand:VOEXTI 0 "register_operand")
+        (if_then_else:VOEXTI
+          (match_operand:<VM> 1 "register_operand")
+          (any_extend:VOEXTI (match_operand:<V_OCT_TRUNC> 3 "register_operand"))
+          (match_operand:VOEXTI 2 "register_operand")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_masked_insn (icode, riscv_vector::RVV_UNOP_M, operands);
+  DONE;
+})
+
+;; Combine trunc(vf2) + vcond_mask
+(define_insn_and_split "*cond_trunc<mode><v_double_trunc>"
+  [(set (match_operand:<V_DOUBLE_TRUNC> 0 "register_operand")
+    (if_then_else:<V_DOUBLE_TRUNC>
+          (match_operand:<VM> 1 "register_operand")
+          (truncate:<V_DOUBLE_TRUNC>
+            (match_operand:VWEXTI 3 "register_operand"))
+          (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))]
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  insn_code icode = code_for_pred_trunc (<MODE>mode);
+  riscv_vector::emit_vlmax_masked_insn (icode, riscv_vector::RVV_UNOP_M, operands);
+  DONE;
+})
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index e9659b2b157..fdd3e8ce404 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -644,22 +644,28 @@ 
   [(set_attr "type" "vext")
    (set_attr "mode" "<MODE>")])
 
-(define_expand "<optab><v_quad_trunc><mode>2"
+(define_insn_and_split "<optab><v_quad_trunc><mode>2"
   [(set (match_operand:VQEXTI 0 "register_operand")
     (any_extend:VQEXTI
      (match_operand:<V_QUAD_TRUNC> 1 "register_operand")))]
-  "TARGET_VECTOR"
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
 {
   insn_code icode = code_for_pred_vf4 (<CODE>, <MODE>mode);
   riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
   DONE;
 })
 
-(define_expand "<optab><v_oct_trunc><mode>2"
+(define_insn_and_split "<optab><v_oct_trunc><mode>2"
   [(set (match_operand:VOEXTI 0 "register_operand")
     (any_extend:VOEXTI
      (match_operand:<V_OCT_TRUNC> 1 "register_operand")))]
-  "TARGET_VECTOR"
+  "TARGET_VECTOR && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(const_int 0)]
 {
   insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
   riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
@@ -698,13 +704,8 @@ 
   "TARGET_VECTOR"
 {
   rtx half = gen_reg_rtx (<V_DOUBLE_TRUNC>mode);
-  rtx opshalf[] = {half, operands[1]};
-  insn_code icode = code_for_pred_trunc (<MODE>mode);
-  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opshalf);
-
-  rtx ops[] = {operands[0], half};
-  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
-  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  emit_insn (gen_trunc<mode><v_double_trunc>2 (half, operands[1]));
+  emit_insn (gen_trunc<v_double_trunc><v_quad_trunc>2 (operands[0], half));
   DONE;
 })
 
@@ -718,19 +719,9 @@ 
      (match_operand:VOEXTI 1 "register_operand")))]
   "TARGET_VECTOR"
 {
-  rtx half = gen_reg_rtx (<V_DOUBLE_TRUNC>mode);
-  rtx opshalf[] = {half, operands[1]};
-  insn_code icode = code_for_pred_trunc (<MODE>mode);
-  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opshalf);
-
   rtx quarter = gen_reg_rtx (<V_QUAD_TRUNC>mode);
-  rtx opsquarter[] = {quarter, half};
-  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
-  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, opsquarter);
-
-  rtx ops[] = {operands[0], quarter};
-  icode = code_for_pred_trunc (<V_QUAD_TRUNC>mode);
-  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  emit_insn (gen_trunc<mode><v_quad_trunc>2 (quarter, operands[1]));
+  emit_insn (gen_trunc<v_quad_trunc><v_oct_trunc>2 (operands[0], quarter));
   DONE;
 })
 
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 2c4405c9860..558330718a1 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -254,6 +254,7 @@  void emit_nonvlmax_slide_tu_insn (unsigned, rtx *, rtx);
 void emit_vlmax_merge_insn (unsigned, int, rtx *);
 void emit_vlmax_cmp_insn (unsigned, rtx *);
 void emit_vlmax_cmp_mu_insn (unsigned, rtx *);
+void emit_vlmax_masked_insn (unsigned, int, rtx *);
 void emit_vlmax_masked_mu_insn (unsigned, int, rtx *);
 void emit_scalar_move_insn (unsigned, rtx *, rtx = 0);
 void emit_nonvlmax_integer_move_insn (unsigned, rtx *, rtx);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 14eda581d00..a2cf006804b 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -905,7 +905,7 @@  emit_vlmax_cmp_mu_insn (unsigned icode, rtx *ops)
 }
 
 /* This function emits a masked instruction.  */
-static void
+void
 emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
 {
   machine_mode dest_mode = GET_MODE (ops[0]);
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c
index 3b288466394..315d2de0a8b 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/narrow-3.c
@@ -27,5 +27,5 @@ 
 
 TEST_ALL ()
 
-/* { dg-final { scan-assembler-times {\tvnsra\.wx} 4 } } */
+/* { dg-final { scan-assembler-times {\tvnsra\.wx} 8 } } */
 /* { dg-final { scan-assembler-times {\tvnsrl\.wx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h
new file mode 100644
index 00000000000..c8ef6df399d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-1.h
@@ -0,0 +1,47 @@ 
+#include <stdint.h>
+
+#define DEF_LOOP(OLD_TYPE, NEW_TYPE)                                           \
+  void __attribute__ ((noipa))                                                 \
+  test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r,                      \
+				  OLD_TYPE *__restrict a,                      \
+				  NEW_TYPE *__restrict b,                      \
+				  OLD_TYPE *__restrict pred, int n)            \
+  {                                                                            \
+    for (int i = 0; i < n; ++i)                                                \
+      {                                                                        \
+	r[i] = pred[i] ? (NEW_TYPE) a[i] : b[i];                               \
+      }                                                                        \
+  }
+
+/* INT -> wider-INT */
+#define TEST_ALL_X2X_WIDER(T)                                                  \
+  T (uint8_t, uint16_t)                                                        \
+  T (uint8_t, uint32_t)                                                        \
+  T (uint8_t, uint64_t)                                                        \
+  T (int8_t, int16_t)                                                          \
+  T (int8_t, int32_t)                                                          \
+  T (int8_t, int64_t)                                                          \
+  T (uint16_t, uint32_t)                                                       \
+  T (uint16_t, uint64_t)                                                       \
+  T (int16_t, int32_t)                                                         \
+  T (int16_t, int64_t)                                                         \
+  T (uint32_t, uint64_t)                                                       \
+  T (int32_t, int64_t)
+
+/* INT -> narrower-INT */
+#define TEST_ALL_X2X_NARROWER(T)                                               \
+  T (uint16_t, uint8_t)                                                        \
+  T (int16_t, int8_t)                                                          \
+  T (uint32_t, uint8_t)                                                        \
+  T (int32_t, int8_t)                                                          \
+  T (uint64_t, uint8_t)                                                        \
+  T (int64_t, int8_t)                                                          \
+  T (uint32_t, uint16_t)                                                       \
+  T (int32_t, int16_t)                                                         \
+  T (uint64_t, uint16_t)                                                       \
+  T (int64_t, int16_t)                                                         \
+  T (uint64_t, uint32_t)                                                       \
+  T (int64_t, int32_t)
+
+TEST_ALL_X2X_WIDER (DEF_LOOP)
+TEST_ALL_X2X_NARROWER (DEF_LOOP)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h
new file mode 100644
index 00000000000..f53c1b3fde9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-2.h
@@ -0,0 +1,46 @@ 
+#include <stdint.h>
+
+#define DEF_LOOP(OLD_TYPE, NEW_TYPE)                                           \
+  void __attribute__ ((noipa))                                                 \
+  test_##OLD_TYPE##_2_##NEW_TYPE (NEW_TYPE *__restrict r,                      \
+				  OLD_TYPE *__restrict a, NEW_TYPE b,          \
+				  OLD_TYPE *__restrict pred, int n)            \
+  {                                                                            \
+    for (int i = 0; i < n; ++i)                                                \
+      {                                                                        \
+	r[i] = pred[i] ? (NEW_TYPE) a[i] : b;                                  \
+      }                                                                        \
+  }
+
+/* INT -> wider-INT */
+#define TEST_ALL_X2X_WIDER(T)                                                  \
+  T (uint8_t, uint16_t)                                                        \
+  T (uint8_t, uint32_t)                                                        \
+  T (uint8_t, uint64_t)                                                        \
+  T (int8_t, int16_t)                                                          \
+  T (int8_t, int32_t)                                                          \
+  T (int8_t, int64_t)                                                          \
+  T (uint16_t, uint32_t)                                                       \
+  T (uint16_t, uint64_t)                                                       \
+  T (int16_t, int32_t)                                                         \
+  T (int16_t, int64_t)                                                         \
+  T (uint32_t, uint64_t)                                                       \
+  T (int32_t, int64_t)
+
+/* INT -> narrower-INT */
+#define TEST_ALL_X2X_NARROWER(T)                                               \
+  T (uint16_t, uint8_t)                                                        \
+  T (int16_t, int8_t)                                                          \
+  T (uint32_t, uint8_t)                                                        \
+  T (int32_t, int8_t)                                                          \
+  T (uint64_t, uint8_t)                                                        \
+  T (int64_t, int8_t)                                                          \
+  T (uint32_t, uint16_t)                                                       \
+  T (int32_t, int16_t)                                                         \
+  T (uint64_t, uint16_t)                                                       \
+  T (int64_t, int16_t)                                                         \
+  T (uint64_t, uint32_t)                                                       \
+  T (int64_t, int32_t)
+
+TEST_ALL_X2X_WIDER (DEF_LOOP)
+TEST_ALL_X2X_NARROWER (DEF_LOOP)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c
new file mode 100644
index 00000000000..d7de6de0610
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-1.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */
+
+#include "cond_convert_int2int-1.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c
new file mode 100644
index 00000000000..23e7c108ce3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv32-2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gcv_zvfh -mabi=ilp32d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */
+
+#include "cond_convert_int2int-2.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c
new file mode 100644
index 00000000000..f8f38caca19
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-1.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */
+
+#include "cond_convert_int2int-1.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c
new file mode 100644
index 00000000000..c48643de7ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int-rv64-2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv_zvfh -mabi=lp64d --param riscv-autovec-preference=scalable -fno-vect-cost-model" } */
+
+#include "cond_convert_int2int-2.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf2\tv[0-9]+,v[0-9]+,v0\.t} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4\tv[0-9]+,v[0-9]+,v0\.t} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8\tv[0-9]+,v[0-9]+,v0\.t} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+,v0\.t} 12 } } */
+/* { dg-final { scan-assembler-times {\tvncvt\.x\.x\.w\tv[0-9]+,v[0-9]+\n} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c
new file mode 100644
index 00000000000..04f24168a38
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-1.c
@@ -0,0 +1,31 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */
+
+#include "cond_convert_int2int-1.h"
+
+#define N 99
+
+#define TEST_LOOP(OLD_TYPE, NEW_TYPE)                                          \
+  {                                                                            \
+    NEW_TYPE r[N], b[N];                                                       \
+    OLD_TYPE a[N], pred[N];                                                    \
+    for (int i = 0; i < N; ++i)                                                \
+      {                                                                        \
+	a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1);                    \
+	b[i] = (i % 9) * (i % 7 + 1);                                          \
+	pred[i] = (i % 7 < 4);                                                 \
+	asm volatile("" ::: "memory");                                         \
+      }                                                                        \
+    test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N);                         \
+    for (int i = 0; i < N; ++i)                                                \
+      if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b[i]))                          \
+	__builtin_abort ();                                                    \
+  }
+
+int
+main ()
+{
+  TEST_ALL_X2X_WIDER (TEST_LOOP)
+  TEST_ALL_X2X_NARROWER (TEST_LOOP)
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c
new file mode 100644
index 00000000000..7a6897bf029
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/cond/cond_convert_int2int_run-2.c
@@ -0,0 +1,30 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "--param=riscv-autovec-preference=scalable -fno-vect-cost-model" } */
+
+#include "cond_convert_int2int-2.h"
+
+#define N 99
+
+#define TEST_LOOP(OLD_TYPE, NEW_TYPE)                                          \
+  {                                                                            \
+    NEW_TYPE r[N], b = 189;                                                    \
+    OLD_TYPE a[N], pred[N];                                                    \
+    for (int i = 0; i < N; ++i)                                                \
+      {                                                                        \
+	a[i] = (i & 1 ? i : 3 * i) * (i % 3 == 0 ? 1 : -1);                    \
+	pred[i] = (i % 7 < 4);                                                 \
+	asm volatile("" ::: "memory");                                         \
+      }                                                                        \
+    test_##OLD_TYPE##_2_##NEW_TYPE (r, a, b, pred, N);                         \
+    for (int i = 0; i < N; ++i)                                                \
+      if (r[i] != (pred[i] ? (NEW_TYPE) a[i] : b))                             \
+	__builtin_abort ();                                                    \
+  }
+
+int
+main ()
+{
+  TEST_ALL_X2X_WIDER (TEST_LOOP)
+  TEST_ALL_X2X_NARROWER (TEST_LOOP)
+  return 0;
+}