diff mbox series

RISC-V: Add autovec sign/zero extension and truncation.

Message ID 1a1cc437-12bd-b3e8-5fe4-7edb41625753@gmail.com
State New
Headers show
Series RISC-V: Add autovec sign/zero extension and truncation. | expand

Commit Message

Robin Dapp May 25, 2023, 9:03 a.m. UTC
Hi,

this patch implements the autovec expanders for sign and zero extension
patterns as well as the accompanying truncations.  In order to use them
additional mode_attr iterators as well as vectorizer hooks are required.
Using these hooks we can e.g. vectorize with VNx4QImode as base mode
and extend VNx4SI to VNx4DI.  They are still going to be expanded in the
future.

vf4 and vf8 truncations are emulated by truncating two and three times
respectively.

The patch also adds tests and changes some expectations for already
existing ones.

Combine does not yet handle binary operations of two widened operands
as we are missing the necessary split/rewrite patterns.  These will be
added at a later time.

Co-authored-by: Juzhe Zhong <juzhe.zhong@rivai.ai>

riscv.exp testsuite is unchanged.  zero-scratch-regs-3.c seems
to FAIL in vcondu but that already happens on trunk.

Regards
 Robin

gcc/ChangeLog:

	* config/riscv/autovec.md (<optab><v_double_trunc><mode>2): New
	expander.
	(<optab><v_quad_trunc><mode>2): Dito.
	(<optab><v_oct_trunc><mode>2): Dito.
	(trunc<mode><v_double_trunc>2): Dito.
	(trunc<mode><v_quad_trunc>2): Dito.
	(trunc<mode><v_oct_trunc>2): Dito.
	* config/riscv/riscv-protos.h (riscv_v_ext_mode_p): Declare.
	(vectorize_related_mode): Define.
	(autovectorize_vector_modes): Define.
	* config/riscv/riscv-v.cc (vectorize_related_mode): Implement
	hook.
	(autovectorize_vector_modes): Implement hook.
	* config/riscv/riscv.cc (riscv_v_ext_tuple_mode_p): Export.
	(riscv_autovectorize_vector_modes): Implement target hook.
	(riscv_vectorize_related_mode): Implement target hook.
	(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES): Define.
	(TARGET_VECTORIZE_RELATED_MODE): Define.
	* config/riscv/vector-iterators.md: Add lowercase versions of
	mode_attr iterators.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adjust
	expectation.
	* gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-run.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-template.h: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64d-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64f-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64x-2.c: Dito.
	* gcc.target/riscv/rvv/rvv.exp: Add new conversion tests.
	* gcc.target/riscv/rvv/vsetvl/avl_single-38.c: Do not vectorize.
	* gcc.target/riscv/rvv/vsetvl/avl_single-47.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/avl_single-49.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/imm_switch-8.c: Dito.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-template.h: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-template.h: New test.
---
 gcc/config/riscv/autovec.md                   | 104 ++++++++++++++++++
 gcc/config/riscv/riscv-protos.h               |   5 +
 gcc/config/riscv/riscv-v.cc                   |  83 ++++++++++++++
 gcc/config/riscv/riscv.cc                     |  31 +++++-
 gcc/config/riscv/vector-iterators.md          |  33 +++++-
 .../riscv/rvv/autovec/binop/shift-rv32gcv.c   |   1 -
 .../riscv/rvv/autovec/binop/shift-rv64gcv.c   |   5 +-
 .../riscv/rvv/autovec/binop/vdiv-run.c        |   4 +-
 .../riscv/rvv/autovec/binop/vdiv-rv32gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vdiv-rv64gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vdiv-template.h   |   5 +-
 .../riscv/rvv/autovec/binop/vrem-rv32gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vrem-rv64gcv.c    |   7 +-
 .../riscv/rvv/autovec/conversions/vncvt-run.c |  35 ++++++
 .../rvv/autovec/conversions/vncvt-rv32gcv.c   |   6 +
 .../rvv/autovec/conversions/vncvt-rv64gcv.c   |   6 +
 .../rvv/autovec/conversions/vncvt-template.h  |  19 ++++
 .../riscv/rvv/autovec/conversions/vsext-run.c |  35 ++++++
 .../rvv/autovec/conversions/vsext-rv32gcv.c   |   8 ++
 .../rvv/autovec/conversions/vsext-rv64gcv.c   |   8 ++
 .../rvv/autovec/conversions/vsext-template.h  |  19 ++++
 .../riscv/rvv/autovec/conversions/vzext-run.c |  35 ++++++
 .../rvv/autovec/conversions/vzext-rv32gcv.c   |   8 ++
 .../rvv/autovec/conversions/vzext-rv64gcv.c   |   8 ++
 .../rvv/autovec/conversions/vzext-template.h  |  19 ++++
 .../riscv/rvv/autovec/zve32f_zvl128b-2.c      |   2 +-
 .../riscv/rvv/autovec/zve32x_zvl128b-2.c      |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64d-2.c   |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64f-2.c   |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64x-2.c   |   2 +-
 gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |   2 +
 .../riscv/rvv/vsetvl/avl_single-38.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-47.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-48.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-49.c          |   2 +-
 .../riscv/rvv/vsetvl/imm_switch-8.c           |   2 +-
 36 files changed, 491 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h

Comments

juzhe.zhong@rivai.ai May 25, 2023, 9:27 a.m. UTC | #1
Hi, Robin.

>>+extern bool riscv_v_ext_mode_p (machine_mode mode);
No, we don't need it as global extern.

>> +  if (riscv_v_ext_mode_p (vector_mode)
>>+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
>>+      GET_MODE_SIZE (element_mode), &min_units))

use riscv_v_ext_vector_mode_p  instead since riscv_v_ext_mode_p includes tuple modes.
You should not use tuple modes in related_mode. Tuple modes will be used in array mode target hook and
used by vec_load_lanes/vec_store_lanes.

Otherwise LGTM since I have reviewed twice already.
Wait for kito's final approval.

Thanks.


juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-25 17:03
To: gcc-patches; Kito Cheng; palmer; juzhe.zhong@rivai.ai; jeffreyalaw
CC: rdapp.gcc
Subject: [PATCH] RISC-V: Add autovec sign/zero extension and truncation.
Hi,
 
this patch implements the autovec expanders for sign and zero extension
patterns as well as the accompanying truncations.  In order to use them
additional mode_attr iterators as well as vectorizer hooks are required.
Using these hooks we can e.g. vectorize with VNx4QImode as base mode
and extend VNx4SI to VNx4DI.  They are still going to be expanded in the
future.
 
vf4 and vf8 truncations are emulated by truncating two and three times
respectively.
 
The patch also adds tests and changes some expectations for already
existing ones.
 
Combine does not yet handle binary operations of two widened operands
as we are missing the necessary split/rewrite patterns.  These will be
added at a later time.
 
Co-authored-by: Juzhe Zhong <juzhe.zhong@rivai.ai>
 
riscv.exp testsuite is unchanged.  zero-scratch-regs-3.c seems
to FAIL in vcondu but that already happens on trunk.
 
Regards
Robin
 
gcc/ChangeLog:
 
* config/riscv/autovec.md (<optab><v_double_trunc><mode>2): New
expander.
(<optab><v_quad_trunc><mode>2): Dito.
(<optab><v_oct_trunc><mode>2): Dito.
(trunc<mode><v_double_trunc>2): Dito.
(trunc<mode><v_quad_trunc>2): Dito.
(trunc<mode><v_oct_trunc>2): Dito.
* config/riscv/riscv-protos.h (riscv_v_ext_mode_p): Declare.
(vectorize_related_mode): Define.
(autovectorize_vector_modes): Define.
* config/riscv/riscv-v.cc (vectorize_related_mode): Implement
hook.
(autovectorize_vector_modes): Implement hook.
* config/riscv/riscv.cc (riscv_v_ext_tuple_mode_p): Export.
(riscv_autovectorize_vector_modes): Implement target hook.
(riscv_vectorize_related_mode): Implement target hook.
(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES): Define.
(TARGET_VECTORIZE_RELATED_MODE): Define.
* config/riscv/vector-iterators.md: Add lowercase versions of
mode_attr iterators.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adjust
expectation.
* gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-run.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-template.h: Dito.
* gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve64d-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve64f-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve64x-2.c: Dito.
* gcc.target/riscv/rvv/rvv.exp: Add new conversion tests.
* gcc.target/riscv/rvv/vsetvl/avl_single-38.c: Do not vectorize.
* gcc.target/riscv/rvv/vsetvl/avl_single-47.c: Dito.
* gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Dito.
* gcc.target/riscv/rvv/vsetvl/avl_single-49.c: Dito.
* gcc.target/riscv/rvv/vsetvl/imm_switch-8.c: Dito.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-run.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-template.h: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-run.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-template.h: New test.
---
gcc/config/riscv/autovec.md                   | 104 ++++++++++++++++++
gcc/config/riscv/riscv-protos.h               |   5 +
gcc/config/riscv/riscv-v.cc                   |  83 ++++++++++++++
gcc/config/riscv/riscv.cc                     |  31 +++++-
gcc/config/riscv/vector-iterators.md          |  33 +++++-
.../riscv/rvv/autovec/binop/shift-rv32gcv.c   |   1 -
.../riscv/rvv/autovec/binop/shift-rv64gcv.c   |   5 +-
.../riscv/rvv/autovec/binop/vdiv-run.c        |   4 +-
.../riscv/rvv/autovec/binop/vdiv-rv32gcv.c    |   7 +-
.../riscv/rvv/autovec/binop/vdiv-rv64gcv.c    |   7 +-
.../riscv/rvv/autovec/binop/vdiv-template.h   |   5 +-
.../riscv/rvv/autovec/binop/vrem-rv32gcv.c    |   7 +-
.../riscv/rvv/autovec/binop/vrem-rv64gcv.c    |   7 +-
.../riscv/rvv/autovec/conversions/vncvt-run.c |  35 ++++++
.../rvv/autovec/conversions/vncvt-rv32gcv.c   |   6 +
.../rvv/autovec/conversions/vncvt-rv64gcv.c   |   6 +
.../rvv/autovec/conversions/vncvt-template.h  |  19 ++++
.../riscv/rvv/autovec/conversions/vsext-run.c |  35 ++++++
.../rvv/autovec/conversions/vsext-rv32gcv.c   |   8 ++
.../rvv/autovec/conversions/vsext-rv64gcv.c   |   8 ++
.../rvv/autovec/conversions/vsext-template.h  |  19 ++++
.../riscv/rvv/autovec/conversions/vzext-run.c |  35 ++++++
.../rvv/autovec/conversions/vzext-rv32gcv.c   |   8 ++
.../rvv/autovec/conversions/vzext-rv64gcv.c   |   8 ++
.../rvv/autovec/conversions/vzext-template.h  |  19 ++++
.../riscv/rvv/autovec/zve32f_zvl128b-2.c      |   2 +-
.../riscv/rvv/autovec/zve32x_zvl128b-2.c      |   2 +-
.../gcc.target/riscv/rvv/autovec/zve64d-2.c   |   2 +-
.../gcc.target/riscv/rvv/autovec/zve64f-2.c   |   2 +-
.../gcc.target/riscv/rvv/autovec/zve64x-2.c   |   2 +-
gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |   2 +
.../riscv/rvv/vsetvl/avl_single-38.c          |   2 +-
.../riscv/rvv/vsetvl/avl_single-47.c          |   2 +-
.../riscv/rvv/vsetvl/avl_single-48.c          |   2 +-
.../riscv/rvv/vsetvl/avl_single-49.c          |   2 +-
.../riscv/rvv/vsetvl/imm_switch-8.c           |   2 +-
36 files changed, 491 insertions(+), 36 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
 
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 1c03468c2f4..c2f2d5083db 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -373,3 +373,107 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
)
+
+;; -------------------------------------------------------------------------
+;; ---- [INT] Sign and zero extension
+;; -------------------------------------------------------------------------
+;; Includes:
+;; - vzext.vf[2|4|8]
+;; - vsext.vf[2|4|8]
+;; -------------------------------------------------------------------------
+
+(define_expand "<optab><v_double_trunc><mode>2"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+    (any_extend:VWEXTI
+     (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+(define_expand "<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"
+{
+  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"
+  [(set (match_operand:VOEXTI 0 "register_operand")
+    (any_extend:VOEXTI
+     (match_operand:<V_OCT_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; ---- [INT] Truncation
+;; -------------------------------------------------------------------------
+;; - vncvt.x.x.w
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_double_trunc>2"
+  [(set (match_operand:<V_DOUBLE_TRUNC> 0 "register_operand")
+    (truncate:<V_DOUBLE_TRUNC>
+     (match_operand:VWEXTI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_trunc (<MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Truncation to a mode whose inner mode size is a quarter of mode's.
+;; We emulate this with two consecutive vncvts.
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_quad_trunc>2"
+  [(set (match_operand:<V_QUAD_TRUNC> 0 "register_operand")
+    (truncate:<V_QUAD_TRUNC>
+     (match_operand:VQEXTI 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 ops[] = {operands[0], half};
+  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Truncation to a mode whose inner mode size is an eigth of mode's.
+;; We emulate this with three consecutive vncvts.
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_oct_trunc>2"
+  [(set (match_operand:<V_OCT_TRUNC> 0 "register_operand")
+    (truncate:<V_OCT_TRUNC>
+     (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);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 5f78fd579bb..6219cff1354 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -81,6 +81,7 @@ extern void riscv_reinit (void);
extern poly_uint64 riscv_regmode_natural_size (machine_mode);
extern bool riscv_v_ext_vector_mode_p (machine_mode);
extern bool riscv_v_ext_tuple_mode_p (machine_mode);
+extern bool riscv_v_ext_mode_p (machine_mode mode);
extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);
extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *);
@@ -253,6 +254,10 @@ enum frm_field_enum
   FRM_RMM = 0b100,
   DYN = 0b111
};
+
+opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode,
+ poly_uint64);
+unsigned int autovectorize_vector_modes (vec<machine_mode> *, bool);
}
/* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..18b39093495 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1396,9 +1396,92 @@ get_cmp_insn_code (rtx_code code, machine_mode mode)
     default:
       gcc_unreachable ();
     }
+
   return icode;
}
+/* This hook gives the vectorizer more vector mode options.  We want it to not
+   only try modes with the maximum number of units a full vector can hold but
+   for example also half the number of units for a smaller elements size.
+   Such vectors can be promoted to a full vector of widened elements
+   (still with the same number of elements, essentially vectorizing at a
+   fixed number of units rather than a fixed number of bytes).  */
+unsigned int
+autovectorize_vector_modes (vector_modes *modes, bool)
+{
+  if (TARGET_VECTOR)
+    {
+      /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+      poly_uint64 full_size
+ = BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul);
+
+      /* Start with a VNxYYQImode where YY is the number of units that
+ fit a whole vector.
+ Then try YY = nunits / 2, nunits / 4 and nunits / 8 which
+ is guided by the extensions we have available (vf2, vf4 and vf8).
+
+ - full_size: Try using full vectors for all element types.
+ - full_size / 2:
+    Try using 16-bit containers for 8-bit elements and full vectors
+    for wider elements.
+ - full_size / 4:
+    Try using 32-bit containers for 8-bit and 16-bit elements and
+    full vectors for wider elements.
+ - full_size / 8:
+    Try using 64-bit containers for all element types.  */
+      static const int rvv_factors[] = {1, 2, 4, 8};
+      for (unsigned int i = 0; i < sizeof (rvv_factors) / sizeof (int); i++)
+ {
+   poly_uint64 units;
+   machine_mode mode;
+   if (can_div_trunc_p (full_size, rvv_factors[i], &units)
+       && get_vector_mode (QImode, units).exists (&mode))
+     modes->safe_push (mode);
+ }
+    }
+  return 0;
+}
+
+/* If the given VECTOR_MODE is an RVV mode,  first get the largest number
+   of units that fit into a full vector at the given ELEMENT_MODE.
+   We will have the vectorizer call us with a successively decreasing
+   number of units (as specified in autovectorize_vector_modes).
+   The starting mode is always the one specified by preferred_simd_mode. */
+opt_machine_mode
+vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+ poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_mode_p (vector_mode)
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+      GET_MODE_SIZE (element_mode), &min_units))
+    {
+      machine_mode rvv_mode;
+      if (maybe_ne (nunits, 0U))
+ {
+   /* If we were given a number of units NUNITS, try to find an
+      RVV vector mode of inner mode ELEMENT_MODE with the same
+      number of units.  */
+   if (multiple_p (min_units, nunits)
+       && get_vector_mode (element_mode, nunits).exists (&rvv_mode))
+     return rvv_mode;
+ }
+      else
+ {
+   /* Look for a vector mode with the same number of units as the
+      VECTOR_MODE we were given.  We keep track of the minimum
+      number of units so far which determines the smallest necessary
+      but largest possible, suitable mode for vectorization.  */
+   min_units = ordered_min (min_units, GET_MODE_SIZE (vector_mode));
+   if (get_vector_mode (element_mode, min_units).exists (&rvv_mode))
+     return rvv_mode;
+ }
+    }
+
+  return default_vectorize_related_mode (vector_mode, element_mode, nunits);
+}
+
/* Expand an RVV comparison.  */
void
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 23040557881..3dfccd3a8c3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1031,7 +1031,7 @@ riscv_v_ext_tuple_mode_p (machine_mode mode)
/* Return true if it is either RVV vector mode or RVV tuple mode.  */
-static bool
+bool
riscv_v_ext_mode_p (machine_mode mode)
{
   return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode);
@@ -7616,6 +7616,28 @@ riscv_mode_priority (int, int n)
   return n;
}
+/* Implement TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES.  */
+unsigned int
+riscv_autovectorize_vector_modes (vector_modes *modes, bool all)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::autovectorize_vector_modes (modes, all);
+
+  return default_autovectorize_vector_modes (modes, all);
+}
+
+/* Implement TARGET_VECTORIZE_RELATED_MODE.  */
+opt_machine_mode
+riscv_vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+       poly_uint64 nunits)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::vectorize_related_mode (vector_mode, element_mode,
+ nunits);
+  return default_vectorize_related_mode (vector_mode, element_mode, nunits);
+}
+
+
/* Initialize the GCC target structure.  */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -7907,6 +7929,13 @@ riscv_mode_priority (int, int n)
#undef TARGET_MODE_PRIORITY
#define TARGET_MODE_PRIORITY riscv_mode_priority
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
+  riscv_autovectorize_vector_modes
+
+#undef TARGET_VECTORIZE_RELATED_MODE
+#define TARGET_VECTORIZE_RELATED_MODE riscv_vectorize_related_mode
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-riscv.h"
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 3096ac5be3c..70fb5b80b1b 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -1118,8 +1118,10 @@ (define_mode_attr V_DOUBLE_TRUNC [
   (VNx16HI "VNx16QI") (VNx32HI "VNx32QI") (VNx64HI "VNx64QI")
   (VNx1SI "VNx1HI") (VNx2SI "VNx2HI") (VNx4SI "VNx4HI") (VNx8SI "VNx8HI")
   (VNx16SI "VNx16HI") (VNx32SI "VNx32HI")
-  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI") (VNx16DI "VNx16SI")
-  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF") (VNx16DF "VNx16SF")
+  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI")
+  (VNx16DI "VNx16SI")
+  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF")
+  (VNx16DF "VNx16SF")
])
(define_mode_attr V_QUAD_TRUNC [
@@ -1130,7 +1132,32 @@ (define_mode_attr V_QUAD_TRUNC [
])
(define_mode_attr V_OCT_TRUNC [
-  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI") (VNx16DI "VNx16QI")
+  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI")
+  (VNx16DI "VNx16QI")
+])
+
+; Again in lower case.
+(define_mode_attr v_double_trunc [
+  (VNx1HI "vnx1qi") (VNx2HI "vnx2qi")  (VNx4HI "vnx4qi")  (VNx8HI "vnx8qi")
+  (VNx16HI "vnx16qi") (VNx32HI "vnx32qi") (VNx64HI "vnx64qi")
+  (VNx1SI "vnx1hi") (VNx2SI "vnx2hi") (VNx4SI "vnx4hi") (VNx8SI "vnx8hi")
+  (VNx16SI "vnx16hi") (VNx32SI "vnx32hi")
+  (VNx1DI "vnx1si") (VNx2DI "vnx2si") (VNx4DI "vnx4si") (VNx8DI "vnx8si")
+  (VNx16DI "vnx16si")
+  (VNx1DF "vnx1sf") (VNx2DF "vnx2sf") (VNx4DF "vnx4sf") (VNx8DF "vnx8sf")
+  (VNx16DF "vnx16sf")
+])
+
+(define_mode_attr v_quad_trunc [
+  (VNx1SI "vnx1qi") (VNx2SI "vnx2qi") (VNx4SI "vnx4qi") (VNx8SI "vnx8qi")
+  (VNx16SI "vnx16qi") (VNx32SI "vnx32qi")
+  (VNx1DI "vnx1hi") (VNx2DI "vnx2hi") (VNx4DI "vnx4hi") (VNx8DI "vnx8hi")
+  (VNx16DI "vnx16hi")
+])
+
+(define_mode_attr v_oct_trunc [
+  (VNx1DI "vnx1qi") (VNx2DI "vnx2qi") (VNx4DI "vnx4qi") (VNx8DI "vnx8qi")
+  (VNx16DI "vnx16qi")
])
(define_mode_attr VINDEX_DOUBLE_TRUNC [
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
index d98100b3276..557a7c82531 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
@@ -10,4 +10,3 @@
/* { dg-final { scan-assembler {\tvsll\.vv} } } */
/* { dg-final { scan-assembler {\tvsrl\.vv} } } */
/* { dg-final { scan-assembler {\tvsra\.vv} } } */
-
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
index d9109fd8774..01a9cb21efc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
@@ -3,9 +3,6 @@
#include "shift-template.h"
-/* TODO: For int16_t and uint16_t we need widening/promotion patterns.
-   Therefore, expect only 4 vsll.vv instead of 6 for now.  */
-
-/* { dg-final { scan-assembler-times {\tvsll\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {\tvsll\.vv} 6 } } */
/* { dg-final { scan-assembler-times {\tvsrl\.vv} 3 } } */
/* { dg-final { scan-assembler-times {\tvsra\.vv} 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
index aa9a3c55abe..5de339172fc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
@@ -15,7 +15,7 @@
     a##TYPE[i] = VAL * 3;       \
     b##TYPE[i] = VAL;           \
   }                             \
-  vadd_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ); \
+  vdiv_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ); \
   for (int i = 0; i < SZ; i++) \
     assert (a##TYPE[i] == 3);
@@ -23,7 +23,7 @@
   TYPE as##TYPE[SZ]; \
   for (int i = 0; i < SZ; i++) \
     as##TYPE[i] = VAL * 5; \
-  vadds_##TYPE (as##TYPE, as##TYPE, VAL, SZ); \
+  vdivs_##TYPE (as##TYPE, as##TYPE, VAL, SZ); \
   for (int i = 0; i < SZ; i++) \
     assert (as##TYPE[i] == 5);
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
index 9759401b9ef..1dce9dd562e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
@@ -3,7 +3,8 @@
#include "vdiv-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
index 7d9b75ae0b1..16a18c466e0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
@@ -3,7 +3,8 @@
#include "vdiv-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
index 12a1de32874..f8d3bfde4ed 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
@@ -2,7 +2,7 @@
#define TEST_TYPE(TYPE) \
   __attribute__((noipa)) \
-  void vadd_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n) \
+  void vdiv_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n) \
   { \
     for (int i = 0; i < n; i++) \
       dst[i] = a[i] / b[i]; \
@@ -10,13 +10,12 @@
#define TEST2_TYPE(TYPE) \
   __attribute__((noipa)) \
-  void vadds_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n) \
+  void vdivs_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n) \
   { \
     for (int i = 0; i < n; i++) \
       dst[i] = a[i] / b; \
   }
-/* *int8_t not autovec currently. */
#define TEST_ALL() \
  TEST_TYPE(int16_t) \
  TEST_TYPE(uint16_t) \
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
index 28cba510a93..df99f5019fb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
@@ -3,7 +3,8 @@
#include "vrem-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
index 5b6961d1f63..3cff13a47e4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
@@ -3,7 +3,8 @@
#include "vrem-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
new file mode 100644
index 00000000000..f55d2dfce7f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2) \
+  TYPE1 src##TYPE1##TYPE2[SZ]; \
+  TYPE2 dst##TYPE1##TYPE2[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    src##TYPE1##TYPE2[i] = i;             \
+    dst##TYPE1##TYPE2[i] = -1; \
+  }                             \
+  vncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \
+ src##TYPE1##TYPE2, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL() \
+ RUN(uint16_t, uint8_t) \
+ RUN(uint32_t, uint8_t) \
+ RUN(uint64_t, uint8_t) \
+ RUN(uint32_t, uint16_t) \
+ RUN(uint64_t, uint16_t) \
+ RUN(uint64_t, uint32_t) \
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
new file mode 100644
index 00000000000..2b5aa0051cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
new file mode 100644
index 00000000000..29349b33da6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
new file mode 100644
index 00000000000..6b19ff12abe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2) \
+  __attribute__((noipa)) \
+  void vncvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = (TYPE1)a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST(uint16_t, uint8_t) \
+ TEST(uint32_t, uint8_t) \
+ TEST(uint32_t, uint16_t) \
+ TEST(uint64_t, uint8_t) \
+ TEST(uint64_t, uint16_t) \
+ TEST(uint64_t, uint32_t) \
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
new file mode 100644
index 00000000000..d5f0190957a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2) \
+  TYPE1 src##TYPE1##TYPE2[SZ]; \
+  TYPE2 dst##TYPE1##TYPE2[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    src##TYPE1##TYPE2[i] = i - 128;            \
+    dst##TYPE1##TYPE2[i] = 0; \
+  }                             \
+  vsext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \
+ src##TYPE1##TYPE2, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (dst##TYPE1##TYPE2[i] == i - 128);
+
+
+#define RUN_ALL() \
+ RUN(int8_t, int16_t) \
+ RUN(int8_t, int32_t) \
+ RUN(int8_t, int64_t) \
+ RUN(int16_t, int32_t) \
+ RUN(int16_t, int64_t) \
+ RUN(int32_t, int64_t) \
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
new file mode 100644
index 00000000000..538216ab9c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
new file mode 100644
index 00000000000..29348cc67e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
new file mode 100644
index 00000000000..c2f5fc92c99
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2) \
+  __attribute__((noipa)) \
+  void vsext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = (TYPE1)a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST(int8_t, int16_t) \
+ TEST(int8_t, int32_t) \
+ TEST(int8_t, int64_t) \
+ TEST(int16_t, int32_t) \
+ TEST(int16_t, int64_t) \
+ TEST(int32_t, int64_t) \
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
new file mode 100644
index 00000000000..9d1c259f592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2) \
+  TYPE1 src##TYPE1##TYPE2[SZ]; \
+  TYPE2 dst##TYPE1##TYPE2[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    src##TYPE1##TYPE2[i] = i;             \
+    dst##TYPE1##TYPE2[i] = -1; \
+  }                             \
+  vzext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \
+ src##TYPE1##TYPE2, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL() \
+ RUN(uint8_t, uint16_t) \
+ RUN(uint8_t, uint32_t) \
+ RUN(uint8_t, uint64_t) \
+ RUN(uint16_t, uint32_t) \
+ RUN(uint16_t, uint64_t) \
+ RUN(uint32_t, uint64_t) \
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
new file mode 100644
index 00000000000..3e92843a5c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
new file mode 100644
index 00000000000..cee0012d58c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
new file mode 100644
index 00000000000..847905b690c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2) \
+  __attribute__((noipa)) \
+  void vzext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = (TYPE1)a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST(uint8_t, uint16_t) \
+ TEST(uint8_t, uint32_t) \
+ TEST(uint8_t, uint64_t) \
+ TEST(uint16_t, uint32_t) \
+ TEST(uint16_t, uint64_t) \
+ TEST(uint32_t, uint64_t) \
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
index c53975e9b01..7f499befa82 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 4 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
index 80a4796fd38..2de09a29f02 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
index 5e38b41a5c3..95d54d7b281 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 6 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
index ee37282f1f8..f9f44a94902 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
index 6a64a1a1fdf..12703a7e036 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..9466c2032e3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/conversions/*.\[cS\]]] \
+    "" "$op"
}
# VLS-VLMAX tests
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
index 34f1cd43a21..8606b10268d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
index 935e1b10630..11403203aa9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
index a1f4b70d4b4..79af2ef450a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
index 4fa68627cc0..77fe05b68a7 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
index 4a1ef3ce5e9..f8568a8c898 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
Robin Dapp May 25, 2023, 9:30 a.m. UTC | #2
Hi Juzhe,

> use riscv_v_ext_vector_mode_p  instead since riscv_v_ext_mode_p includes tuple modes.
> You should not use tuple modes in related_mode. Tuple modes will be used in array mode target hook and
> used by vec_load_lanes/vec_store_lanes.

Ah, thanks for catching this.  Yes, vector_mode_p is what I intended
obviously.

Regards
 Robin
Li, Pan2 via Gcc-patches May 25, 2023, 12:21 p.m. UTC | #3
The zero-scratch-regs-3.c comes from below PATCH. 

https://gcc.gnu.org/pipermail/gcc-patches/2023-April/615494.html

Hi Yanzhang,

Could you please help to double check the issue reported by Robin? Aka: " zero-scratch-regs-3.c seems to FAIL in vcondu but that already happens on trunk."

Thanks a lot.

Pan

-----Original Message-----
From: Gcc-patches <gcc-patches-bounces+pan2.li=intel.com@gcc.gnu.org> On Behalf Of Robin Dapp via Gcc-patches
Sent: Thursday, May 25, 2023 5:03 PM
To: gcc-patches <gcc-patches@gcc.gnu.org>; Kito Cheng <kito.cheng@gmail.com>; palmer <palmer@dabbelt.com>; juzhe.zhong@rivai.ai; jeffreyalaw <jeffreyalaw@gmail.com>
Cc: rdapp.gcc@gmail.com
Subject: [PATCH] RISC-V: Add autovec sign/zero extension and truncation.

Hi,

this patch implements the autovec expanders for sign and zero extension patterns as well as the accompanying truncations.  In order to use them additional mode_attr iterators as well as vectorizer hooks are required.
Using these hooks we can e.g. vectorize with VNx4QImode as base mode and extend VNx4SI to VNx4DI.  They are still going to be expanded in the future.

vf4 and vf8 truncations are emulated by truncating two and three times respectively.

The patch also adds tests and changes some expectations for already existing ones.

Combine does not yet handle binary operations of two widened operands as we are missing the necessary split/rewrite patterns.  These will be added at a later time.

Co-authored-by: Juzhe Zhong <juzhe.zhong@rivai.ai>

riscv.exp testsuite is unchanged.  zero-scratch-regs-3.c seems to FAIL in vcondu but that already happens on trunk.

Regards
 Robin

gcc/ChangeLog:

	* config/riscv/autovec.md (<optab><v_double_trunc><mode>2): New
	expander.
	(<optab><v_quad_trunc><mode>2): Dito.
	(<optab><v_oct_trunc><mode>2): Dito.
	(trunc<mode><v_double_trunc>2): Dito.
	(trunc<mode><v_quad_trunc>2): Dito.
	(trunc<mode><v_oct_trunc>2): Dito.
	* config/riscv/riscv-protos.h (riscv_v_ext_mode_p): Declare.
	(vectorize_related_mode): Define.
	(autovectorize_vector_modes): Define.
	* config/riscv/riscv-v.cc (vectorize_related_mode): Implement
	hook.
	(autovectorize_vector_modes): Implement hook.
	* config/riscv/riscv.cc (riscv_v_ext_tuple_mode_p): Export.
	(riscv_autovectorize_vector_modes): Implement target hook.
	(riscv_vectorize_related_mode): Implement target hook.
	(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES): Define.
	(TARGET_VECTORIZE_RELATED_MODE): Define.
	* config/riscv/vector-iterators.md: Add lowercase versions of
	mode_attr iterators.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adjust
	expectation.
	* gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-run.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-template.h: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64d-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64f-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64x-2.c: Dito.
	* gcc.target/riscv/rvv/rvv.exp: Add new conversion tests.
	* gcc.target/riscv/rvv/vsetvl/avl_single-38.c: Do not vectorize.
	* gcc.target/riscv/rvv/vsetvl/avl_single-47.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/avl_single-49.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/imm_switch-8.c: Dito.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-template.h: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-template.h: New test.
---
 gcc/config/riscv/autovec.md                   | 104 ++++++++++++++++++
 gcc/config/riscv/riscv-protos.h               |   5 +
 gcc/config/riscv/riscv-v.cc                   |  83 ++++++++++++++
 gcc/config/riscv/riscv.cc                     |  31 +++++-
 gcc/config/riscv/vector-iterators.md          |  33 +++++-
 .../riscv/rvv/autovec/binop/shift-rv32gcv.c   |   1 -
 .../riscv/rvv/autovec/binop/shift-rv64gcv.c   |   5 +-
 .../riscv/rvv/autovec/binop/vdiv-run.c        |   4 +-
 .../riscv/rvv/autovec/binop/vdiv-rv32gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vdiv-rv64gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vdiv-template.h   |   5 +-
 .../riscv/rvv/autovec/binop/vrem-rv32gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vrem-rv64gcv.c    |   7 +-
 .../riscv/rvv/autovec/conversions/vncvt-run.c |  35 ++++++
 .../rvv/autovec/conversions/vncvt-rv32gcv.c   |   6 +
 .../rvv/autovec/conversions/vncvt-rv64gcv.c   |   6 +
 .../rvv/autovec/conversions/vncvt-template.h  |  19 ++++  .../riscv/rvv/autovec/conversions/vsext-run.c |  35 ++++++
 .../rvv/autovec/conversions/vsext-rv32gcv.c   |   8 ++
 .../rvv/autovec/conversions/vsext-rv64gcv.c   |   8 ++
 .../rvv/autovec/conversions/vsext-template.h  |  19 ++++  .../riscv/rvv/autovec/conversions/vzext-run.c |  35 ++++++
 .../rvv/autovec/conversions/vzext-rv32gcv.c   |   8 ++
 .../rvv/autovec/conversions/vzext-rv64gcv.c   |   8 ++
 .../rvv/autovec/conversions/vzext-template.h  |  19 ++++
 .../riscv/rvv/autovec/zve32f_zvl128b-2.c      |   2 +-
 .../riscv/rvv/autovec/zve32x_zvl128b-2.c      |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64d-2.c   |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64f-2.c   |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64x-2.c   |   2 +-
 gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |   2 +
 .../riscv/rvv/vsetvl/avl_single-38.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-47.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-48.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-49.c          |   2 +-
 .../riscv/rvv/vsetvl/imm_switch-8.c           |   2 +-
 36 files changed, 491 insertions(+), 36 deletions(-)  create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h

diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index 1c03468c2f4..c2f2d5083db 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -373,3 +373,107 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
 )
+
+;; 
+-----------------------------------------------------------------------
+--
+;; ---- [INT] Sign and zero extension
+;; 
+-----------------------------------------------------------------------
+--
+;; Includes:
+;; - vzext.vf[2|4|8]
+;; - vsext.vf[2|4|8]
+;; 
+-----------------------------------------------------------------------
+--
+
+(define_expand "<optab><v_double_trunc><mode>2"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+    (any_extend:VWEXTI
+     (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, 
+operands);
+  DONE;
+})
+
+(define_expand "<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"
+{
+  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"
+  [(set (match_operand:VOEXTI 0 "register_operand")
+    (any_extend:VOEXTI
+     (match_operand:<V_OCT_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, 
+operands);
+  DONE;
+})
+
+;; 
+-----------------------------------------------------------------------
+--
+;; ---- [INT] Truncation
+;; 
+-----------------------------------------------------------------------
+--
+;; - vncvt.x.x.w
+;; 
+-----------------------------------------------------------------------
+-- (define_expand "trunc<mode><v_double_trunc>2"
+  [(set (match_operand:<V_DOUBLE_TRUNC> 0 "register_operand")
+    (truncate:<V_DOUBLE_TRUNC>
+     (match_operand:VWEXTI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_trunc (<MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, 
+operands);
+  DONE;
+})
+
+;; 
+-----------------------------------------------------------------------
+-- ;; Truncation to a mode whose inner mode size is a quarter of 
+mode's.
+;; We emulate this with two consecutive vncvts.
+;; 
+-----------------------------------------------------------------------
+-- (define_expand "trunc<mode><v_quad_trunc>2"
+  [(set (match_operand:<V_QUAD_TRUNC> 0 "register_operand")
+    (truncate:<V_QUAD_TRUNC>
+     (match_operand:VQEXTI 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 ops[] = {operands[0], half};
+  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  DONE;
+})
+
+;; 
+-----------------------------------------------------------------------
+-- ;; Truncation to a mode whose inner mode size is an eigth of mode's.
+;; We emulate this with three consecutive vncvts.
+;; 
+-----------------------------------------------------------------------
+-- (define_expand "trunc<mode><v_oct_trunc>2"
+  [(set (match_operand:<V_OCT_TRUNC> 0 "register_operand")
+    (truncate:<V_OCT_TRUNC>
+     (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);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 5f78fd579bb..6219cff1354 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -81,6 +81,7 @@ extern void riscv_reinit (void);  extern poly_uint64 riscv_regmode_natural_size (machine_mode);  extern bool riscv_v_ext_vector_mode_p (machine_mode);  extern bool riscv_v_ext_tuple_mode_p (machine_mode);
+extern bool riscv_v_ext_mode_p (machine_mode mode);
 extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);  extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);  extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *); @@ -253,6 +254,10 @@ enum frm_field_enum
   FRM_RMM = 0b100,
   DYN = 0b111
 };
+
+opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode,
+					 poly_uint64);
+unsigned int autovectorize_vector_modes (vec<machine_mode> *, bool);
 }
 
 /* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index f71ad9e46a1..18b39093495 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1396,9 +1396,92 @@ get_cmp_insn_code (rtx_code code, machine_mode mode)
     default:
       gcc_unreachable ();
     }
+
   return icode;
 }
 
+/* This hook gives the vectorizer more vector mode options.  We want it to not
+   only try modes with the maximum number of units a full vector can hold but
+   for example also half the number of units for a smaller elements size.
+   Such vectors can be promoted to a full vector of widened elements
+   (still with the same number of elements, essentially vectorizing at a
+   fixed number of units rather than a fixed number of bytes).  */ 
+unsigned int autovectorize_vector_modes (vector_modes *modes, bool) {
+  if (TARGET_VECTOR)
+    {
+      /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+      poly_uint64 full_size
+	= BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul);
+
+      /* Start with a VNxYYQImode where YY is the number of units that
+	 fit a whole vector.
+	 Then try YY = nunits / 2, nunits / 4 and nunits / 8 which
+	 is guided by the extensions we have available (vf2, vf4 and vf8).
+
+	 - full_size: Try using full vectors for all element types.
+	 - full_size / 2:
+	   Try using 16-bit containers for 8-bit elements and full vectors
+	   for wider elements.
+	 - full_size / 4:
+	   Try using 32-bit containers for 8-bit and 16-bit elements and
+	   full vectors for wider elements.
+	 - full_size / 8:
+	   Try using 64-bit containers for all element types.  */
+      static const int rvv_factors[] = {1, 2, 4, 8};
+      for (unsigned int i = 0; i < sizeof (rvv_factors) / sizeof (int); i++)
+	{
+	  poly_uint64 units;
+	  machine_mode mode;
+	  if (can_div_trunc_p (full_size, rvv_factors[i], &units)
+	      && get_vector_mode (QImode, units).exists (&mode))
+	    modes->safe_push (mode);
+	}
+    }
+  return 0;
+}
+
+/* If the given VECTOR_MODE is an RVV mode,  first get the largest number
+   of units that fit into a full vector at the given ELEMENT_MODE.
+   We will have the vectorizer call us with a successively decreasing
+   number of units (as specified in autovectorize_vector_modes).
+   The starting mode is always the one specified by 
+preferred_simd_mode. */ opt_machine_mode vectorize_related_mode 
+(machine_mode vector_mode, scalar_mode element_mode,
+			poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the 
+future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_mode_p (vector_mode)
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+		     GET_MODE_SIZE (element_mode), &min_units))
+    {
+      machine_mode rvv_mode;
+      if (maybe_ne (nunits, 0U))
+	{
+	  /* If we were given a number of units NUNITS, try to find an
+	     RVV vector mode of inner mode ELEMENT_MODE with the same
+	     number of units.  */
+	  if (multiple_p (min_units, nunits)
+	      && get_vector_mode (element_mode, nunits).exists (&rvv_mode))
+	    return rvv_mode;
+	}
+      else
+	{
+	  /* Look for a vector mode with the same number of units as the
+	     VECTOR_MODE we were given.  We keep track of the minimum
+	     number of units so far which determines the smallest necessary
+	     but largest possible, suitable mode for vectorization.  */
+	  min_units = ordered_min (min_units, GET_MODE_SIZE (vector_mode));
+	  if (get_vector_mode (element_mode, min_units).exists (&rvv_mode))
+	    return rvv_mode;
+	}
+    }
+
+  return default_vectorize_related_mode (vector_mode, element_mode, 
+nunits); }
+
 /* Expand an RVV comparison.  */
 
 void
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 23040557881..3dfccd3a8c3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1031,7 +1031,7 @@ riscv_v_ext_tuple_mode_p (machine_mode mode)
 
 /* Return true if it is either RVV vector mode or RVV tuple mode.  */
 
-static bool
+bool
 riscv_v_ext_mode_p (machine_mode mode)
 {
   return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode); @@ -7616,6 +7616,28 @@ riscv_mode_priority (int, int n)
   return n;
 }
 
+/* Implement TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES.  */ unsigned 
+int riscv_autovectorize_vector_modes (vector_modes *modes, bool all) {
+  if (TARGET_VECTOR)
+    return riscv_vector::autovectorize_vector_modes (modes, all);
+
+  return default_autovectorize_vector_modes (modes, all); }
+
+/* Implement TARGET_VECTORIZE_RELATED_MODE.  */ opt_machine_mode 
+riscv_vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+			      poly_uint64 nunits)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::vectorize_related_mode (vector_mode, element_mode,
+						 nunits);
+  return default_vectorize_related_mode (vector_mode, element_mode, 
+nunits); }
+
+
 /* Initialize the GCC target structure.  */  #undef TARGET_ASM_ALIGNED_HI_OP  #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -7907,6 +7929,13 @@ riscv_mode_priority (int, int n)  #undef TARGET_MODE_PRIORITY  #define TARGET_MODE_PRIORITY riscv_mode_priority
 
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
+  riscv_autovectorize_vector_modes
+
+#undef TARGET_VECTORIZE_RELATED_MODE
+#define TARGET_VECTORIZE_RELATED_MODE riscv_vectorize_related_mode
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 3096ac5be3c..70fb5b80b1b 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -1118,8 +1118,10 @@ (define_mode_attr V_DOUBLE_TRUNC [
   (VNx16HI "VNx16QI") (VNx32HI "VNx32QI") (VNx64HI "VNx64QI")
   (VNx1SI "VNx1HI") (VNx2SI "VNx2HI") (VNx4SI "VNx4HI") (VNx8SI "VNx8HI")
   (VNx16SI "VNx16HI") (VNx32SI "VNx32HI")
-  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI") (VNx16DI "VNx16SI")
-  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF") (VNx16DF "VNx16SF")
+  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI 
+ "VNx8SI")  (VNx16DI "VNx16SI")  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") 
+ (VNx4DF "VNx4SF") (VNx8DF "VNx8SF")  (VNx16DF "VNx16SF")
 ])
 
 (define_mode_attr V_QUAD_TRUNC [
@@ -1130,7 +1132,32 @@ (define_mode_attr V_QUAD_TRUNC [
 ])
 
 (define_mode_attr V_OCT_TRUNC [
-  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI") (VNx16DI "VNx16QI")
+  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI 
+"VNx8QI")
+  (VNx16DI "VNx16QI")
+])
+
+; Again in lower case.
+(define_mode_attr v_double_trunc [
+  (VNx1HI "vnx1qi") (VNx2HI "vnx2qi")  (VNx4HI "vnx4qi")  (VNx8HI 
+"vnx8qi")
+  (VNx16HI "vnx16qi") (VNx32HI "vnx32qi") (VNx64HI "vnx64qi")
+  (VNx1SI "vnx1hi") (VNx2SI "vnx2hi") (VNx4SI "vnx4hi") (VNx8SI 
+"vnx8hi")
+  (VNx16SI "vnx16hi") (VNx32SI "vnx32hi")
+  (VNx1DI "vnx1si") (VNx2DI "vnx2si") (VNx4DI "vnx4si") (VNx8DI 
+"vnx8si")
+  (VNx16DI "vnx16si")
+  (VNx1DF "vnx1sf") (VNx2DF "vnx2sf") (VNx4DF "vnx4sf") (VNx8DF 
+"vnx8sf")
+  (VNx16DF "vnx16sf")
+])
+
+(define_mode_attr v_quad_trunc [
+  (VNx1SI "vnx1qi") (VNx2SI "vnx2qi") (VNx4SI "vnx4qi") (VNx8SI 
+"vnx8qi")
+  (VNx16SI "vnx16qi") (VNx32SI "vnx32qi")
+  (VNx1DI "vnx1hi") (VNx2DI "vnx2hi") (VNx4DI "vnx4hi") (VNx8DI 
+"vnx8hi")
+  (VNx16DI "vnx16hi")
+])
+
+(define_mode_attr v_oct_trunc [
+  (VNx1DI "vnx1qi") (VNx2DI "vnx2qi") (VNx4DI "vnx4qi") (VNx8DI 
+"vnx8qi")
+  (VNx16DI "vnx16qi")
 ])
 
 (define_mode_attr VINDEX_DOUBLE_TRUNC [ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
index d98100b3276..557a7c82531 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
@@ -10,4 +10,3 @@
 /* { dg-final { scan-assembler {\tvsll\.vv} } } */
 /* { dg-final { scan-assembler {\tvsrl\.vv} } } */
 /* { dg-final { scan-assembler {\tvsra\.vv} } } */
-
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
index d9109fd8774..01a9cb21efc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
@@ -3,9 +3,6 @@
 
 #include "shift-template.h"
 
-/* TODO: For int16_t and uint16_t we need widening/promotion patterns.
-   Therefore, expect only 4 vsll.vv instead of 6 for now.  */
-
-/* { dg-final { scan-assembler-times {\tvsll\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {\tvsll\.vv} 6 } } */
 /* { dg-final { scan-assembler-times {\tvsrl\.vv} 3 } } */
 /* { dg-final { scan-assembler-times {\tvsra\.vv} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
index aa9a3c55abe..5de339172fc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
@@ -15,7 +15,7 @@
     a##TYPE[i] = VAL * 3;       		\
     b##TYPE[i] = VAL;           		\
   }                             		\
-  vadd_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ);	\
+  vdiv_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ);	\
   for (int i = 0; i < SZ; i++)			\
     assert (a##TYPE[i] == 3);
 
@@ -23,7 +23,7 @@
   TYPE as##TYPE[SZ];				\
   for (int i = 0; i < SZ; i++)			\
     as##TYPE[i] = VAL * 5;			\
-  vadds_##TYPE (as##TYPE, as##TYPE, VAL, SZ);	\
+  vdivs_##TYPE (as##TYPE, as##TYPE, VAL, SZ);	\
   for (int i = 0; i < SZ; i++)			\
     assert (as##TYPE[i] == 5);
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
index 9759401b9ef..1dce9dd562e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
@@ -3,7 +3,8 @@
 
 #include "vdiv-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
index 7d9b75ae0b1..16a18c466e0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
@@ -3,7 +3,8 @@
 
 #include "vdiv-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
index 12a1de32874..f8d3bfde4ed 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
@@ -2,7 +2,7 @@
 
 #define TEST_TYPE(TYPE) 				\
   __attribute__((noipa))				\
-  void vadd_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n)	\
+  void vdiv_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n)	\
   {							\
     for (int i = 0; i < n; i++)				\
       dst[i] = a[i] / b[i];				\
@@ -10,13 +10,12 @@
 
 #define TEST2_TYPE(TYPE) 				\
   __attribute__((noipa))				\
-  void vadds_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n)	\
+  void vdivs_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n)	\
   {							\
     for (int i = 0; i < n; i++)				\
       dst[i] = a[i] / b;				\
   }
 
-/* *int8_t not autovec currently. */
 #define TEST_ALL()	\
  TEST_TYPE(int16_t)	\
  TEST_TYPE(uint16_t)	\
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
index 28cba510a93..df99f5019fb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
@@ -3,7 +3,8 @@
 
 #include "vrem-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
index 5b6961d1f63..3cff13a47e4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
@@ -3,7 +3,8 @@
 
 #include "vrem-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
new file mode 100644
index 00000000000..f55d2dfce7f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i;             		\
+    dst##TYPE1##TYPE2[i] = -1;				\
+  }                             			\
+  vncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL()					\
+ RUN(uint16_t, uint8_t)					\
+ RUN(uint32_t, uint8_t)					\
+ RUN(uint64_t, uint8_t)					\
+ RUN(uint32_t, uint16_t)				\
+ RUN(uint64_t, uint16_t)				\
+ RUN(uint64_t, uint32_t)				\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
new file mode 100644
index 00000000000..2b5aa0051cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32g
+++ cv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv32gcv -mabi=ilp32d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
new file mode 100644
index 00000000000..29349b33da6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64g
+++ cv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv64gcv -mabi=lp64d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
new file mode 100644
index 00000000000..6b19ff12abe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-templ
+++ ate.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vncvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(uint16_t, uint8_t)					\
+ TEST(uint32_t, uint8_t)					\
+ TEST(uint32_t, uint16_t)					\
+ TEST(uint64_t, uint8_t)					\
+ TEST(uint64_t, uint16_t)					\
+ TEST(uint64_t, uint32_t)					\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
new file mode 100644
index 00000000000..d5f0190957a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i - 128;            		\
+    dst##TYPE1##TYPE2[i] = 0;				\
+  }                             			\
+  vsext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i - 128);
+
+
+#define RUN_ALL()					\
+ RUN(int8_t, int16_t)					\
+ RUN(int8_t, int32_t)					\
+ RUN(int8_t, int64_t)					\
+ RUN(int16_t, int32_t)					\
+ RUN(int16_t, int64_t)					\
+ RUN(int32_t, int64_t)					\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
new file mode 100644
index 00000000000..538216ab9c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv32gcv -mabi=ilp32d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
new file mode 100644
index 00000000000..29348cc67e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv64gcv -mabi=lp64d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
new file mode 100644
index 00000000000..c2f5fc92c99
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-templ
+++ ate.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vsext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(int8_t, int16_t)						\
+ TEST(int8_t, int32_t)						\
+ TEST(int8_t, int64_t)						\
+ TEST(int16_t, int32_t)						\
+ TEST(int16_t, int64_t)						\
+ TEST(int32_t, int64_t)						\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
new file mode 100644
index 00000000000..9d1c259f592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i;             		\
+    dst##TYPE1##TYPE2[i] = -1;				\
+  }                             			\
+  vzext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL()					\
+ RUN(uint8_t, uint16_t)					\
+ RUN(uint8_t, uint32_t)					\
+ RUN(uint8_t, uint64_t)					\
+ RUN(uint16_t, uint32_t)				\
+ RUN(uint16_t, uint64_t)				\
+ RUN(uint32_t, uint64_t)				\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
new file mode 100644
index 00000000000..3e92843a5c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv32gcv -mabi=ilp32d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
new file mode 100644
index 00000000000..cee0012d58c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv64gcv -mabi=lp64d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
new file mode 100644
index 00000000000..847905b690c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-templ
+++ ate.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vzext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(uint8_t, uint16_t)					\
+ TEST(uint8_t, uint32_t)					\
+ TEST(uint8_t, uint64_t)					\
+ TEST(uint16_t, uint32_t)					\
+ TEST(uint16_t, uint64_t)					\
+ TEST(uint32_t, uint64_t)					\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
index c53975e9b01..7f499befa82 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 4 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
index 80a4796fd38..2de09a29f02 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
index 5e38b41a5c3..95d54d7b281 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 6 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
index ee37282f1f8..f9f44a94902 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
index 6a64a1a1fdf..12703a7e036 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..9466c2032e3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/conversions/*.\[cS\]]] \
+    "" "$op"
 }
 
 # VLS-VLMAX tests
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
index 34f1cd43a21..8606b10268d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns 
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
index 935e1b10630..11403203aa9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns 
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
index a1f4b70d4b4..79af2ef450a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns 
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
index 4fa68627cc0..77fe05b68a7 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns 
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
index 4a1ef3ce5e9..f8568a8c898 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns 
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
--
2.40.1
Li, Pan2 via Gcc-patches May 26, 2023, 12:33 a.m. UTC | #4
Looks Juzhe has fixed this issue as below, thanks Juzhe.

https://gcc.gnu.org/pipermail/gcc-patches/2023-May/619733.html

Pan

-----Original Message-----
From: Li, Pan2 
Sent: Thursday, May 25, 2023 8:22 PM
To: gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Cc: Robin Dapp <rdapp.gcc@gmail.com>; Kito Cheng <kito.cheng@gmail.com>; palmer <palmer@dabbelt.com>; juzhe.zhong@rivai.ai; jeffreyalaw <jeffreyalaw@gmail.com>
Subject: RE: [PATCH] RISC-V: Add autovec sign/zero extension and truncation.

The zero-scratch-regs-3.c comes from below PATCH. 

https://gcc.gnu.org/pipermail/gcc-patches/2023-April/615494.html

Hi Yanzhang,

Could you please help to double check the issue reported by Robin? Aka: " zero-scratch-regs-3.c seems to FAIL in vcondu but that already happens on trunk."

Thanks a lot.

Pan

-----Original Message-----
From: Gcc-patches <gcc-patches-bounces+pan2.li=intel.com@gcc.gnu.org> On Behalf Of Robin Dapp via Gcc-patches
Sent: Thursday, May 25, 2023 5:03 PM
To: gcc-patches <gcc-patches@gcc.gnu.org>; Kito Cheng <kito.cheng@gmail.com>; palmer <palmer@dabbelt.com>; juzhe.zhong@rivai.ai; jeffreyalaw <jeffreyalaw@gmail.com>
Cc: rdapp.gcc@gmail.com
Subject: [PATCH] RISC-V: Add autovec sign/zero extension and truncation.

Hi,

this patch implements the autovec expanders for sign and zero extension patterns as well as the accompanying truncations.  In order to use them additional mode_attr iterators as well as vectorizer hooks are required.
Using these hooks we can e.g. vectorize with VNx4QImode as base mode and extend VNx4SI to VNx4DI.  They are still going to be expanded in the future.

vf4 and vf8 truncations are emulated by truncating two and three times respectively.

The patch also adds tests and changes some expectations for already existing ones.

Combine does not yet handle binary operations of two widened operands as we are missing the necessary split/rewrite patterns.  These will be added at a later time.

Co-authored-by: Juzhe Zhong <juzhe.zhong@rivai.ai>

riscv.exp testsuite is unchanged.  zero-scratch-regs-3.c seems to FAIL in vcondu but that already happens on trunk.

Regards
 Robin

gcc/ChangeLog:

	* config/riscv/autovec.md (<optab><v_double_trunc><mode>2): New
	expander.
	(<optab><v_quad_trunc><mode>2): Dito.
	(<optab><v_oct_trunc><mode>2): Dito.
	(trunc<mode><v_double_trunc>2): Dito.
	(trunc<mode><v_quad_trunc>2): Dito.
	(trunc<mode><v_oct_trunc>2): Dito.
	* config/riscv/riscv-protos.h (riscv_v_ext_mode_p): Declare.
	(vectorize_related_mode): Define.
	(autovectorize_vector_modes): Define.
	* config/riscv/riscv-v.cc (vectorize_related_mode): Implement
	hook.
	(autovectorize_vector_modes): Implement hook.
	* config/riscv/riscv.cc (riscv_v_ext_tuple_mode_p): Export.
	(riscv_autovectorize_vector_modes): Implement target hook.
	(riscv_vectorize_related_mode): Implement target hook.
	(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES): Define.
	(TARGET_VECTORIZE_RELATED_MODE): Define.
	* config/riscv/vector-iterators.md: Add lowercase versions of
	mode_attr iterators.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adjust
	expectation.
	* gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-run.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vdiv-template.h: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64d-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64f-2.c: Dito.
	* gcc.target/riscv/rvv/autovec/zve64x-2.c: Dito.
	* gcc.target/riscv/rvv/rvv.exp: Add new conversion tests.
	* gcc.target/riscv/rvv/vsetvl/avl_single-38.c: Do not vectorize.
	* gcc.target/riscv/rvv/vsetvl/avl_single-47.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/avl_single-49.c: Dito.
	* gcc.target/riscv/rvv/vsetvl/imm_switch-8.c: Dito.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vsext-template.h: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-run.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/conversions/vzext-template.h: New test.
---
 gcc/config/riscv/autovec.md                   | 104 ++++++++++++++++++
 gcc/config/riscv/riscv-protos.h               |   5 +
 gcc/config/riscv/riscv-v.cc                   |  83 ++++++++++++++
 gcc/config/riscv/riscv.cc                     |  31 +++++-
 gcc/config/riscv/vector-iterators.md          |  33 +++++-
 .../riscv/rvv/autovec/binop/shift-rv32gcv.c   |   1 -
 .../riscv/rvv/autovec/binop/shift-rv64gcv.c   |   5 +-
 .../riscv/rvv/autovec/binop/vdiv-run.c        |   4 +-
 .../riscv/rvv/autovec/binop/vdiv-rv32gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vdiv-rv64gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vdiv-template.h   |   5 +-
 .../riscv/rvv/autovec/binop/vrem-rv32gcv.c    |   7 +-
 .../riscv/rvv/autovec/binop/vrem-rv64gcv.c    |   7 +-
 .../riscv/rvv/autovec/conversions/vncvt-run.c |  35 ++++++
 .../rvv/autovec/conversions/vncvt-rv32gcv.c   |   6 +
 .../rvv/autovec/conversions/vncvt-rv64gcv.c   |   6 +
 .../rvv/autovec/conversions/vncvt-template.h  |  19 ++++  .../riscv/rvv/autovec/conversions/vsext-run.c |  35 ++++++
 .../rvv/autovec/conversions/vsext-rv32gcv.c   |   8 ++
 .../rvv/autovec/conversions/vsext-rv64gcv.c   |   8 ++
 .../rvv/autovec/conversions/vsext-template.h  |  19 ++++  .../riscv/rvv/autovec/conversions/vzext-run.c |  35 ++++++
 .../rvv/autovec/conversions/vzext-rv32gcv.c   |   8 ++
 .../rvv/autovec/conversions/vzext-rv64gcv.c   |   8 ++
 .../rvv/autovec/conversions/vzext-template.h  |  19 ++++
 .../riscv/rvv/autovec/zve32f_zvl128b-2.c      |   2 +-
 .../riscv/rvv/autovec/zve32x_zvl128b-2.c      |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64d-2.c   |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64f-2.c   |   2 +-
 .../gcc.target/riscv/rvv/autovec/zve64x-2.c   |   2 +-
 gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |   2 +
 .../riscv/rvv/vsetvl/avl_single-38.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-47.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-48.c          |   2 +-
 .../riscv/rvv/vsetvl/avl_single-49.c          |   2 +-
 .../riscv/rvv/vsetvl/imm_switch-8.c           |   2 +-
 36 files changed, 491 insertions(+), 36 deletions(-)  create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h

diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index 1c03468c2f4..c2f2d5083db 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -373,3 +373,107 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
 )
+
+;;
+-----------------------------------------------------------------------
+--
+;; ---- [INT] Sign and zero extension
+;;
+-----------------------------------------------------------------------
+--
+;; Includes:
+;; - vzext.vf[2|4|8]
+;; - vsext.vf[2|4|8]
+;;
+-----------------------------------------------------------------------
+--
+
+(define_expand "<optab><v_double_trunc><mode>2"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+    (any_extend:VWEXTI
+     (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, 
+operands);
+  DONE;
+})
+
+(define_expand "<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"
+{
+  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"
+  [(set (match_operand:VOEXTI 0 "register_operand")
+    (any_extend:VOEXTI
+     (match_operand:<V_OCT_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, 
+operands);
+  DONE;
+})
+
+;;
+-----------------------------------------------------------------------
+--
+;; ---- [INT] Truncation
+;;
+-----------------------------------------------------------------------
+--
+;; - vncvt.x.x.w
+;;
+-----------------------------------------------------------------------
+-- (define_expand "trunc<mode><v_double_trunc>2"
+  [(set (match_operand:<V_DOUBLE_TRUNC> 0 "register_operand")
+    (truncate:<V_DOUBLE_TRUNC>
+     (match_operand:VWEXTI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_trunc (<MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, 
+operands);
+  DONE;
+})
+
+;;
+-----------------------------------------------------------------------
+-- ;; Truncation to a mode whose inner mode size is a quarter of 
+mode's.
+;; We emulate this with two consecutive vncvts.
+;;
+-----------------------------------------------------------------------
+-- (define_expand "trunc<mode><v_quad_trunc>2"
+  [(set (match_operand:<V_QUAD_TRUNC> 0 "register_operand")
+    (truncate:<V_QUAD_TRUNC>
+     (match_operand:VQEXTI 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 ops[] = {operands[0], half};
+  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  DONE;
+})
+
+;;
+-----------------------------------------------------------------------
+-- ;; Truncation to a mode whose inner mode size is an eigth of mode's.
+;; We emulate this with three consecutive vncvts.
+;;
+-----------------------------------------------------------------------
+-- (define_expand "trunc<mode><v_oct_trunc>2"
+  [(set (match_operand:<V_OCT_TRUNC> 0 "register_operand")
+    (truncate:<V_OCT_TRUNC>
+     (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);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 5f78fd579bb..6219cff1354 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -81,6 +81,7 @@ extern void riscv_reinit (void);  extern poly_uint64 riscv_regmode_natural_size (machine_mode);  extern bool riscv_v_ext_vector_mode_p (machine_mode);  extern bool riscv_v_ext_tuple_mode_p (machine_mode);
+extern bool riscv_v_ext_mode_p (machine_mode mode);
 extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);  extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);  extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *); @@ -253,6 +254,10 @@ enum frm_field_enum
   FRM_RMM = 0b100,
   DYN = 0b111
 };
+
+opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode,
+					 poly_uint64);
+unsigned int autovectorize_vector_modes (vec<machine_mode> *, bool);
 }
 
 /* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index f71ad9e46a1..18b39093495 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1396,9 +1396,92 @@ get_cmp_insn_code (rtx_code code, machine_mode mode)
     default:
       gcc_unreachable ();
     }
+
   return icode;
 }
 
+/* This hook gives the vectorizer more vector mode options.  We want it to not
+   only try modes with the maximum number of units a full vector can hold but
+   for example also half the number of units for a smaller elements size.
+   Such vectors can be promoted to a full vector of widened elements
+   (still with the same number of elements, essentially vectorizing at a
+   fixed number of units rather than a fixed number of bytes).  */ 
+unsigned int autovectorize_vector_modes (vector_modes *modes, bool) {
+  if (TARGET_VECTOR)
+    {
+      /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+      poly_uint64 full_size
+	= BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul);
+
+      /* Start with a VNxYYQImode where YY is the number of units that
+	 fit a whole vector.
+	 Then try YY = nunits / 2, nunits / 4 and nunits / 8 which
+	 is guided by the extensions we have available (vf2, vf4 and vf8).
+
+	 - full_size: Try using full vectors for all element types.
+	 - full_size / 2:
+	   Try using 16-bit containers for 8-bit elements and full vectors
+	   for wider elements.
+	 - full_size / 4:
+	   Try using 32-bit containers for 8-bit and 16-bit elements and
+	   full vectors for wider elements.
+	 - full_size / 8:
+	   Try using 64-bit containers for all element types.  */
+      static const int rvv_factors[] = {1, 2, 4, 8};
+      for (unsigned int i = 0; i < sizeof (rvv_factors) / sizeof (int); i++)
+	{
+	  poly_uint64 units;
+	  machine_mode mode;
+	  if (can_div_trunc_p (full_size, rvv_factors[i], &units)
+	      && get_vector_mode (QImode, units).exists (&mode))
+	    modes->safe_push (mode);
+	}
+    }
+  return 0;
+}
+
+/* If the given VECTOR_MODE is an RVV mode,  first get the largest number
+   of units that fit into a full vector at the given ELEMENT_MODE.
+   We will have the vectorizer call us with a successively decreasing
+   number of units (as specified in autovectorize_vector_modes).
+   The starting mode is always the one specified by 
+preferred_simd_mode. */ opt_machine_mode vectorize_related_mode 
+(machine_mode vector_mode, scalar_mode element_mode,
+			poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the 
+future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_mode_p (vector_mode)
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+		     GET_MODE_SIZE (element_mode), &min_units))
+    {
+      machine_mode rvv_mode;
+      if (maybe_ne (nunits, 0U))
+	{
+	  /* If we were given a number of units NUNITS, try to find an
+	     RVV vector mode of inner mode ELEMENT_MODE with the same
+	     number of units.  */
+	  if (multiple_p (min_units, nunits)
+	      && get_vector_mode (element_mode, nunits).exists (&rvv_mode))
+	    return rvv_mode;
+	}
+      else
+	{
+	  /* Look for a vector mode with the same number of units as the
+	     VECTOR_MODE we were given.  We keep track of the minimum
+	     number of units so far which determines the smallest necessary
+	     but largest possible, suitable mode for vectorization.  */
+	  min_units = ordered_min (min_units, GET_MODE_SIZE (vector_mode));
+	  if (get_vector_mode (element_mode, min_units).exists (&rvv_mode))
+	    return rvv_mode;
+	}
+    }
+
+  return default_vectorize_related_mode (vector_mode, element_mode, 
+nunits); }
+
 /* Expand an RVV comparison.  */
 
 void
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 23040557881..3dfccd3a8c3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1031,7 +1031,7 @@ riscv_v_ext_tuple_mode_p (machine_mode mode)
 
 /* Return true if it is either RVV vector mode or RVV tuple mode.  */
 
-static bool
+bool
 riscv_v_ext_mode_p (machine_mode mode)
 {
   return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode); @@ -7616,6 +7616,28 @@ riscv_mode_priority (int, int n)
   return n;
 }
 
+/* Implement TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES.  */ unsigned 
+int riscv_autovectorize_vector_modes (vector_modes *modes, bool all) {
+  if (TARGET_VECTOR)
+    return riscv_vector::autovectorize_vector_modes (modes, all);
+
+  return default_autovectorize_vector_modes (modes, all); }
+
+/* Implement TARGET_VECTORIZE_RELATED_MODE.  */ opt_machine_mode 
+riscv_vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+			      poly_uint64 nunits)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::vectorize_related_mode (vector_mode, element_mode,
+						 nunits);
+  return default_vectorize_related_mode (vector_mode, element_mode, 
+nunits); }
+
+
 /* Initialize the GCC target structure.  */  #undef TARGET_ASM_ALIGNED_HI_OP  #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -7907,6 +7929,13 @@ riscv_mode_priority (int, int n)  #undef TARGET_MODE_PRIORITY  #define TARGET_MODE_PRIORITY riscv_mode_priority
 
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
+  riscv_autovectorize_vector_modes
+
+#undef TARGET_VECTORIZE_RELATED_MODE
+#define TARGET_VECTORIZE_RELATED_MODE riscv_vectorize_related_mode
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 3096ac5be3c..70fb5b80b1b 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -1118,8 +1118,10 @@ (define_mode_attr V_DOUBLE_TRUNC [
   (VNx16HI "VNx16QI") (VNx32HI "VNx32QI") (VNx64HI "VNx64QI")
   (VNx1SI "VNx1HI") (VNx2SI "VNx2HI") (VNx4SI "VNx4HI") (VNx8SI "VNx8HI")
   (VNx16SI "VNx16HI") (VNx32SI "VNx32HI")
-  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI") (VNx16DI "VNx16SI")
-  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF") (VNx16DF "VNx16SF")
+  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI
+ "VNx8SI")  (VNx16DI "VNx16SI")  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") 
+ (VNx4DF "VNx4SF") (VNx8DF "VNx8SF")  (VNx16DF "VNx16SF")
 ])
 
 (define_mode_attr V_QUAD_TRUNC [
@@ -1130,7 +1132,32 @@ (define_mode_attr V_QUAD_TRUNC [
 ])
 
 (define_mode_attr V_OCT_TRUNC [
-  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI") (VNx16DI "VNx16QI")
+  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI
+"VNx8QI")
+  (VNx16DI "VNx16QI")
+])
+
+; Again in lower case.
+(define_mode_attr v_double_trunc [
+  (VNx1HI "vnx1qi") (VNx2HI "vnx2qi")  (VNx4HI "vnx4qi")  (VNx8HI
+"vnx8qi")
+  (VNx16HI "vnx16qi") (VNx32HI "vnx32qi") (VNx64HI "vnx64qi")
+  (VNx1SI "vnx1hi") (VNx2SI "vnx2hi") (VNx4SI "vnx4hi") (VNx8SI
+"vnx8hi")
+  (VNx16SI "vnx16hi") (VNx32SI "vnx32hi")
+  (VNx1DI "vnx1si") (VNx2DI "vnx2si") (VNx4DI "vnx4si") (VNx8DI
+"vnx8si")
+  (VNx16DI "vnx16si")
+  (VNx1DF "vnx1sf") (VNx2DF "vnx2sf") (VNx4DF "vnx4sf") (VNx8DF
+"vnx8sf")
+  (VNx16DF "vnx16sf")
+])
+
+(define_mode_attr v_quad_trunc [
+  (VNx1SI "vnx1qi") (VNx2SI "vnx2qi") (VNx4SI "vnx4qi") (VNx8SI
+"vnx8qi")
+  (VNx16SI "vnx16qi") (VNx32SI "vnx32qi")
+  (VNx1DI "vnx1hi") (VNx2DI "vnx2hi") (VNx4DI "vnx4hi") (VNx8DI
+"vnx8hi")
+  (VNx16DI "vnx16hi")
+])
+
+(define_mode_attr v_oct_trunc [
+  (VNx1DI "vnx1qi") (VNx2DI "vnx2qi") (VNx4DI "vnx4qi") (VNx8DI
+"vnx8qi")
+  (VNx16DI "vnx16qi")
 ])
 
 (define_mode_attr VINDEX_DOUBLE_TRUNC [ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
index d98100b3276..557a7c82531 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
@@ -10,4 +10,3 @@
 /* { dg-final { scan-assembler {\tvsll\.vv} } } */
 /* { dg-final { scan-assembler {\tvsrl\.vv} } } */
 /* { dg-final { scan-assembler {\tvsra\.vv} } } */
-
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
index d9109fd8774..01a9cb21efc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
@@ -3,9 +3,6 @@
 
 #include "shift-template.h"
 
-/* TODO: For int16_t and uint16_t we need widening/promotion patterns.
-   Therefore, expect only 4 vsll.vv instead of 6 for now.  */
-
-/* { dg-final { scan-assembler-times {\tvsll\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {\tvsll\.vv} 6 } } */
 /* { dg-final { scan-assembler-times {\tvsrl\.vv} 3 } } */
 /* { dg-final { scan-assembler-times {\tvsra\.vv} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
index aa9a3c55abe..5de339172fc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
@@ -15,7 +15,7 @@
     a##TYPE[i] = VAL * 3;       		\
     b##TYPE[i] = VAL;           		\
   }                             		\
-  vadd_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ);	\
+  vdiv_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ);	\
   for (int i = 0; i < SZ; i++)			\
     assert (a##TYPE[i] == 3);
 
@@ -23,7 +23,7 @@
   TYPE as##TYPE[SZ];				\
   for (int i = 0; i < SZ; i++)			\
     as##TYPE[i] = VAL * 5;			\
-  vadds_##TYPE (as##TYPE, as##TYPE, VAL, SZ);	\
+  vdivs_##TYPE (as##TYPE, as##TYPE, VAL, SZ);	\
   for (int i = 0; i < SZ; i++)			\
     assert (as##TYPE[i] == 5);
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
index 9759401b9ef..1dce9dd562e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
@@ -3,7 +3,8 @@
 
 #include "vdiv-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
index 7d9b75ae0b1..16a18c466e0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
@@ -3,7 +3,8 @@
 
 #include "vdiv-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
index 12a1de32874..f8d3bfde4ed 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
@@ -2,7 +2,7 @@
 
 #define TEST_TYPE(TYPE) 				\
   __attribute__((noipa))				\
-  void vadd_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n)	\
+  void vdiv_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n)	\
   {							\
     for (int i = 0; i < n; i++)				\
       dst[i] = a[i] / b[i];				\
@@ -10,13 +10,12 @@
 
 #define TEST2_TYPE(TYPE) 				\
   __attribute__((noipa))				\
-  void vadds_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n)	\
+  void vdivs_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n)	\
   {							\
     for (int i = 0; i < n; i++)				\
       dst[i] = a[i] / b;				\
   }
 
-/* *int8_t not autovec currently. */
 #define TEST_ALL()	\
  TEST_TYPE(int16_t)	\
  TEST_TYPE(uint16_t)	\
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
index 28cba510a93..df99f5019fb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
@@ -3,7 +3,8 @@
 
 #include "vrem-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
index 5b6961d1f63..3cff13a47e4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
@@ -3,7 +3,8 @@
 
 #include "vrem-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
new file mode 100644
index 00000000000..f55d2dfce7f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i;             		\
+    dst##TYPE1##TYPE2[i] = -1;				\
+  }                             			\
+  vncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL()					\
+ RUN(uint16_t, uint8_t)					\
+ RUN(uint32_t, uint8_t)					\
+ RUN(uint64_t, uint8_t)					\
+ RUN(uint32_t, uint16_t)				\
+ RUN(uint64_t, uint16_t)				\
+ RUN(uint64_t, uint32_t)				\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
new file mode 100644
index 00000000000..2b5aa0051cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32g
+++ cv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv32gcv -mabi=ilp32d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
new file mode 100644
index 00000000000..29349b33da6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64g
+++ cv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv64gcv -mabi=lp64d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
new file mode 100644
index 00000000000..6b19ff12abe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-templ
+++ ate.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vncvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(uint16_t, uint8_t)					\
+ TEST(uint32_t, uint8_t)					\
+ TEST(uint32_t, uint16_t)					\
+ TEST(uint64_t, uint8_t)					\
+ TEST(uint64_t, uint16_t)					\
+ TEST(uint64_t, uint32_t)					\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
new file mode 100644
index 00000000000..d5f0190957a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i - 128;            		\
+    dst##TYPE1##TYPE2[i] = 0;				\
+  }                             			\
+  vsext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i - 128);
+
+
+#define RUN_ALL()					\
+ RUN(int8_t, int16_t)					\
+ RUN(int8_t, int32_t)					\
+ RUN(int8_t, int64_t)					\
+ RUN(int16_t, int32_t)					\
+ RUN(int16_t, int64_t)					\
+ RUN(int32_t, int64_t)					\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
new file mode 100644
index 00000000000..538216ab9c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv32gcv -mabi=ilp32d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
new file mode 100644
index 00000000000..29348cc67e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv64gcv -mabi=lp64d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
new file mode 100644
index 00000000000..c2f5fc92c99
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-templ
+++ ate.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vsext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(int8_t, int16_t)						\
+ TEST(int8_t, int32_t)						\
+ TEST(int8_t, int64_t)						\
+ TEST(int16_t, int32_t)						\
+ TEST(int16_t, int64_t)						\
+ TEST(int32_t, int64_t)						\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
new file mode 100644
index 00000000000..9d1c259f592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i;             		\
+    dst##TYPE1##TYPE2[i] = -1;				\
+  }                             			\
+  vzext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL()					\
+ RUN(uint8_t, uint16_t)					\
+ RUN(uint8_t, uint32_t)					\
+ RUN(uint8_t, uint64_t)					\
+ RUN(uint16_t, uint32_t)				\
+ RUN(uint16_t, uint64_t)				\
+ RUN(uint32_t, uint64_t)				\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
new file mode 100644
index 00000000000..3e92843a5c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv32gcv -mabi=ilp32d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
new file mode 100644
index 00000000000..cee0012d58c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64g
+++ cv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
+-march=rv64gcv -mabi=lp64d 
+--param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
new file mode 100644
index 00000000000..847905b690c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-templ
+++ ate.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vzext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(uint8_t, uint16_t)					\
+ TEST(uint8_t, uint32_t)					\
+ TEST(uint8_t, uint64_t)					\
+ TEST(uint16_t, uint32_t)					\
+ TEST(uint16_t, uint64_t)					\
+ TEST(uint32_t, uint64_t)					\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
index c53975e9b01..7f499befa82 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 4 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
index 80a4796fd38..2de09a29f02 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
index 5e38b41a5c3..95d54d7b281 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 6 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
index ee37282f1f8..f9f44a94902 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
index 6a64a1a1fdf..12703a7e036 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
@@ -3,4 +3,4 @@
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 
+"vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..9466c2032e3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/conversions/*.\[cS\]]] \
+    "" "$op"
 }
 
 # VLS-VLMAX tests
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
index 34f1cd43a21..8606b10268d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
index 935e1b10630..11403203aa9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
index a1f4b70d4b4..79af2ef450a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
index 4fa68627cc0..77fe05b68a7 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
index 4a1ef3ce5e9..f8568a8c898 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns
+-fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
--
2.40.1
juzhe.zhong@rivai.ai May 26, 2023, 12:53 a.m. UTC | #5
I realize that both TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES and TARGET_VECTORIZE_RELATED_MODE
will partially enable some auto-vectorization even preferred_simd_mode does not enable auto-vectorization
when we don't specify --param=riscv-autovec-preference.

So plz add autovec_use_vlmax_p
into both these target hook implementation.

+opt_machine_mode
+vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+ poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_mode_p (vector_mode)
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+      GET_MODE_SIZE (element_mode), &min_units))

Change it into:

+opt_machine_mode
+vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+ poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_vector_mode_p (vector_mode) &&  autovec_use_vlmax_p ()
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+      GET_MODE_SIZE (element_mode), &min_units))


And

+unsigned int
+autovectorize_vector_modes (vector_modes *modes, bool)
+{
+  if (TARGET_VECTOR)
+    {

You don't need TAREGET_VECTOR since you already gate it in :

+/* Implement TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES.  */
+unsigned int
+riscv_autovectorize_vector_modes (vector_modes *modes, bool all)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::autovectorize_vector_modes (modes, all);
+
+  return default_autovectorize_vector_modes (modes, all);
+}

so plz change it into :

+unsigned int
+autovectorize_vector_modes (vector_modes *modes, bool)
+{
+  if (autovec_use_vlmax_p ())
+    {

Doing this just like in riscv_vector::preferred_simd_modes

Others let Kito chime in more comments.

Thanks.


juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-25 17:03
To: gcc-patches; Kito Cheng; palmer; juzhe.zhong@rivai.ai; jeffreyalaw
CC: rdapp.gcc
Subject: [PATCH] RISC-V: Add autovec sign/zero extension and truncation.
Hi,
 
this patch implements the autovec expanders for sign and zero extension
patterns as well as the accompanying truncations.  In order to use them
additional mode_attr iterators as well as vectorizer hooks are required.
Using these hooks we can e.g. vectorize with VNx4QImode as base mode
and extend VNx4SI to VNx4DI.  They are still going to be expanded in the
future.
 
vf4 and vf8 truncations are emulated by truncating two and three times
respectively.
 
The patch also adds tests and changes some expectations for already
existing ones.
 
Combine does not yet handle binary operations of two widened operands
as we are missing the necessary split/rewrite patterns.  These will be
added at a later time.
 
Co-authored-by: Juzhe Zhong <juzhe.zhong@rivai.ai>
 
riscv.exp testsuite is unchanged.  zero-scratch-regs-3.c seems
to FAIL in vcondu but that already happens on trunk.
 
Regards
Robin
 
gcc/ChangeLog:
 
* config/riscv/autovec.md (<optab><v_double_trunc><mode>2): New
expander.
(<optab><v_quad_trunc><mode>2): Dito.
(<optab><v_oct_trunc><mode>2): Dito.
(trunc<mode><v_double_trunc>2): Dito.
(trunc<mode><v_quad_trunc>2): Dito.
(trunc<mode><v_oct_trunc>2): Dito.
* config/riscv/riscv-protos.h (riscv_v_ext_mode_p): Declare.
(vectorize_related_mode): Define.
(autovectorize_vector_modes): Define.
* config/riscv/riscv-v.cc (vectorize_related_mode): Implement
hook.
(autovectorize_vector_modes): Implement hook.
* config/riscv/riscv.cc (riscv_v_ext_tuple_mode_p): Export.
(riscv_autovectorize_vector_modes): Implement target hook.
(riscv_vectorize_related_mode): Implement target hook.
(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES): Define.
(TARGET_VECTORIZE_RELATED_MODE): Define.
* config/riscv/vector-iterators.md: Add lowercase versions of
mode_attr iterators.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adjust
expectation.
* gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-run.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vdiv-template.h: Dito.
* gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c: Dito.
* gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve64d-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve64f-2.c: Dito.
* gcc.target/riscv/rvv/autovec/zve64x-2.c: Dito.
* gcc.target/riscv/rvv/rvv.exp: Add new conversion tests.
* gcc.target/riscv/rvv/vsetvl/avl_single-38.c: Do not vectorize.
* gcc.target/riscv/rvv/vsetvl/avl_single-47.c: Dito.
* gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Dito.
* gcc.target/riscv/rvv/vsetvl/avl_single-49.c: Dito.
* gcc.target/riscv/rvv/vsetvl/imm_switch-8.c: Dito.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-run.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vsext-template.h: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-run.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/conversions/vzext-template.h: New test.
---
gcc/config/riscv/autovec.md                   | 104 ++++++++++++++++++
gcc/config/riscv/riscv-protos.h               |   5 +
gcc/config/riscv/riscv-v.cc                   |  83 ++++++++++++++
gcc/config/riscv/riscv.cc                     |  31 +++++-
gcc/config/riscv/vector-iterators.md          |  33 +++++-
.../riscv/rvv/autovec/binop/shift-rv32gcv.c   |   1 -
.../riscv/rvv/autovec/binop/shift-rv64gcv.c   |   5 +-
.../riscv/rvv/autovec/binop/vdiv-run.c        |   4 +-
.../riscv/rvv/autovec/binop/vdiv-rv32gcv.c    |   7 +-
.../riscv/rvv/autovec/binop/vdiv-rv64gcv.c    |   7 +-
.../riscv/rvv/autovec/binop/vdiv-template.h   |   5 +-
.../riscv/rvv/autovec/binop/vrem-rv32gcv.c    |   7 +-
.../riscv/rvv/autovec/binop/vrem-rv64gcv.c    |   7 +-
.../riscv/rvv/autovec/conversions/vncvt-run.c |  35 ++++++
.../rvv/autovec/conversions/vncvt-rv32gcv.c   |   6 +
.../rvv/autovec/conversions/vncvt-rv64gcv.c   |   6 +
.../rvv/autovec/conversions/vncvt-template.h  |  19 ++++
.../riscv/rvv/autovec/conversions/vsext-run.c |  35 ++++++
.../rvv/autovec/conversions/vsext-rv32gcv.c   |   8 ++
.../rvv/autovec/conversions/vsext-rv64gcv.c   |   8 ++
.../rvv/autovec/conversions/vsext-template.h  |  19 ++++
.../riscv/rvv/autovec/conversions/vzext-run.c |  35 ++++++
.../rvv/autovec/conversions/vzext-rv32gcv.c   |   8 ++
.../rvv/autovec/conversions/vzext-rv64gcv.c   |   8 ++
.../rvv/autovec/conversions/vzext-template.h  |  19 ++++
.../riscv/rvv/autovec/zve32f_zvl128b-2.c      |   2 +-
.../riscv/rvv/autovec/zve32x_zvl128b-2.c      |   2 +-
.../gcc.target/riscv/rvv/autovec/zve64d-2.c   |   2 +-
.../gcc.target/riscv/rvv/autovec/zve64f-2.c   |   2 +-
.../gcc.target/riscv/rvv/autovec/zve64x-2.c   |   2 +-
gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |   2 +
.../riscv/rvv/vsetvl/avl_single-38.c          |   2 +-
.../riscv/rvv/vsetvl/avl_single-47.c          |   2 +-
.../riscv/rvv/vsetvl/avl_single-48.c          |   2 +-
.../riscv/rvv/vsetvl/avl_single-49.c          |   2 +-
.../riscv/rvv/vsetvl/imm_switch-8.c           |   2 +-
36 files changed, 491 insertions(+), 36 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
 
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 1c03468c2f4..c2f2d5083db 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -373,3 +373,107 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
)
+
+;; -------------------------------------------------------------------------
+;; ---- [INT] Sign and zero extension
+;; -------------------------------------------------------------------------
+;; Includes:
+;; - vzext.vf[2|4|8]
+;; - vsext.vf[2|4|8]
+;; -------------------------------------------------------------------------
+
+(define_expand "<optab><v_double_trunc><mode>2"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+    (any_extend:VWEXTI
+     (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+(define_expand "<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"
+{
+  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"
+  [(set (match_operand:VOEXTI 0 "register_operand")
+    (any_extend:VOEXTI
+     (match_operand:<V_OCT_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; ---- [INT] Truncation
+;; -------------------------------------------------------------------------
+;; - vncvt.x.x.w
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_double_trunc>2"
+  [(set (match_operand:<V_DOUBLE_TRUNC> 0 "register_operand")
+    (truncate:<V_DOUBLE_TRUNC>
+     (match_operand:VWEXTI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_trunc (<MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Truncation to a mode whose inner mode size is a quarter of mode's.
+;; We emulate this with two consecutive vncvts.
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_quad_trunc>2"
+  [(set (match_operand:<V_QUAD_TRUNC> 0 "register_operand")
+    (truncate:<V_QUAD_TRUNC>
+     (match_operand:VQEXTI 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 ops[] = {operands[0], half};
+  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Truncation to a mode whose inner mode size is an eigth of mode's.
+;; We emulate this with three consecutive vncvts.
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_oct_trunc>2"
+  [(set (match_operand:<V_OCT_TRUNC> 0 "register_operand")
+    (truncate:<V_OCT_TRUNC>
+     (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);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 5f78fd579bb..6219cff1354 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -81,6 +81,7 @@ extern void riscv_reinit (void);
extern poly_uint64 riscv_regmode_natural_size (machine_mode);
extern bool riscv_v_ext_vector_mode_p (machine_mode);
extern bool riscv_v_ext_tuple_mode_p (machine_mode);
+extern bool riscv_v_ext_mode_p (machine_mode mode);
extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);
extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *);
@@ -253,6 +254,10 @@ enum frm_field_enum
   FRM_RMM = 0b100,
   DYN = 0b111
};
+
+opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode,
+ poly_uint64);
+unsigned int autovectorize_vector_modes (vec<machine_mode> *, bool);
}
/* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..18b39093495 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1396,9 +1396,92 @@ get_cmp_insn_code (rtx_code code, machine_mode mode)
     default:
       gcc_unreachable ();
     }
+
   return icode;
}
+/* This hook gives the vectorizer more vector mode options.  We want it to not
+   only try modes with the maximum number of units a full vector can hold but
+   for example also half the number of units for a smaller elements size.
+   Such vectors can be promoted to a full vector of widened elements
+   (still with the same number of elements, essentially vectorizing at a
+   fixed number of units rather than a fixed number of bytes).  */
+unsigned int
+autovectorize_vector_modes (vector_modes *modes, bool)
+{
+  if (TARGET_VECTOR)
+    {
+      /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+      poly_uint64 full_size
+ = BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul);
+
+      /* Start with a VNxYYQImode where YY is the number of units that
+ fit a whole vector.
+ Then try YY = nunits / 2, nunits / 4 and nunits / 8 which
+ is guided by the extensions we have available (vf2, vf4 and vf8).
+
+ - full_size: Try using full vectors for all element types.
+ - full_size / 2:
+    Try using 16-bit containers for 8-bit elements and full vectors
+    for wider elements.
+ - full_size / 4:
+    Try using 32-bit containers for 8-bit and 16-bit elements and
+    full vectors for wider elements.
+ - full_size / 8:
+    Try using 64-bit containers for all element types.  */
+      static const int rvv_factors[] = {1, 2, 4, 8};
+      for (unsigned int i = 0; i < sizeof (rvv_factors) / sizeof (int); i++)
+ {
+   poly_uint64 units;
+   machine_mode mode;
+   if (can_div_trunc_p (full_size, rvv_factors[i], &units)
+       && get_vector_mode (QImode, units).exists (&mode))
+     modes->safe_push (mode);
+ }
+    }
+  return 0;
+}
+
+/* If the given VECTOR_MODE is an RVV mode,  first get the largest number
+   of units that fit into a full vector at the given ELEMENT_MODE.
+   We will have the vectorizer call us with a successively decreasing
+   number of units (as specified in autovectorize_vector_modes).
+   The starting mode is always the one specified by preferred_simd_mode. */
+opt_machine_mode
+vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+ poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_mode_p (vector_mode)
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+      GET_MODE_SIZE (element_mode), &min_units))
+    {
+      machine_mode rvv_mode;
+      if (maybe_ne (nunits, 0U))
+ {
+   /* If we were given a number of units NUNITS, try to find an
+      RVV vector mode of inner mode ELEMENT_MODE with the same
+      number of units.  */
+   if (multiple_p (min_units, nunits)
+       && get_vector_mode (element_mode, nunits).exists (&rvv_mode))
+     return rvv_mode;
+ }
+      else
+ {
+   /* Look for a vector mode with the same number of units as the
+      VECTOR_MODE we were given.  We keep track of the minimum
+      number of units so far which determines the smallest necessary
+      but largest possible, suitable mode for vectorization.  */
+   min_units = ordered_min (min_units, GET_MODE_SIZE (vector_mode));
+   if (get_vector_mode (element_mode, min_units).exists (&rvv_mode))
+     return rvv_mode;
+ }
+    }
+
+  return default_vectorize_related_mode (vector_mode, element_mode, nunits);
+}
+
/* Expand an RVV comparison.  */
void
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 23040557881..3dfccd3a8c3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1031,7 +1031,7 @@ riscv_v_ext_tuple_mode_p (machine_mode mode)
/* Return true if it is either RVV vector mode or RVV tuple mode.  */
-static bool
+bool
riscv_v_ext_mode_p (machine_mode mode)
{
   return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode);
@@ -7616,6 +7616,28 @@ riscv_mode_priority (int, int n)
   return n;
}
+/* Implement TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES.  */
+unsigned int
+riscv_autovectorize_vector_modes (vector_modes *modes, bool all)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::autovectorize_vector_modes (modes, all);
+
+  return default_autovectorize_vector_modes (modes, all);
+}
+
+/* Implement TARGET_VECTORIZE_RELATED_MODE.  */
+opt_machine_mode
+riscv_vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+       poly_uint64 nunits)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::vectorize_related_mode (vector_mode, element_mode,
+ nunits);
+  return default_vectorize_related_mode (vector_mode, element_mode, nunits);
+}
+
+
/* Initialize the GCC target structure.  */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -7907,6 +7929,13 @@ riscv_mode_priority (int, int n)
#undef TARGET_MODE_PRIORITY
#define TARGET_MODE_PRIORITY riscv_mode_priority
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
+  riscv_autovectorize_vector_modes
+
+#undef TARGET_VECTORIZE_RELATED_MODE
+#define TARGET_VECTORIZE_RELATED_MODE riscv_vectorize_related_mode
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-riscv.h"
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 3096ac5be3c..70fb5b80b1b 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -1118,8 +1118,10 @@ (define_mode_attr V_DOUBLE_TRUNC [
   (VNx16HI "VNx16QI") (VNx32HI "VNx32QI") (VNx64HI "VNx64QI")
   (VNx1SI "VNx1HI") (VNx2SI "VNx2HI") (VNx4SI "VNx4HI") (VNx8SI "VNx8HI")
   (VNx16SI "VNx16HI") (VNx32SI "VNx32HI")
-  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI") (VNx16DI "VNx16SI")
-  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF") (VNx16DF "VNx16SF")
+  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI")
+  (VNx16DI "VNx16SI")
+  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF")
+  (VNx16DF "VNx16SF")
])
(define_mode_attr V_QUAD_TRUNC [
@@ -1130,7 +1132,32 @@ (define_mode_attr V_QUAD_TRUNC [
])
(define_mode_attr V_OCT_TRUNC [
-  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI") (VNx16DI "VNx16QI")
+  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI")
+  (VNx16DI "VNx16QI")
+])
+
+; Again in lower case.
+(define_mode_attr v_double_trunc [
+  (VNx1HI "vnx1qi") (VNx2HI "vnx2qi")  (VNx4HI "vnx4qi")  (VNx8HI "vnx8qi")
+  (VNx16HI "vnx16qi") (VNx32HI "vnx32qi") (VNx64HI "vnx64qi")
+  (VNx1SI "vnx1hi") (VNx2SI "vnx2hi") (VNx4SI "vnx4hi") (VNx8SI "vnx8hi")
+  (VNx16SI "vnx16hi") (VNx32SI "vnx32hi")
+  (VNx1DI "vnx1si") (VNx2DI "vnx2si") (VNx4DI "vnx4si") (VNx8DI "vnx8si")
+  (VNx16DI "vnx16si")
+  (VNx1DF "vnx1sf") (VNx2DF "vnx2sf") (VNx4DF "vnx4sf") (VNx8DF "vnx8sf")
+  (VNx16DF "vnx16sf")
+])
+
+(define_mode_attr v_quad_trunc [
+  (VNx1SI "vnx1qi") (VNx2SI "vnx2qi") (VNx4SI "vnx4qi") (VNx8SI "vnx8qi")
+  (VNx16SI "vnx16qi") (VNx32SI "vnx32qi")
+  (VNx1DI "vnx1hi") (VNx2DI "vnx2hi") (VNx4DI "vnx4hi") (VNx8DI "vnx8hi")
+  (VNx16DI "vnx16hi")
+])
+
+(define_mode_attr v_oct_trunc [
+  (VNx1DI "vnx1qi") (VNx2DI "vnx2qi") (VNx4DI "vnx4qi") (VNx8DI "vnx8qi")
+  (VNx16DI "vnx16qi")
])
(define_mode_attr VINDEX_DOUBLE_TRUNC [
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
index d98100b3276..557a7c82531 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
@@ -10,4 +10,3 @@
/* { dg-final { scan-assembler {\tvsll\.vv} } } */
/* { dg-final { scan-assembler {\tvsrl\.vv} } } */
/* { dg-final { scan-assembler {\tvsra\.vv} } } */
-
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
index d9109fd8774..01a9cb21efc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
@@ -3,9 +3,6 @@
#include "shift-template.h"
-/* TODO: For int16_t and uint16_t we need widening/promotion patterns.
-   Therefore, expect only 4 vsll.vv instead of 6 for now.  */
-
-/* { dg-final { scan-assembler-times {\tvsll\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {\tvsll\.vv} 6 } } */
/* { dg-final { scan-assembler-times {\tvsrl\.vv} 3 } } */
/* { dg-final { scan-assembler-times {\tvsra\.vv} 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
index aa9a3c55abe..5de339172fc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
@@ -15,7 +15,7 @@
     a##TYPE[i] = VAL * 3;       \
     b##TYPE[i] = VAL;           \
   }                             \
-  vadd_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ); \
+  vdiv_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ); \
   for (int i = 0; i < SZ; i++) \
     assert (a##TYPE[i] == 3);
@@ -23,7 +23,7 @@
   TYPE as##TYPE[SZ]; \
   for (int i = 0; i < SZ; i++) \
     as##TYPE[i] = VAL * 5; \
-  vadds_##TYPE (as##TYPE, as##TYPE, VAL, SZ); \
+  vdivs_##TYPE (as##TYPE, as##TYPE, VAL, SZ); \
   for (int i = 0; i < SZ; i++) \
     assert (as##TYPE[i] == 5);
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
index 9759401b9ef..1dce9dd562e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
@@ -3,7 +3,8 @@
#include "vdiv-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
index 7d9b75ae0b1..16a18c466e0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
@@ -3,7 +3,8 @@
#include "vdiv-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
index 12a1de32874..f8d3bfde4ed 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
@@ -2,7 +2,7 @@
#define TEST_TYPE(TYPE) \
   __attribute__((noipa)) \
-  void vadd_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n) \
+  void vdiv_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n) \
   { \
     for (int i = 0; i < n; i++) \
       dst[i] = a[i] / b[i]; \
@@ -10,13 +10,12 @@
#define TEST2_TYPE(TYPE) \
   __attribute__((noipa)) \
-  void vadds_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n) \
+  void vdivs_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n) \
   { \
     for (int i = 0; i < n; i++) \
       dst[i] = a[i] / b; \
   }
-/* *int8_t not autovec currently. */
#define TEST_ALL() \
  TEST_TYPE(int16_t) \
  TEST_TYPE(uint16_t) \
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
index 28cba510a93..df99f5019fb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
@@ -3,7 +3,8 @@
#include "vrem-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
index 5b6961d1f63..3cff13a47e4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
@@ -3,7 +3,8 @@
#include "vrem-template.h"
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
new file mode 100644
index 00000000000..f55d2dfce7f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2) \
+  TYPE1 src##TYPE1##TYPE2[SZ]; \
+  TYPE2 dst##TYPE1##TYPE2[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    src##TYPE1##TYPE2[i] = i;             \
+    dst##TYPE1##TYPE2[i] = -1; \
+  }                             \
+  vncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \
+ src##TYPE1##TYPE2, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL() \
+ RUN(uint16_t, uint8_t) \
+ RUN(uint32_t, uint8_t) \
+ RUN(uint64_t, uint8_t) \
+ RUN(uint32_t, uint16_t) \
+ RUN(uint64_t, uint16_t) \
+ RUN(uint64_t, uint32_t) \
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
new file mode 100644
index 00000000000..2b5aa0051cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
new file mode 100644
index 00000000000..29349b33da6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
new file mode 100644
index 00000000000..6b19ff12abe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2) \
+  __attribute__((noipa)) \
+  void vncvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = (TYPE1)a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST(uint16_t, uint8_t) \
+ TEST(uint32_t, uint8_t) \
+ TEST(uint32_t, uint16_t) \
+ TEST(uint64_t, uint8_t) \
+ TEST(uint64_t, uint16_t) \
+ TEST(uint64_t, uint32_t) \
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
new file mode 100644
index 00000000000..d5f0190957a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2) \
+  TYPE1 src##TYPE1##TYPE2[SZ]; \
+  TYPE2 dst##TYPE1##TYPE2[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    src##TYPE1##TYPE2[i] = i - 128;            \
+    dst##TYPE1##TYPE2[i] = 0; \
+  }                             \
+  vsext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \
+ src##TYPE1##TYPE2, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (dst##TYPE1##TYPE2[i] == i - 128);
+
+
+#define RUN_ALL() \
+ RUN(int8_t, int16_t) \
+ RUN(int8_t, int32_t) \
+ RUN(int8_t, int64_t) \
+ RUN(int16_t, int32_t) \
+ RUN(int16_t, int64_t) \
+ RUN(int32_t, int64_t) \
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
new file mode 100644
index 00000000000..538216ab9c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
new file mode 100644
index 00000000000..29348cc67e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
new file mode 100644
index 00000000000..c2f5fc92c99
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2) \
+  __attribute__((noipa)) \
+  void vsext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = (TYPE1)a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST(int8_t, int16_t) \
+ TEST(int8_t, int32_t) \
+ TEST(int8_t, int64_t) \
+ TEST(int16_t, int32_t) \
+ TEST(int16_t, int64_t) \
+ TEST(int32_t, int64_t) \
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
new file mode 100644
index 00000000000..9d1c259f592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2) \
+  TYPE1 src##TYPE1##TYPE2[SZ]; \
+  TYPE2 dst##TYPE1##TYPE2[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    src##TYPE1##TYPE2[i] = i;             \
+    dst##TYPE1##TYPE2[i] = -1; \
+  }                             \
+  vzext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2, \
+ src##TYPE1##TYPE2, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL() \
+ RUN(uint8_t, uint16_t) \
+ RUN(uint8_t, uint32_t) \
+ RUN(uint8_t, uint64_t) \
+ RUN(uint16_t, uint32_t) \
+ RUN(uint16_t, uint64_t) \
+ RUN(uint32_t, uint64_t) \
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
new file mode 100644
index 00000000000..3e92843a5c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
new file mode 100644
index 00000000000..cee0012d58c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
new file mode 100644
index 00000000000..847905b690c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
@@ -0,0 +1,19 @@
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2) \
+  __attribute__((noipa)) \
+  void vzext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = (TYPE1)a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST(uint8_t, uint16_t) \
+ TEST(uint8_t, uint32_t) \
+ TEST(uint8_t, uint64_t) \
+ TEST(uint16_t, uint32_t) \
+ TEST(uint16_t, uint64_t) \
+ TEST(uint32_t, uint64_t) \
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
index c53975e9b01..7f499befa82 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 4 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
index 80a4796fd38..2de09a29f02 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
index 5e38b41a5c3..95d54d7b281 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 6 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
index ee37282f1f8..f9f44a94902 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
index 6a64a1a1fdf..12703a7e036 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
@@ -3,4 +3,4 @@
#include "template-1.h"
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..9466c2032e3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/conversions/*.\[cS\]]] \
+    "" "$op"
}
# VLS-VLMAX tests
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
index 34f1cd43a21..8606b10268d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
index 935e1b10630..11403203aa9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
index a1f4b70d4b4..79af2ef450a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
index 4fa68627cc0..77fe05b68a7 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
index 4a1ef3ce5e9..f8568a8c898 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
#include "riscv_vector.h"
Robin Dapp May 26, 2023, 6:32 a.m. UTC | #6
> I realize that both TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES and
> TARGET_VECTORIZE_RELATED_MODE will partially enable some
> auto-vectorization even preferred_simd_mode does not enable
> auto-vectorization when we don't specify
> --param=riscv-autovec-preference.
> 
> So plz add autovec_use_vlmax_p into both these target hook
> implementation.

Yes, changed it.  I think that's still minor enough as to not warrant
a separate V2.  Will wait for Kito for final verdict on this and
commit with both changes if nothing else comes up.

Regards
 Robin
Jeff Law May 26, 2023, 4:58 p.m. UTC | #7
On 5/25/23 03:03, Robin Dapp wrote:
> Hi,
> 
> this patch implements the autovec expanders for sign and zero extension
> patterns as well as the accompanying truncations.  In order to use them
> additional mode_attr iterators as well as vectorizer hooks are required.
> Using these hooks we can e.g. vectorize with VNx4QImode as base mode
> and extend VNx4SI to VNx4DI.  They are still going to be expanded in the
> future.
> 
> vf4 and vf8 truncations are emulated by truncating two and three times
> respectively.
> 
> The patch also adds tests and changes some expectations for already
> existing ones.
> 
> Combine does not yet handle binary operations of two widened operands
> as we are missing the necessary split/rewrite patterns.  These will be
> added at a later time.
> 
> Co-authored-by: Juzhe Zhong <juzhe.zhong@rivai.ai>
> 
> riscv.exp testsuite is unchanged.  zero-scratch-regs-3.c seems
> to FAIL in vcondu but that already happens on trunk.
Yea, I bisected the zero-scratch-regs-3 failure and passed it off to 
Juzhe last night.  It's already been fixed on the trunk.

> 
> Regards
>   Robin
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/autovec.md (<optab><v_double_trunc><mode>2): New
> 	expander.
> 	(<optab><v_quad_trunc><mode>2): Dito.
> 	(<optab><v_oct_trunc><mode>2): Dito.
> 	(trunc<mode><v_double_trunc>2): Dito.
> 	(trunc<mode><v_quad_trunc>2): Dito.
> 	(trunc<mode><v_oct_trunc>2): Dito.
> 	* config/riscv/riscv-protos.h (riscv_v_ext_mode_p): Declare.
> 	(vectorize_related_mode): Define.
> 	(autovectorize_vector_modes): Define.
> 	* config/riscv/riscv-v.cc (vectorize_related_mode): Implement
> 	hook.
> 	(autovectorize_vector_modes): Implement hook.
> 	* config/riscv/riscv.cc (riscv_v_ext_tuple_mode_p): Export.
> 	(riscv_autovectorize_vector_modes): Implement target hook.
> 	(riscv_vectorize_related_mode): Implement target hook.
> 	(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES): Define.
> 	(TARGET_VECTORIZE_RELATED_MODE): Define.
> 	* config/riscv/vector-iterators.md: Add lowercase versions of
> 	mode_attr iterators.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adjust
> 	expectation.
> 	* gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/binop/vdiv-run.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/binop/vdiv-template.h: Dito.
> 	* gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/zve64d-2.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/zve64f-2.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/zve64x-2.c: Dito.
> 	* gcc.target/riscv/rvv/rvv.exp: Add new conversion tests.
> 	* gcc.target/riscv/rvv/vsetvl/avl_single-38.c: Do not vectorize.
> 	* gcc.target/riscv/rvv/vsetvl/avl_single-47.c: Dito.
> 	* gcc.target/riscv/rvv/vsetvl/avl_single-48.c: Dito.
> 	* gcc.target/riscv/rvv/vsetvl/avl_single-49.c: Dito.
> 	* gcc.target/riscv/rvv/vsetvl/imm_switch-8.c: Dito.
> 	* gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vsext-run.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vsext-template.h: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vzext-run.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/conversions/vzext-template.h: New test.
> ---





> +/* If the given VECTOR_MODE is an RVV mode,  first get the largest number
> +   of units that fit into a full vector at the given ELEMENT_MODE.
> +   We will have the vectorizer call us with a successively decreasing
> +   number of units (as specified in autovectorize_vector_modes).
> +   The starting mode is always the one specified by preferred_simd_mode. */
> +opt_machine_mode
> +vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
> +			poly_uint64 nunits)
> +{
> +  /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
> +  poly_uint64 min_units;
> +  if (riscv_v_ext_mode_p (vector_mode)
I think Juzhe already noted this needs to change.  That may mean the 
code to expose riscv_v_ext_mode_p can be dropped.

OK for the trunk with that change.

jeff
diff mbox series

Patch

diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 1c03468c2f4..c2f2d5083db 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -373,3 +373,107 @@  (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
 )
+
+;; -------------------------------------------------------------------------
+;; ---- [INT] Sign and zero extension
+;; -------------------------------------------------------------------------
+;; Includes:
+;; - vzext.vf[2|4|8]
+;; - vsext.vf[2|4|8]
+;; -------------------------------------------------------------------------
+
+(define_expand "<optab><v_double_trunc><mode>2"
+  [(set (match_operand:VWEXTI 0 "register_operand")
+    (any_extend:VWEXTI
+     (match_operand:<V_DOUBLE_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf2 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+(define_expand "<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"
+{
+  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"
+  [(set (match_operand:VOEXTI 0 "register_operand")
+    (any_extend:VOEXTI
+     (match_operand:<V_OCT_TRUNC> 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_vf8 (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; ---- [INT] Truncation
+;; -------------------------------------------------------------------------
+;; - vncvt.x.x.w
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_double_trunc>2"
+  [(set (match_operand:<V_DOUBLE_TRUNC> 0 "register_operand")
+    (truncate:<V_DOUBLE_TRUNC>
+     (match_operand:VWEXTI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred_trunc (<MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Truncation to a mode whose inner mode size is a quarter of mode's.
+;; We emulate this with two consecutive vncvts.
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_quad_trunc>2"
+  [(set (match_operand:<V_QUAD_TRUNC> 0 "register_operand")
+    (truncate:<V_QUAD_TRUNC>
+     (match_operand:VQEXTI 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 ops[] = {operands[0], half};
+  icode = code_for_pred_trunc (<V_DOUBLE_TRUNC>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, ops);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------
+;; Truncation to a mode whose inner mode size is an eigth of mode's.
+;; We emulate this with three consecutive vncvts.
+;; -------------------------------------------------------------------------
+(define_expand "trunc<mode><v_oct_trunc>2"
+  [(set (match_operand:<V_OCT_TRUNC> 0 "register_operand")
+    (truncate:<V_OCT_TRUNC>
+     (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);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 5f78fd579bb..6219cff1354 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -81,6 +81,7 @@  extern void riscv_reinit (void);
 extern poly_uint64 riscv_regmode_natural_size (machine_mode);
 extern bool riscv_v_ext_vector_mode_p (machine_mode);
 extern bool riscv_v_ext_tuple_mode_p (machine_mode);
+extern bool riscv_v_ext_mode_p (machine_mode mode);
 extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
 extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *);
 extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *);
@@ -253,6 +254,10 @@  enum frm_field_enum
   FRM_RMM = 0b100,
   DYN = 0b111
 };
+
+opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode,
+					 poly_uint64);
+unsigned int autovectorize_vector_modes (vec<machine_mode> *, bool);
 }
 
 /* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..18b39093495 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1396,9 +1396,92 @@  get_cmp_insn_code (rtx_code code, machine_mode mode)
     default:
       gcc_unreachable ();
     }
+
   return icode;
 }
 
+/* This hook gives the vectorizer more vector mode options.  We want it to not
+   only try modes with the maximum number of units a full vector can hold but
+   for example also half the number of units for a smaller elements size.
+   Such vectors can be promoted to a full vector of widened elements
+   (still with the same number of elements, essentially vectorizing at a
+   fixed number of units rather than a fixed number of bytes).  */
+unsigned int
+autovectorize_vector_modes (vector_modes *modes, bool)
+{
+  if (TARGET_VECTOR)
+    {
+      /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+      poly_uint64 full_size
+	= BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul);
+
+      /* Start with a VNxYYQImode where YY is the number of units that
+	 fit a whole vector.
+	 Then try YY = nunits / 2, nunits / 4 and nunits / 8 which
+	 is guided by the extensions we have available (vf2, vf4 and vf8).
+
+	 - full_size: Try using full vectors for all element types.
+	 - full_size / 2:
+	   Try using 16-bit containers for 8-bit elements and full vectors
+	   for wider elements.
+	 - full_size / 4:
+	   Try using 32-bit containers for 8-bit and 16-bit elements and
+	   full vectors for wider elements.
+	 - full_size / 8:
+	   Try using 64-bit containers for all element types.  */
+      static const int rvv_factors[] = {1, 2, 4, 8};
+      for (unsigned int i = 0; i < sizeof (rvv_factors) / sizeof (int); i++)
+	{
+	  poly_uint64 units;
+	  machine_mode mode;
+	  if (can_div_trunc_p (full_size, rvv_factors[i], &units)
+	      && get_vector_mode (QImode, units).exists (&mode))
+	    modes->safe_push (mode);
+	}
+    }
+  return 0;
+}
+
+/* If the given VECTOR_MODE is an RVV mode,  first get the largest number
+   of units that fit into a full vector at the given ELEMENT_MODE.
+   We will have the vectorizer call us with a successively decreasing
+   number of units (as specified in autovectorize_vector_modes).
+   The starting mode is always the one specified by preferred_simd_mode. */
+opt_machine_mode
+vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+			poly_uint64 nunits)
+{
+  /* TODO: We will support RVV VLS auto-vectorization mode in the future. */
+  poly_uint64 min_units;
+  if (riscv_v_ext_mode_p (vector_mode)
+      && multiple_p (BYTES_PER_RISCV_VECTOR * ((int) riscv_autovec_lmul),
+		     GET_MODE_SIZE (element_mode), &min_units))
+    {
+      machine_mode rvv_mode;
+      if (maybe_ne (nunits, 0U))
+	{
+	  /* If we were given a number of units NUNITS, try to find an
+	     RVV vector mode of inner mode ELEMENT_MODE with the same
+	     number of units.  */
+	  if (multiple_p (min_units, nunits)
+	      && get_vector_mode (element_mode, nunits).exists (&rvv_mode))
+	    return rvv_mode;
+	}
+      else
+	{
+	  /* Look for a vector mode with the same number of units as the
+	     VECTOR_MODE we were given.  We keep track of the minimum
+	     number of units so far which determines the smallest necessary
+	     but largest possible, suitable mode for vectorization.  */
+	  min_units = ordered_min (min_units, GET_MODE_SIZE (vector_mode));
+	  if (get_vector_mode (element_mode, min_units).exists (&rvv_mode))
+	    return rvv_mode;
+	}
+    }
+
+  return default_vectorize_related_mode (vector_mode, element_mode, nunits);
+}
+
 /* Expand an RVV comparison.  */
 
 void
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 23040557881..3dfccd3a8c3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1031,7 +1031,7 @@  riscv_v_ext_tuple_mode_p (machine_mode mode)
 
 /* Return true if it is either RVV vector mode or RVV tuple mode.  */
 
-static bool
+bool
 riscv_v_ext_mode_p (machine_mode mode)
 {
   return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode);
@@ -7616,6 +7616,28 @@  riscv_mode_priority (int, int n)
   return n;
 }
 
+/* Implement TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES.  */
+unsigned int
+riscv_autovectorize_vector_modes (vector_modes *modes, bool all)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::autovectorize_vector_modes (modes, all);
+
+  return default_autovectorize_vector_modes (modes, all);
+}
+
+/* Implement TARGET_VECTORIZE_RELATED_MODE.  */
+opt_machine_mode
+riscv_vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode,
+			      poly_uint64 nunits)
+{
+  if (TARGET_VECTOR)
+    return riscv_vector::vectorize_related_mode (vector_mode, element_mode,
+						 nunits);
+  return default_vectorize_related_mode (vector_mode, element_mode, nunits);
+}
+
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -7907,6 +7929,13 @@  riscv_mode_priority (int, int n)
 #undef TARGET_MODE_PRIORITY
 #define TARGET_MODE_PRIORITY riscv_mode_priority
 
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
+  riscv_autovectorize_vector_modes
+
+#undef TARGET_VECTORIZE_RELATED_MODE
+#define TARGET_VECTORIZE_RELATED_MODE riscv_vectorize_related_mode
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 3096ac5be3c..70fb5b80b1b 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -1118,8 +1118,10 @@  (define_mode_attr V_DOUBLE_TRUNC [
   (VNx16HI "VNx16QI") (VNx32HI "VNx32QI") (VNx64HI "VNx64QI")
   (VNx1SI "VNx1HI") (VNx2SI "VNx2HI") (VNx4SI "VNx4HI") (VNx8SI "VNx8HI")
   (VNx16SI "VNx16HI") (VNx32SI "VNx32HI")
-  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI") (VNx16DI "VNx16SI")
-  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF") (VNx16DF "VNx16SF")
+  (VNx1DI "VNx1SI") (VNx2DI "VNx2SI") (VNx4DI "VNx4SI") (VNx8DI "VNx8SI")
+  (VNx16DI "VNx16SI")
+  (VNx1DF "VNx1SF") (VNx2DF "VNx2SF") (VNx4DF "VNx4SF") (VNx8DF "VNx8SF")
+  (VNx16DF "VNx16SF")
 ])
 
 (define_mode_attr V_QUAD_TRUNC [
@@ -1130,7 +1132,32 @@  (define_mode_attr V_QUAD_TRUNC [
 ])
 
 (define_mode_attr V_OCT_TRUNC [
-  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI") (VNx16DI "VNx16QI")
+  (VNx1DI "VNx1QI") (VNx2DI "VNx2QI") (VNx4DI "VNx4QI") (VNx8DI "VNx8QI")
+  (VNx16DI "VNx16QI")
+])
+
+; Again in lower case.
+(define_mode_attr v_double_trunc [
+  (VNx1HI "vnx1qi") (VNx2HI "vnx2qi")  (VNx4HI "vnx4qi")  (VNx8HI "vnx8qi")
+  (VNx16HI "vnx16qi") (VNx32HI "vnx32qi") (VNx64HI "vnx64qi")
+  (VNx1SI "vnx1hi") (VNx2SI "vnx2hi") (VNx4SI "vnx4hi") (VNx8SI "vnx8hi")
+  (VNx16SI "vnx16hi") (VNx32SI "vnx32hi")
+  (VNx1DI "vnx1si") (VNx2DI "vnx2si") (VNx4DI "vnx4si") (VNx8DI "vnx8si")
+  (VNx16DI "vnx16si")
+  (VNx1DF "vnx1sf") (VNx2DF "vnx2sf") (VNx4DF "vnx4sf") (VNx8DF "vnx8sf")
+  (VNx16DF "vnx16sf")
+])
+
+(define_mode_attr v_quad_trunc [
+  (VNx1SI "vnx1qi") (VNx2SI "vnx2qi") (VNx4SI "vnx4qi") (VNx8SI "vnx8qi")
+  (VNx16SI "vnx16qi") (VNx32SI "vnx32qi")
+  (VNx1DI "vnx1hi") (VNx2DI "vnx2hi") (VNx4DI "vnx4hi") (VNx8DI "vnx8hi")
+  (VNx16DI "vnx16hi")
+])
+
+(define_mode_attr v_oct_trunc [
+  (VNx1DI "vnx1qi") (VNx2DI "vnx2qi") (VNx4DI "vnx4qi") (VNx8DI "vnx8qi")
+  (VNx16DI "vnx16qi")
 ])
 
 (define_mode_attr VINDEX_DOUBLE_TRUNC [
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
index d98100b3276..557a7c82531 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c
@@ -10,4 +10,3 @@ 
 /* { dg-final { scan-assembler {\tvsll\.vv} } } */
 /* { dg-final { scan-assembler {\tvsrl\.vv} } } */
 /* { dg-final { scan-assembler {\tvsra\.vv} } } */
-
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
index d9109fd8774..01a9cb21efc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c
@@ -3,9 +3,6 @@ 
 
 #include "shift-template.h"
 
-/* TODO: For int16_t and uint16_t we need widening/promotion patterns.
-   Therefore, expect only 4 vsll.vv instead of 6 for now.  */
-
-/* { dg-final { scan-assembler-times {\tvsll\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {\tvsll\.vv} 6 } } */
 /* { dg-final { scan-assembler-times {\tvsrl\.vv} 3 } } */
 /* { dg-final { scan-assembler-times {\tvsra\.vv} 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
index aa9a3c55abe..5de339172fc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-run.c
@@ -15,7 +15,7 @@ 
     a##TYPE[i] = VAL * 3;       		\
     b##TYPE[i] = VAL;           		\
   }                             		\
-  vadd_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ);	\
+  vdiv_##TYPE (a##TYPE, a##TYPE, b##TYPE, SZ);	\
   for (int i = 0; i < SZ; i++)			\
     assert (a##TYPE[i] == 3);
 
@@ -23,7 +23,7 @@ 
   TYPE as##TYPE[SZ];				\
   for (int i = 0; i < SZ; i++)			\
     as##TYPE[i] = VAL * 5;			\
-  vadds_##TYPE (as##TYPE, as##TYPE, VAL, SZ);	\
+  vdivs_##TYPE (as##TYPE, as##TYPE, VAL, SZ);	\
   for (int i = 0; i < SZ; i++)			\
     assert (as##TYPE[i] == 5);
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
index 9759401b9ef..1dce9dd562e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
@@ -3,7 +3,8 @@ 
 
 #include "vdiv-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
index 7d9b75ae0b1..16a18c466e0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
@@ -3,7 +3,8 @@ 
 
 #include "vdiv-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vdiv.vv here.  */
+/* Currently we use an epilogue loop which also contains vdivs.  Therefore we
+   expect 10 vdiv[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdivu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvdivu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
index 12a1de32874..f8d3bfde4ed 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-template.h
@@ -2,7 +2,7 @@ 
 
 #define TEST_TYPE(TYPE) 				\
   __attribute__((noipa))				\
-  void vadd_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n)	\
+  void vdiv_##TYPE (TYPE *dst, TYPE *a, TYPE *b, int n)	\
   {							\
     for (int i = 0; i < n; i++)				\
       dst[i] = a[i] / b[i];				\
@@ -10,13 +10,12 @@ 
 
 #define TEST2_TYPE(TYPE) 				\
   __attribute__((noipa))				\
-  void vadds_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n)	\
+  void vdivs_##TYPE (TYPE *dst, TYPE *a, TYPE b, int n)	\
   {							\
     for (int i = 0; i < n; i++)				\
       dst[i] = a[i] / b;				\
   }
 
-/* *int8_t not autovec currently. */
 #define TEST_ALL()	\
  TEST_TYPE(int16_t)	\
  TEST_TYPE(uint16_t)	\
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
index 28cba510a93..df99f5019fb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv32gcv.c
@@ -3,7 +3,8 @@ 
 
 #include "vrem-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
index 5b6961d1f63..3cff13a47e4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vrem-rv64gcv.c
@@ -3,7 +3,8 @@ 
 
 #include "vrem-template.h"
 
-/* TODO: Implement vector type promotion.  We should have 6 vrem.vv here.  */
+/* Currently we use an epilogue loop which also contains vrems.  Therefore we
+   expect 10 vrem[u]s instead of 6.  */
 
-/* { dg-final { scan-assembler-times {\tvrem\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvremu\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {\tvrem\.vv} 10 } } */
+/* { dg-final { scan-assembler-times {\tvremu\.vv} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
new file mode 100644
index 00000000000..f55d2dfce7f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-run.c
@@ -0,0 +1,35 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i;             		\
+    dst##TYPE1##TYPE2[i] = -1;				\
+  }                             			\
+  vncvt_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL()					\
+ RUN(uint16_t, uint8_t)					\
+ RUN(uint32_t, uint8_t)					\
+ RUN(uint64_t, uint8_t)					\
+ RUN(uint32_t, uint16_t)				\
+ RUN(uint64_t, uint16_t)				\
+ RUN(uint64_t, uint32_t)				\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
new file mode 100644
index 00000000000..2b5aa0051cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv32gcv.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
new file mode 100644
index 00000000000..29349b33da6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-rv64gcv.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vncvt-template.h"
+
+/* { dg-final { scan-assembler-times {\tvncvt.x.x.w} 10 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
new file mode 100644
index 00000000000..6b19ff12abe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vncvt-template.h
@@ -0,0 +1,19 @@ 
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vncvt_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(uint16_t, uint8_t)					\
+ TEST(uint32_t, uint8_t)					\
+ TEST(uint32_t, uint16_t)					\
+ TEST(uint64_t, uint8_t)					\
+ TEST(uint64_t, uint16_t)					\
+ TEST(uint64_t, uint32_t)					\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
new file mode 100644
index 00000000000..d5f0190957a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-run.c
@@ -0,0 +1,35 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i - 128;            		\
+    dst##TYPE1##TYPE2[i] = 0;				\
+  }                             			\
+  vsext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i - 128);
+
+
+#define RUN_ALL()					\
+ RUN(int8_t, int16_t)					\
+ RUN(int8_t, int32_t)					\
+ RUN(int8_t, int64_t)					\
+ RUN(int16_t, int32_t)					\
+ RUN(int16_t, int64_t)					\
+ RUN(int32_t, int64_t)					\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
new file mode 100644
index 00000000000..538216ab9c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv32gcv.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
new file mode 100644
index 00000000000..29348cc67e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-rv64gcv.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vsext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvsext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvsext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
new file mode 100644
index 00000000000..c2f5fc92c99
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vsext-template.h
@@ -0,0 +1,19 @@ 
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vsext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(int8_t, int16_t)						\
+ TEST(int8_t, int32_t)						\
+ TEST(int8_t, int64_t)						\
+ TEST(int16_t, int32_t)						\
+ TEST(int16_t, int64_t)						\
+ TEST(int32_t, int64_t)						\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
new file mode 100644
index 00000000000..9d1c259f592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-run.c
@@ -0,0 +1,35 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+#include <assert.h>
+
+#define SZ 256
+
+#define RUN(TYPE1,TYPE2)				\
+  TYPE1 src##TYPE1##TYPE2[SZ];				\
+  TYPE2 dst##TYPE1##TYPE2[SZ];				\
+  for (int i = 0; i < SZ; i++)				\
+  {                             			\
+    src##TYPE1##TYPE2[i] = i;             		\
+    dst##TYPE1##TYPE2[i] = -1;				\
+  }                             			\
+  vzext_##TYPE1##TYPE2 (dst##TYPE1##TYPE2,		\
+			src##TYPE1##TYPE2, SZ);		\
+  for (int i = 0; i < SZ; i++)				\
+    assert (dst##TYPE1##TYPE2[i] == i);
+
+
+#define RUN_ALL()					\
+ RUN(uint8_t, uint16_t)					\
+ RUN(uint8_t, uint32_t)					\
+ RUN(uint8_t, uint64_t)					\
+ RUN(uint16_t, uint32_t)				\
+ RUN(uint16_t, uint64_t)				\
+ RUN(uint32_t, uint64_t)				\
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
new file mode 100644
index 00000000000..3e92843a5c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv32gcv.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
new file mode 100644
index 00000000000..cee0012d58c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-rv64gcv.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vzext-template.h"
+
+/* { dg-final { scan-assembler-times {\tvzext\.vf2} 3 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf4} 2 } } */
+/* { dg-final { scan-assembler-times {\tvzext\.vf8} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
new file mode 100644
index 00000000000..847905b690c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/conversions/vzext-template.h
@@ -0,0 +1,19 @@ 
+#include <stdint-gcc.h>
+
+#define TEST(TYPE1, TYPE2)					\
+  __attribute__((noipa))					\
+  void vzext_##TYPE1##TYPE2 (TYPE2 *dst, TYPE1 *a, int n)	\
+  {								\
+    for (int i = 0; i < n; i++)					\
+      dst[i] = (TYPE1)a[i];					\
+  }
+
+#define TEST_ALL()						\
+ TEST(uint8_t, uint16_t)					\
+ TEST(uint8_t, uint32_t)					\
+ TEST(uint8_t, uint64_t)					\
+ TEST(uint16_t, uint32_t)					\
+ TEST(uint16_t, uint64_t)					\
+ TEST(uint32_t, uint64_t)					\
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
index c53975e9b01..7f499befa82 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32f_zvl128b-2.c
@@ -3,4 +3,4 @@ 
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 4 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
index 80a4796fd38..2de09a29f02 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve32x_zvl128b-2.c
@@ -3,4 +3,4 @@ 
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
index 5e38b41a5c3..95d54d7b281 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64d-2.c
@@ -3,4 +3,4 @@ 
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 6 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
index ee37282f1f8..f9f44a94902 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64f-2.c
@@ -3,4 +3,4 @@ 
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 5 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
index 6a64a1a1fdf..12703a7e036 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/zve64x-2.c
@@ -3,4 +3,4 @@ 
 
 #include "template-1.h"
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 3 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..9466c2032e3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@  foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/conversions/*.\[cS\]]] \
+    "" "$op"
 }
 
 # VLS-VLMAX tests
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
index 34f1cd43a21..8606b10268d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-38.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
index 935e1b10630..11403203aa9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-47.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
index a1f4b70d4b4..79af2ef450a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-48.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
index 4fa68627cc0..77fe05b68a7 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/avl_single-49.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
index 4a1ef3ce5e9..f8568a8c898 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/imm_switch-8.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -fno-schedule-insns -fno-schedule-insns2 -fno-tree-vectorize" } */
 
 #include "riscv_vector.h"