public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/1] RISC-V: Support CORE-V XCVMEM extension
@ 2023-11-09 12:42 Mary Bennett
  2023-11-09 12:42 ` [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Mary Bennett @ 2023-11-09 12:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: mary.bennett

This patch series presents the comprehensive implementation of the MEM
extension for CORE-V.

Tested with riscv-gnu-toolchain on binutils, ld, gas and gcc testsuites to
ensure its correctness and compatibility with the existing codebase.
However, your input, reviews, and suggestions are invaluable in making this
extension even more robust.

The CORE-V builtins are described in the specification [1] and work can be
found in the OpenHW group's Github repository [2].

[1] github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md

[2] github.com/openhwgroup/corev-gcc

Contributors:
  Mary Bennett <mary.bennett@embecosm.com>
  Nandni Jamnadas <nandni.jamnadas@embecosm.com>
  Pietra Ferreira <pietra.ferreira@embecosm.com>
  Charlie Keaney
  Jessica Mills
  Craig Blackmore <craig.blackmore@embecosm.com>
  Simon Cook <simon.cook@embecosm.com>
  Jeremy Bennett <jeremy.bennett@embecosm.com>
  Helene Chelin <helene.chelin@embecosm.com>

RISC-V: Add support for XCVmem extension in CV32E40P

 gcc/common/config/riscv/riscv-common.cc       |   2 +
 gcc/config/riscv/constraints.md               |  28 +++
 gcc/config/riscv/corev.md                     | 227 ++++++++++++++++++
 gcc/config/riscv/predicates.md                |  20 +-
 gcc/config/riscv/riscv-protos.h               |  12 +-
 gcc/config/riscv/riscv.cc                     |  48 +++-
 gcc/config/riscv/riscv.h                      |   6 +-
 gcc/config/riscv/riscv.md                     |  46 ++--
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/doc/sourcebuild.texi                      |   3 +
 .../gcc.target/riscv/cv-mem-lb-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lb-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lb-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lh-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lh-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lh-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lw-compile-1.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-3.c    |  22 ++
 .../riscv/cv-mem-operand-compile-1.c          |  19 ++
 .../riscv/cv-mem-operand-compile-2.c          |  20 ++
 .../riscv/cv-mem-operand-compile-3.c          |  28 +++
 .../riscv/cv-mem-operand-compile-4.c          |  21 ++
 .../riscv/cv-mem-operand-compile-5.c          |  25 ++
 .../riscv/cv-mem-operand-compile-6.c          |  21 ++
 .../riscv/cv-mem-operand-compile-7.c          |  24 ++
 .../riscv/cv-mem-operand-compile-8.c          |  18 ++
 .../gcc.target/riscv/cv-mem-sb-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sb-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sb-compile-3.c    |  30 +++
 .../gcc.target/riscv/cv-mem-sh-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sh-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sh-compile-3.c    |  30 +++
 .../gcc.target/riscv/cv-mem-sw-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sw-compile-3.c    |  30 +++
 gcc/testsuite/lib/target-supports.exp         |  14 ++
 43 files changed, 1216 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P
  2023-11-09 12:42 [PATCH 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
@ 2023-11-09 12:42 ` Mary Bennett
  2023-11-19  7:55   ` Kito Cheng
  2024-01-11 14:41 ` [PATCH v2 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
  2024-01-25 14:02 ` [PATCH v3 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
  2 siblings, 1 reply; 7+ messages in thread
From: Mary Bennett @ 2023-11-09 12:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: mary.bennett

XCVmem adds more loads and stores. To prevent non-XCVmem loads and
stores from generating illegal XCVmem specific operands, constraint
'm' was redefined. 'm' does not accept POST_MODIFY or reg + reg
addresses.

Spec: github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md

Contributors:
  Mary Bennett <mary.bennett@embecosm.com>
  Nandni Jamnadas <nandni.jamnadas@embecosm.com>
  Pietra Ferreira <pietra.ferreira@embecosm.com>
  Charlie Keaney
  Jessica Mills
  Craig Blackmore <craig.blackmore@embecosm.com>
  Simon Cook <simon.cook@embecosm.com>
  Jeremy Bennett <jeremy.bennett@embecosm.com>
  Helene Chelin <helene.chelin@embecosm.com>

gcc/ChangeLog:
	* common/config/riscv/riscv-common.cc: Add the XCVmem
	  extension.
	* config/riscv/riscv.opt: Likewise.
	* config/riscv/corev.md: Likewise.
	* config/riscv/predicates.md: Likewise.
	* config/riscv/riscv-protos.h: Likewise.
	* config/riscv/riscv.cc: Add POST_MODIFY.
	* config/riscv/riscv.h: Likewise.
	* config/riscv/riscv.md: Prevent XCVmem operands being
	  used in non-XCVmem loads and stores.
        * config/riscv/constraints.md: Likewise.
	* config/riscv/predicates.md: Likewise.
	* doc/sourcebuild.texi: Add XCVmem documentation.

gcc/testsuite/ChangeLog:
	* gcc.target/riscv/cv-mem-operand-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-4.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-5.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-6.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-7.c: New test.
        * gcc.target/riscv/cv-mem-operand-compile-8.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-3.c: New test.
	* lib/target-supports.exp: Add proc for XCVmem.
---
 gcc/common/config/riscv/riscv-common.cc       |   2 +
 gcc/config/riscv/constraints.md               |  28 +++
 gcc/config/riscv/corev.md                     | 227 ++++++++++++++++++
 gcc/config/riscv/predicates.md                |  20 +-
 gcc/config/riscv/riscv-protos.h               |  12 +-
 gcc/config/riscv/riscv.cc                     |  48 +++-
 gcc/config/riscv/riscv.h                      |   6 +-
 gcc/config/riscv/riscv.md                     |  46 ++--
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/doc/sourcebuild.texi                      |   3 +
 .../gcc.target/riscv/cv-mem-lb-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lb-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lb-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lh-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lh-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lh-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lw-compile-1.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-3.c    |  22 ++
 .../riscv/cv-mem-operand-compile-1.c          |  19 ++
 .../riscv/cv-mem-operand-compile-2.c          |  20 ++
 .../riscv/cv-mem-operand-compile-3.c          |  28 +++
 .../riscv/cv-mem-operand-compile-4.c          |  21 ++
 .../riscv/cv-mem-operand-compile-5.c          |  25 ++
 .../riscv/cv-mem-operand-compile-6.c          |  21 ++
 .../riscv/cv-mem-operand-compile-7.c          |  24 ++
 .../riscv/cv-mem-operand-compile-8.c          |  18 ++
 .../gcc.target/riscv/cv-mem-sb-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sb-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sb-compile-3.c    |  30 +++
 .../gcc.target/riscv/cv-mem-sh-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sh-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sh-compile-3.c    |  30 +++
 .../gcc.target/riscv/cv-mem-sw-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sw-compile-3.c    |  30 +++
 gcc/testsuite/lib/target-supports.exp         |  14 ++
 43 files changed, 1216 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 04631e007f0..862674f921b 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -314,6 +314,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
   {"xcvalu", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xcvelw", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xcvbi", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xcvmem", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1671,6 +1672,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"xcvalu",        &gcc_options::x_riscv_xcv_subext, MASK_XCVALU},
   {"xcvelw",        &gcc_options::x_riscv_xcv_subext, MASK_XCVELW},
   {"xcvbi",         &gcc_options::x_riscv_xcv_subext, MASK_XCVBI},
+  {"xcvmem",        &gcc_options::x_riscv_xcv_subext, MASK_XCVMEM},
 
   {"xtheadba",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
   {"xtheadbb",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 718b4bd77df..f67bff0940f 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -35,6 +35,17 @@
 
 ;; General constraints
 
+(define_memory_constraint "m"
+  "An address that is not base reg + index reg or post modify."
+  (and (match_code "mem")
+       (and (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
+                                                 MEM_ADDR_SPACE (op))")
+            (not (match_test "((GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+                || GET_CODE (XEXP (op, 0)) == POST_MODIFY)
+		&& TARGET_XCVMEM")))))
+
 (define_constraint "I"
   "An I-type 12-bit signed immediate."
   (and (match_code "const_int")
@@ -253,3 +264,20 @@
    A 5-bit signed immediate for CORE-V Immediate Branch."
   (and (match_code "const_int")
        (match_test "IN_RANGE (ival, -16, 15)")))
+
+(define_constraint "CV_mem_plus"
+  "@internal
+   An address for reg+reg stores and loads"
+  (and (match_code "mem")
+       (match_test "GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG")))
+
+(define_constraint "CV_mem_post"
+  "@internal
+   An address for post-modify or reg+reg stores and loads"
+  (and (match_code "mem")
+       (match_test "(GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+		|| GET_CODE (XEXP (op, 0)) == POST_MODIFY")))
diff --git a/gcc/config/riscv/corev.md b/gcc/config/riscv/corev.md
index 7d7b952d817..fef7666e5dd 100644
--- a/gcc/config/riscv/corev.md
+++ b/gcc/config/riscv/corev.md
@@ -720,3 +720,230 @@
   "cv.b%C1imm\t%2,%3,%0"
   [(set_attr "type" "branch")
    (set_attr "mode" "none")])
+
+;;CORE-V Post Increment Load/ Store
+;; Post Increment Register-Immediate and Register-Register Load/Store
+(define_insn "cv_load<mode>_postinc"
+   [(set (match_operand:ANYI 0 "register_operand" "=r")
+         (match_operand:ANYI 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "cv_load_<optab><SHORT:mode>_postinc"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+     (any_extend:SI (match_operand:SHORT 1 "mem_post_inc" "CV_mem_post")))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load><u>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "cv_loadsf_postinc_hardfloat"
+   [(set (match_operand:SF 0 "register_operand" "=r")
+         (match_operand:SF 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.lw\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_loadsf_postinc_softfloat"
+   [(set (match_operand:SF 0 "register_operand" "=r")
+         (match_operand:SF 1 "mem_post_inc" "CV_mem_post"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.lw\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_loadhf_postinc_hardfloat"
+   [(set (match_operand:HF 0 "register_operand" "=r")
+         (match_operand:HF 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.lh\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HF")])
+
+(define_insn "cv_loadhf_postinc_softfloat"
+   [(set (match_operand:HF 0 "register_operand" "=r")
+         (match_operand:HF 1 "mem_post_inc" "CV_mem_post"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.lh\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HF")])
+
+(define_insn "cv_store<mode>_postinc"
+   [(set (match_operand:ANYI 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:ANYI 1 "register_operand" "r"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "cv_storesf_postinc_hardfloat"
+   [(set (match_operand:SF 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:SF 1 "register_operand" "r"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.sw\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_storesf_postinc_softfloat"
+   [(set (match_operand:SF 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:SF 1 "register_operand" "r"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.sw\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_storehf_postinc_hardfloat"
+   [(set (match_operand:HF 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:HF 1 "register_operand" "r"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.sh\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "HF")])
+
+(define_insn "cv_storehf_postinc_softfloat"
+   [(set (match_operand:HF 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:HF 1 "register_operand" "r"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.sh\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "HF")])
+
+;; Normal Register-Register Load/Store
+(define_insn "cv_load<mode>"
+   [(set (match_operand:ANYI 0 "register_operand" "=r")
+         (match_operand:ANYI 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "cv_load_<optab><SHORT:mode>"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+     (any_extend:SI (match_operand:SHORT 1 "mem_plus_reg" "CV_mem_plus")))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load><u>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "cv_loadsf_hardfloat"
+   [(set (match_operand:SF 0 "register_operand" "=r")
+         (match_operand:SF 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.lw\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_loadsf_softfloat"
+   [(set (match_operand:SF 0 "register_operand" "=r")
+         (match_operand:SF 1 "mem_plus_reg" "CV_mem_plus"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.lw\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_loadhf_hardfloat"
+   [(set (match_operand:HF 0 "register_operand" "=r")
+         (match_operand:HF 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.lh\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HF")])
+
+(define_insn "cv_loadhf_softfloat"
+   [(set (match_operand:HF 0 "register_operand" "=r")
+         (match_operand:HF 1 "mem_plus_reg" "CV_mem_plus"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.lh\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "HF")])
+
+(define_insn "cv_store<mode>"
+   [(set (match_operand:ANYI 0 "mem_plus_reg" "=CV_mem_plus")
+     (match_operand:ANYI 1 "register_operand" "r"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "cv_storesf_hardfloat"
+  [(set (match_operand:SF 0 "mem_plus_reg"     "=CV_mem_plus")
+        (match_operand:SF 1 "register_operand" " r"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.sw\t%1,%0"
+  [(set_attr "move_type" "store")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_storesf_softfloat"
+  [(set (match_operand:SF 0 "mem_plus_reg"     "=CV_mem_plus")
+        (match_operand:SF 1 "register_operand" " r"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (SFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  "cv.sw\t%1,%0"
+  [(set_attr "move_type" "store")
+   (set_attr "mode" "SF")])
+
+(define_insn "cv_storehf_hardfloat"
+  [(set (match_operand:HF 0 "mem_plus_reg"     "=CV_mem_plus")
+        (match_operand:HF 1 "register_operand" " r"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.sh\t%1,%0"
+  [(set_attr "move_type" "store")
+   (set_attr "mode" "HF")])
+
+(define_insn "cv_storehf_softfloat"
+  [(set (match_operand:HF 0 "mem_plus_reg"     "=CV_mem_plus")
+        (match_operand:HF 1 "register_operand" " r"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (HFmode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  "cv.sh\t%1,%0"
+  [(set_attr "move_type" "store")
+   (set_attr "mode" "HF")])
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 69a6319c2c8..b7ccc6c2239 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -234,8 +234,22 @@
   return false;
 })
 
+(define_predicate "mem_post_inc"
+  (and (match_code "mem")
+       (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == POST_MODIFY
+                    && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4")))
+
+(define_predicate "mem_plus_reg"
+  (and (match_code "mem")
+       (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == PLUS
+		    && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4
+		    && REG_P (XEXP (XEXP (op, 0), 1))
+		    && REG_P (XEXP (XEXP (op, 0), 0))")))
+
 (define_predicate "move_operand"
-  (match_operand 0 "general_operand")
+  (and (match_operand 0 "general_operand")
+  (and (not (match_operand 0 "mem_post_inc"))
+       (not (match_operand 0 "mem_plus_reg"))))
 {
   enum riscv_symbol_type symbol_type;
 
@@ -404,6 +418,10 @@
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), -16, 15)")))
 
+(define_predicate "nonimmediate_nonpostinc"
+  (and (match_operand 0 "nonimmediate_operand")
+	(not (match_operand 0 "mem_post_inc"))))
+
 ;; Predicates for the V extension.
 (define_special_predicate "vector_length_operand"
   (ior (match_operand 0 "pmode_register_operand")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index d322b7e80ec..d7085d0338c 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -68,7 +68,8 @@ enum riscv_address_type {
   ADDRESS_REG_WB,
   ADDRESS_LO_SUM,
   ADDRESS_CONST_INT,
-  ADDRESS_SYMBOLIC
+  ADDRESS_SYMBOLIC,
+  ADDRESS_REG_INC
 };
 
 /* Information about an address described by riscv_address_type.
@@ -91,7 +92,13 @@ enum riscv_address_type {
        is the type of symbol it references.
 
    ADDRESS_SYMBOLIC
-       SYMBOL_TYPE is the type of symbol that the address references.  */
+       SYMBOL_TYPE is the type of symbol that the address references.
+
+   ADDRESS_REG_INC:
+       A base register + offset address access with post modify side-effect
+       (base register += offset).  The offset is an immediate or index
+       register.
+       */
 struct riscv_address_info {
   enum riscv_address_type type;
   rtx reg;
@@ -101,6 +108,7 @@ struct riscv_address_info {
 };
 
 /* Routines implemented in riscv.cc.  */
+bool riscv_legitimate_xcvmem_address_p (machine_mode, rtx, bool);
 extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx);
 extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *);
 extern int riscv_float_const_rtx_index_for_fli (rtx);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 08ff05dcc3f..b701e1fb08f 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1084,7 +1084,7 @@ riscv_regno_mode_ok_for_base_p (int regno,
 enum reg_class
 riscv_index_reg_class ()
 {
-  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
+  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX || TARGET_XCVMEM)
     return GR_REGS;
 
   return NO_REGS;
@@ -1360,6 +1360,16 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       info->offset = const0_rtx;
       return riscv_valid_base_register_p (info->reg, mode, strict_p);
 
+    case POST_MODIFY:
+      /* For instructions using post inc, the offset can either be register
+       * or 12-bit immediate. */
+       info->type = ADDRESS_REG_INC;
+       info->reg = XEXP (x, 0);
+       info->offset = XEXP ((XEXP (x, 1)), 1);
+       return (riscv_valid_base_register_p (info->reg, mode, strict_p)
+       && (riscv_valid_base_register_p (info->offset, mode, strict_p)
+	       || riscv_valid_offset_p (info->offset, mode)));
+
     case PLUS:
       /* RVV load/store disallow any offset.  */
       if (riscv_v_ext_mode_p (mode))
@@ -1369,7 +1379,8 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       info->reg = XEXP (x, 0);
       info->offset = XEXP (x, 1);
       return (riscv_valid_base_register_p (info->reg, mode, strict_p)
-	      && riscv_valid_offset_p (info->offset, mode));
+	      && (riscv_valid_offset_p (info->offset, mode)
+		  || (TARGET_XCVMEM && riscv_valid_base_register_p (info->offset, mode, strict_p))));
 
     case LO_SUM:
       /* RVV load/store disallow LO_SUM.  */
@@ -2485,6 +2496,30 @@ riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
   REG_NOTES (insn) = dwarf;
 }
 
+/* Check if post inc instructions are valid. If not, make the address
+ * vaild. */
+bool
+riscv_legitimate_xcvmem_address_p (machine_mode mode, rtx x, bool strict_p)
+{
+  struct riscv_address_info addr;
+
+  switch (GET_CODE (x))
+    {
+    case POST_MODIFY:
+      if (riscv_classify_address (&addr, x, mode, strict_p))
+	return addr.type == ADDRESS_REG_INC;
+      return false;
+
+    case PLUS:
+      if (REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)) && riscv_classify_address (&addr, x, mode, strict_p))
+        return addr.type == ADDRESS_REG;
+      return false;
+
+    default:
+      return false;
+    }
+}
+
 /* If (set DEST SRC) is not a valid move instruction, emit an equivalent
    sequence that is valid.  */
 
@@ -5601,7 +5636,8 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
     switch (addr.type)
       {
       case ADDRESS_REG:
-	output_addr_const (file, riscv_strip_unspec_address (addr.offset));
+	if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+	else output_addr_const (file, riscv_strip_unspec_address (addr.offset));
 	fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
 	return;
 
@@ -5619,6 +5655,12 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
 	output_addr_const (file, riscv_strip_unspec_address (x));
 	return;
 
+      case ADDRESS_REG_INC:
+	fprintf (file, "(%s),", reg_names[REGNO (addr.reg)]);
+	if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+	else output_addr_const (file, addr.offset);
+	return;
+
       default:
 	gcc_unreachable ();
       }
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 1e9813b4f39..185e7d6ce23 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -44,6 +44,8 @@ along with GCC; see the file COPYING3.  If not see
 #define RISCV_TUNE_STRING_DEFAULT "rocket"
 #endif
 
+#define TARGET_MEM_CONSTRAINT 'w'
+
 extern const char *riscv_expand_arch (int argc, const char **argv);
 extern const char *riscv_expand_arch_from_cpu (int argc, const char **argv);
 extern const char *riscv_default_mtune (int argc, const char **argv);
@@ -1197,7 +1199,9 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
    e.g. RVVMF64BI vs RVVMF1BI on zvl512b, which is [1, 1] vs [64, 64].  */
 #define MAX_POLY_VARIANT 64
 
-#define HAVE_POST_MODIFY_DISP TARGET_XTHEADMEMIDX
+#define HAVE_POST_MODIFY_DISP (TARGET_XTHEADMEMIDX || TARGET_XCVMEM)
 #define HAVE_PRE_MODIFY_DISP  TARGET_XTHEADMEMIDX
 
+#define HAVE_POST_MODIFY_REG TARGET_XCVMEM
+
 #endif /* ! GCC_RISCV_H */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 168c8665a7a..5c9ea62d943 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1663,13 +1663,13 @@
 
 (define_expand "zero_extendsidi2"
   [(set (match_operand:DI 0 "register_operand")
-	(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
+	(zero_extend:DI (match_operand:SI 1 "nonimmediate_nonpostinc")))]
   "TARGET_64BIT")
 
 (define_insn_and_split "*zero_extendsidi2_internal"
   [(set (match_operand:DI     0 "register_operand"     "=r,r")
 	(zero_extend:DI
-	    (match_operand:SI 1 "nonimmediate_operand" " r,m")))]
+	    (match_operand:SI 1 "nonimmediate_nonpostinc" " r,m")))]
   "TARGET_64BIT && !TARGET_ZBA && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX
    && !(register_operand (operands[1], SImode)
         && reg_or_subregno (operands[1]) == VL_REGNUM)"
@@ -1691,13 +1691,13 @@
 (define_expand "zero_extendhi<GPR:mode>2"
   [(set (match_operand:GPR    0 "register_operand")
 	(zero_extend:GPR
-	    (match_operand:HI 1 "nonimmediate_operand")))]
+	    (match_operand:HI 1 "nonimmediate_nonpostinc")))]
   "")
 
 (define_insn_and_split "*zero_extendhi<GPR:mode>2"
   [(set (match_operand:GPR    0 "register_operand"     "=r,r")
 	(zero_extend:GPR
-	    (match_operand:HI 1 "nonimmediate_operand" " r,m")))]
+	    (match_operand:HI 1 "nonimmediate_nonpostinc" " r,m")))]
   "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
   "@
    #
@@ -1720,13 +1720,13 @@
 (define_expand "zero_extendqi<SUPERQI:mode>2"
   [(set (match_operand:SUPERQI    0 "register_operand")
 	(zero_extend:SUPERQI
-	    (match_operand:QI 1 "nonimmediate_operand")))]
+	    (match_operand:QI 1 "nonimmediate_nonpostinc")))]
   "")
 
 (define_insn "*zero_extendqi<SUPERQI:mode>2_internal"
   [(set (match_operand:SUPERQI 0 "register_operand"    "=r,r")
 	(zero_extend:SUPERQI
-	    (match_operand:QI 1 "nonimmediate_operand" " r,m")))]
+	    (match_operand:QI 1 "nonimmediate_nonpostinc" " r,m")))]
   "!TARGET_XTHEADMEMIDX"
   "@
    andi\t%0,%1,0xff
@@ -1745,13 +1745,13 @@
 (define_expand "extendsidi2"
   [(set (match_operand:DI     0 "register_operand"     "=r,r")
 	(sign_extend:DI
-	    (match_operand:SI 1 "nonimmediate_operand" " r,m")))]
+	    (match_operand:SI 1 "nonimmediate_nonpostinc" " r,m")))]
   "TARGET_64BIT")
 
 (define_insn "*extendsidi2_internal"
   [(set (match_operand:DI     0 "register_operand"     "=r,r")
 	(sign_extend:DI
-	    (match_operand:SI 1 "nonimmediate_operand" " r,m")))]
+	    (match_operand:SI 1 "nonimmediate_nonpostinc" " r,m")))]
   "TARGET_64BIT && !TARGET_XTHEADMEMIDX"
   "@
    sext.w\t%0,%1
@@ -1762,13 +1762,13 @@
 
 (define_expand "extend<SHORT:mode><SUPERQI:mode>2"
   [(set (match_operand:SUPERQI 0 "register_operand")
-	(sign_extend:SUPERQI (match_operand:SHORT 1 "nonimmediate_operand")))]
+	(sign_extend:SUPERQI (match_operand:SHORT 1 "nonimmediate_nonpostinc")))]
   "")
 
 (define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2"
   [(set (match_operand:SUPERQI   0 "register_operand"     "=r,r")
 	(sign_extend:SUPERQI
-	    (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))]
+	    (match_operand:SHORT 1 "nonimmediate_nonpostinc" " r,m")))]
   "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
   "@
    #
@@ -1827,7 +1827,7 @@
 })
 
 (define_insn "*movhf_hardfloat"
-  [(set (match_operand:HF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:HF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
   "TARGET_ZFHMIN
    && (register_operand (operands[0], HFmode)
@@ -1838,7 +1838,7 @@
    (set_attr "mode" "HF")])
 
 (define_insn "*movhf_softfloat"
-  [(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
+  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f, r,r,m,*f,*r")
 	(match_operand:HF 1 "move_operand"         " f,Gr,m,r,*r,*f"))]
   "!TARGET_ZFHMIN
    && (register_operand (operands[0], HFmode)
@@ -2062,7 +2062,7 @@
 })
 
 (define_insn "*movdi_32bit"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,m,  *f,*f,*r,*f,*m,r")
+  [(set (match_operand:DI 0 "nonimmediate_nonpostinc" "=r,r,r,m,  *f,*f,*r,*f,*m,r")
 	(match_operand:DI 1 "move_operand"         " r,i,m,r,*J*r,*m,*f,*f,*f,vp"))]
   "!TARGET_64BIT
    && (register_operand (operands[0], DImode)
@@ -2074,7 +2074,7 @@
    (set_attr "ext" "base,base,base,base,d,d,d,d,d,vector")])
 
 (define_insn "*movdi_64bit"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*f,*r,*f,*m,r")
+  [(set (match_operand:DI 0 "nonimmediate_nonpostinc" "=r,r,r, m,  *f,*f,*r,*f,*m,r")
 	(match_operand:DI 1 "move_operand"         " r,T,m,rJ,*r*J,*m,*f,*f,*f,vp"))]
   "TARGET_64BIT
    && (register_operand (operands[0], DImode)
@@ -2097,7 +2097,7 @@
 })
 
 (define_insn "*movsi_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*f,*r,*m,r")
+  [(set (match_operand:SI 0 "nonimmediate_nonpostinc" "=r,r,r, m,  *f,*f,*r,*m,r")
 	(match_operand:SI 1 "move_operand"         " r,T,m,rJ,*r*J,*m,*f,*f,vp"))]
   "(register_operand (operands[0], SImode)
     || reg_or_0_operand (operands[1], SImode))
@@ -2126,7 +2126,7 @@
 })
 
 (define_insn "*movhi_internal"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
+  [(set (match_operand:HI 0 "nonimmediate_nonpostinc" "=r,r,r, m,  *f,*r,r")
 	(match_operand:HI 1 "move_operand"	   " r,T,m,rJ,*r*J,*f,vp"))]
   "(register_operand (operands[0], HImode)
     || reg_or_0_operand (operands[1], HImode))"
@@ -2170,7 +2170,7 @@
 })
 
 (define_insn "*movqi_internal"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
+  [(set (match_operand:QI 0 "nonimmediate_nonpostinc" "=r,r,r, m,  *f,*r,r")
 	(match_operand:QI 1 "move_operand"         " r,I,m,rJ,*r*J,*f,vp"))]
   "(register_operand (operands[0], QImode)
     || reg_or_0_operand (operands[1], QImode))"
@@ -2192,7 +2192,7 @@
 })
 
 (define_insn "*movsf_hardfloat"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+  [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:SF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
   "TARGET_HARD_FLOAT
    && (register_operand (operands[0], SFmode)
@@ -2203,7 +2203,7 @@
    (set_attr "mode" "SF")])
 
 (define_insn "*movsf_softfloat"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "= r,r,m")
+  [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "= r,r,m")
 	(match_operand:SF 1 "move_operand"         " Gr,m,r"))]
   "!TARGET_HARD_FLOAT
    && (register_operand (operands[0], SFmode)
@@ -2228,7 +2228,7 @@
 ;; In RV32, we lack fmv.x.d and fmv.d.x.  Go through memory instead.
 ;; (However, we can still use fcvt.d.w to zero a floating-point register.)
 (define_insn "*movdf_hardfloat_rv32"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*zmvf,*zmvr,  *r,*r,*m")
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,m,m,*zmvf,*zmvr,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))]
   "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
@@ -2239,7 +2239,7 @@
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_hardfloat_rv64"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))]
   "TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
@@ -2250,7 +2250,7 @@
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_softfloat"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "= r,r, m")
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "= r,r, m")
 	(match_operand:DF 1 "move_operand"         " rG,m,rG"))]
   "!TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
@@ -2297,7 +2297,7 @@
    (set_attr "mode" "DF")])
 
 (define_split
-  [(set (match_operand:MOVE64 0 "nonimmediate_operand")
+  [(set (match_operand:MOVE64 0 "nonimmediate_nonpostinc")
 	(match_operand:MOVE64 1 "move_operand"))]
   "reload_completed
    && riscv_split_64bit_move_p (operands[0], operands[1])"
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index d06c0f8f416..5076d049d9f 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -415,6 +415,8 @@ Mask(XCVELW) Var(riscv_xcv_subext)
 
 Mask(XCVBI) Var(riscv_xcv_subext)
 
+Mask(XCVMEM) Var(riscv_xcv_subext)
+
 TargetVariable
 int riscv_xthead_subext
 
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 6fee1144238..cd3e58a2508 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2487,6 +2487,9 @@ Test system has support for the CORE-V ELW extension.
 @item cv_bi
 Test system has support for the CORE-V BI extension.
 
+@item cv_mem
+Test system has support for the CORE-V MEM extension.
+
 @end table
 
 @subsubsection Other hardware attributes
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
new file mode 100644
index 00000000000..1850eaa8f92
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    char_sum += array_char[i];
+  }
+
+  return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
new file mode 100644
index 00000000000..3d3ad6d43a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    char_sum += *array_char;
+    array_char+=j*sizeof(array_char);
+  }
+
+  return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
new file mode 100644
index 00000000000..358e34455d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+  return array_char[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
new file mode 100644
index 00000000000..1edc4402fa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    uns_char_sum += array_uchar[i];
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
new file mode 100644
index 00000000000..182e7e6ae96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    uns_char_sum += *array_uchar;
+    array_uchar+=j*sizeof(array_uchar);
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
new file mode 100644
index 00000000000..00099c15b6a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+  return array_uchar[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
new file mode 100644
index 00000000000..a7e74e8978e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    short_sum += array_short[i];
+  }
+
+  return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
new file mode 100644
index 00000000000..4ec9672d6ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n, int j)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    short_sum += *array_short;
+    array_short+=j*sizeof(array_short);
+  }
+
+  return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
new file mode 100644
index 00000000000..3a9b1a1deb8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+  return array_short[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
new file mode 100644
index 00000000000..19963fa706e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    uns_short_sum += array_ushort[i];
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
new file mode 100644
index 00000000000..9669e575511
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n, int j)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    uns_short_sum += *array_ushort;
+    array_ushort+=j*sizeof(array_ushort);
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
new file mode 100644
index 00000000000..baa2731aba2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+  return array_ushort[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
new file mode 100644
index 00000000000..3d61fc0f01c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* We don't generate for some optimization levels. TODO: should support for Os,
+   Oz and Og */
+/* { dg-skip-if "" { *-*-* }  { "-O0" "-Os" "-Oz" "-Og" } { "" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    int_sum += array_int[i];
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    uns_int_sum += array_uint[i];
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
new file mode 100644
index 00000000000..9909981c373
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n, int j)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    int_sum += *array_int;
+    array_int+=j*sizeof(array_int);
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n, int j)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    uns_int_sum += *array_uint;
+    array_uint+=j*sizeof(array_uint);
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
new file mode 100644
index 00000000000..8864927de9c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+  return array_int[i+j];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+  return array_uint[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
new file mode 100644
index 00000000000..05204b41573
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (plus:SI (reg reg)))`.
+ */
+
+struct {
+  double a[3];
+} * b;
+int c;
+
+int
+foo (void)
+{
+  b[0].a[c] -= b[0].a[c];
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
new file mode 100644
index 00000000000..373915f73d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (post_modify:SI (reg reg)))`.
+ */
+
+int bar (double);
+
+int
+foo (void)
+{
+  double *b;
+  int c = 0;
+  for (;; c++)
+    bar (b[c]);
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
new file mode 100644
index 00000000000..c622d60cd2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2 -Wno-int-conversion" } */
+
+/*
+ * Test for illegal XCVmem specific operand in loads.
+ * Instruction `lbu reg,reg(reg)`.
+ */
+
+int a;
+int bar (char);
+
+int
+foo (void)
+{
+  short *d;
+  char *e = (char *)foo;
+  for (;;) {
+    char c = d++;
+    bar (c);
+    short b = e[0] + b;
+    if (b)
+      a = 5;
+    e += 2;
+  }
+}
+
+/* { dg-final { scan-assembler-not "lbu\t\[a-z\]\[0-99\],\[a-z\]\[0-99\]\\(\[a-z\]\[0-99\]\\)" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
new file mode 100644
index 00000000000..4922f9667d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32if_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in flw.
+ * Error: illegal operands `flw fa5,a5(a4)'
+ */
+
+int b, e;
+float *m;
+
+int
+foo (void) {
+  m[1] = m[b];
+  m[b] = e;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "flw\tfa5,a5\\(a4\\)" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
new file mode 100644
index 00000000000..140486ce20b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32" } */
+
+/*
+ * Tests that stores can generate regular reg:imm operands.
+ */
+
+int a[1];
+int b, c, d, e, f;
+float g;
+
+int
+foo (void)
+{
+  int h;
+  for (;; d++)
+    switch (c) {
+    case 8:
+      g = e == f;
+      a[h + d] = g;
+      g = e < f;
+      b = g;
+    }
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
new file mode 100644
index 00000000000..8d6113971a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+
+/*
+ * Test for illegal XCVmem specific operands in lw.
+ */
+
+int
+fooSIsigned (signed int* array_int)
+{
+  return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint)
+{
+  return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.lw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
new file mode 100644
index 00000000000..dc61d859988
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for illegal XCVmem specific operands in register-immediate sw.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i)
+{
+  array_int [3] = i;
+  return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i)
+{
+  array_uint [3] = i;
+  return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.sw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
new file mode 100644
index 00000000000..da7f5166fe7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in sw.
+ */
+
+int a;
+float *b;
+
+int
+foo (void)
+{
+  int c;
+  for (c = 0; c < 10; c++)
+    b[c] = a;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
new file mode 100644
index 00000000000..596283f41e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_char[i] += char_sum;
+  }
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_uchar[i] += uns_char_sum;
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
new file mode 100644
index 00000000000..f907eca2fbf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_char += char_sum;
+    array_char+=j*sizeof(array_char);
+  }
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_uchar += uns_char_sum;
+    array_uchar+=j*sizeof(array_uchar);
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
new file mode 100644
index 00000000000..822573d13af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+  int char_sum = 1;
+
+  array_char[i+j] += char_sum;
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+  int uns_char_sum = 1;
+
+  array_uchar[i+j] += uns_char_sum;
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
new file mode 100644
index 00000000000..036836cc419
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_short[i] += short_sum;
+  }
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_ushort[i] += uns_short_sum;
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
new file mode 100644
index 00000000000..c761137395f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n, int j)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_short += short_sum;
+    array_short+=j*sizeof(array_short);
+  }
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n, int j)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_ushort += uns_short_sum;
+    array_ushort+=j*sizeof(array_ushort);
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
new file mode 100644
index 00000000000..3d8e07f9093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+  int short_sum = 1;
+
+  array_short[i+j] = short_sum;
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+  int uns_short_sum = 1;
+
+  array_ushort[i+j] += uns_short_sum;
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
new file mode 100644
index 00000000000..230022761cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_int[i] += int_sum;
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_uint[i] += uns_int_sum;
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
new file mode 100644
index 00000000000..fc5fcba22ef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n, int j)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_int += int_sum;
+    array_int+=j*sizeof(array_int);
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n, int j)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_uint += uns_int_sum;
+    array_uint+=j*sizeof(array_uint);
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c
new file mode 100644
index 00000000000..c709f2e5fc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+  int int_sum = 1;
+
+  array_int[i+j] = int_sum;
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+  int uns_int_sum = 1;
+
+  array_uint[i+j] = uns_int_sum;
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 0eae746e848..949fd413ff5 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -13111,6 +13111,20 @@ proc check_effective_target_cv_bi { } {
     } "-march=rv32i_xcvbi" ]
 }
 
+# Return 1 if the CORE-V MEM extension is available.
+proc check_effective_target_cv_mem { } {
+    if { !([istarget riscv*-*-*]) } {
+         return 0
+     }
+    return [check_no_compiler_messages cv_mem object {
+        void foo (void)
+        {
+          asm ("cv.lw t0, (t1), 4");
+        }
+    } "-march=rv32i_xcvmem" ]
+}
+
+
 proc check_effective_target_loongarch_sx { } {
     return [check_no_compiler_messages loongarch_lsx assembly {
        #if !defined(__loongarch_sx)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P
  2023-11-09 12:42 ` [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
@ 2023-11-19  7:55   ` Kito Cheng
  0 siblings, 0 replies; 7+ messages in thread
From: Kito Cheng @ 2023-11-19  7:55 UTC (permalink / raw)
  To: Mary Bennett; +Cc: gcc-patches

> diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
> index 718b4bd77df..f67bff0940f 100644
> --- a/gcc/config/riscv/constraints.md
> +++ b/gcc/config/riscv/constraints.md
> @@ -35,6 +35,17 @@
>
>  ;; General constraints
>
> +(define_memory_constraint "m"
> +  "An address that is not base reg + index reg or post modify."
> +  (and (match_code "mem")
> +       (and (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
> +                                                 MEM_ADDR_SPACE (op))")
> +            (not (match_test "((GET_CODE (XEXP (op, 0)) == PLUS
> +                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
> +                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
> +                || GET_CODE (XEXP (op, 0)) == POST_MODIFY)
> +               && TARGET_XCVMEM")))))
> +

I would suggest not overriding `m` and using the same move pattern
instead, like th_output_move.

I believe that should be good for both code gen and maintainability.

For codegen, IRA/LRA would like to see all possible solutions put
within the move pattern.

>  (define_constraint "I"
>    "An I-type 12-bit signed immediate."
>    (and (match_code "const_int")
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index 1e9813b4f39..185e7d6ce23 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -44,6 +44,8 @@ along with GCC; see the file COPYING3.  If not see
>  #define RISCV_TUNE_STRING_DEFAULT "rocket"
>  #endif
>
> +#define TARGET_MEM_CONSTRAINT 'w'

Maybe I missed something but I didn't see it used anywhere?

> +
>  extern const char *riscv_expand_arch (int argc, const char **argv);
>  extern const char *riscv_expand_arch_from_cpu (int argc, const char **argv);
>  extern const char *riscv_default_mtune (int argc, const char **argv);
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 168c8665a7a..5c9ea62d943 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -1663,13 +1663,13 @@
>
>  (define_expand "zero_extendsidi2"
>    [(set (match_operand:DI 0 "register_operand")
> -       (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
> +       (zero_extend:DI (match_operand:SI 1 "nonimmediate_nonpostinc")))]

Does Core-V support RV64? Does it xcvmem support cv.lwu if it supports RV64?

Don't change this if it does not support RV64, and see comment of
zero_extendhi if
it supports.

>    "TARGET_64BIT")
>
>  (define_insn_and_split "*zero_extendsidi2_internal"
>    [(set (match_operand:DI     0 "register_operand"     "=r,r")
>         (zero_extend:DI
> -           (match_operand:SI 1 "nonimmediate_operand" " r,m")))]
> +           (match_operand:SI 1 "nonimmediate_nonpostinc" " r,m")))]
>    "TARGET_64BIT && !TARGET_ZBA && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX
>     && !(register_operand (operands[1], SImode)
>          && reg_or_subregno (operands[1]) == VL_REGNUM)"

> @@ -1691,13 +1691,13 @@
>  (define_expand "zero_extendhi<GPR:mode>2"
>    [(set (match_operand:GPR    0 "register_operand")
>         (zero_extend:GPR
> -           (match_operand:HI 1 "nonimmediate_operand")))]
> +           (match_operand:HI 1 "nonimmediate_nonpostinc")))]


I would like to prevent this change if possible.

>    "")
>
>  (define_insn_and_split "*zero_extendhi<GPR:mode>2"
>    [(set (match_operand:GPR    0 "register_operand"     "=r,r")
>         (zero_extend:GPR
> -           (match_operand:HI 1 "nonimmediate_operand" " r,m")))]
> +           (match_operand:HI 1 "nonimmediate_nonpostinc" " r,m")))]
>    "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
>    "@
>     #

Use riscv_output_move for outputting lhu, then it should be able to naturally
support cv.lhu as well.

Same comment for all other zero_extend* and extend* patterns.

> @@ -1827,7 +1827,7 @@
>  })
>
>  (define_insn "*movhf_hardfloat"
> -  [(set (match_operand:HF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
> +  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")

Just repeat here, I really want to prevent using separated patterns to
handle postinc.

>         (match_operand:HF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
>    "TARGET_ZFHMIN
>     && (register_operand (operands[0], HFmode)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 0/1] RISC-V: Support CORE-V XCVMEM extension
  2023-11-09 12:42 [PATCH 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
  2023-11-09 12:42 ` [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
@ 2024-01-11 14:41 ` Mary Bennett
  2024-01-11 14:41   ` [PATCH v2 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
  2024-01-25 14:02 ` [PATCH v3 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
  2 siblings, 1 reply; 7+ messages in thread
From: Mary Bennett @ 2024-01-11 14:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: mary.bennett

This patch series presents the comprehensive implementation of the MEM
extension for CORE-V.

Tested with riscv-gnu-toolchain on binutils, ld, gas and gcc testsuites to
ensure its correctness and compatibility with the existing codebase.
However, your input, reviews, and suggestions are invaluable in making this
extension even more robust.

The CORE-V builtins are described in the specification [1] and work can be
found in the OpenHW group's Github repository [2].

[1] github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md

[2] github.com/openhwgroup/corev-gcc

Contributors:
  Mary Bennett <mary.bennett@embecosm.com>
  Nandni Jamnadas <nandni.jamnadas@embecosm.com>
  Pietra Ferreira <pietra.ferreira@embecosm.com>
  Charlie Keaney
  Jessica Mills
  Craig Blackmore <craig.blackmore@embecosm.com>
  Simon Cook <simon.cook@embecosm.com>
  Jeremy Bennett <jeremy.bennett@embecosm.com>
  Helene Chelin <helene.chelin@embecosm.com>

RISC-V: Add support for XCVmem extension in CV32E40P

 gcc/common/config/riscv/riscv-common.cc       |   2 +
 gcc/config/riscv/constraints.md               |  29 ++
 gcc/config/riscv/corev.md                     | 270 ++++++++++++++++++
 gcc/config/riscv/predicates.md                |  20 +-
 gcc/config/riscv/riscv-protos.h               |  12 +-
 gcc/config/riscv/riscv.cc                     |  48 +++-
 gcc/config/riscv/riscv.h                      |   4 +-
 gcc/config/riscv/riscv.md                     |  26 +-
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/doc/sourcebuild.texi                      |   3 +
 .../gcc.target/riscv/cv-mem-lb-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lb-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lb-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lh-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lh-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lh-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lw-compile-1.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-3.c    |  22 ++
 .../riscv/cv-mem-operand-compile-1.c          |  19 ++
 .../riscv/cv-mem-operand-compile-2.c          |  20 ++
 .../riscv/cv-mem-operand-compile-3.c          |  28 ++
 .../riscv/cv-mem-operand-compile-4.c          |  21 ++
 .../riscv/cv-mem-operand-compile-5.c          |  25 ++
 .../riscv/cv-mem-operand-compile-6.c          |  21 ++
 .../riscv/cv-mem-operand-compile-7.c          |  24 ++
 .../riscv/cv-mem-operand-compile-8.c          |  18 ++
 .../gcc.target/riscv/cv-mem-sb-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sb-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sb-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sh-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sh-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sh-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sw-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sw-compile-3.c    |  30 ++
 gcc/testsuite/lib/target-supports.exp         |  13 +
 43 files changed, 1247 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/1] RISC-V: Add support for XCVmem extension in CV32E40P
  2024-01-11 14:41 ` [PATCH v2 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
@ 2024-01-11 14:41   ` Mary Bennett
  0 siblings, 0 replies; 7+ messages in thread
From: Mary Bennett @ 2024-01-11 14:41 UTC (permalink / raw)
  To: gcc-patches; +Cc: mary.bennett

XCVmem adds more loads and stores. To prevent non-XCVmem loads and
stores from generating illegal XCVmem specific operands, constraint
'm' was redefined. 'm' does not accept POST_MODIFY or reg + reg
addresses.

Spec: github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md

Contributors:
  Mary Bennett <mary.bennett@embecosm.com>
  Nandni Jamnadas <nandni.jamnadas@embecosm.com>
  Pietra Ferreira <pietra.ferreira@embecosm.com>
  Charlie Keaney
  Jessica Mills
  Craig Blackmore <craig.blackmore@embecosm.com>
  Simon Cook <simon.cook@embecosm.com>
  Jeremy Bennett <jeremy.bennett@embecosm.com>
  Helene Chelin <helene.chelin@embecosm.com>

gcc/ChangeLog:
	* common/config/riscv/riscv-common.cc: Add the XCVmem
	  extension.
	* config/riscv/riscv.opt: Likewise.
	* config/riscv/corev.md: Likewise.
	* config/riscv/predicates.md: Likewise.
	* config/riscv/riscv-protos.h: Likewise.
	* config/riscv/riscv.cc: Add POST_MODIFY.
	* config/riscv/riscv.h: Likewise.
	* config/riscv/riscv.md: Prevent XCVmem operands being
	  used in non-XCVmem loads and stores.
        * config/riscv/constraints.md: Likewise.
	* config/riscv/predicates.md: Likewise.
	* doc/sourcebuild.texi: Add XCVmem documentation.

gcc/testsuite/ChangeLog:
	* gcc.target/riscv/cv-mem-operand-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-4.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-5.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-6.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-7.c: New test.
        * gcc.target/riscv/cv-mem-operand-compile-8.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-3.c: New test.
	* lib/target-supports.exp: Add proc for XCVmem.

Change the priority of the XCVmem instructions

Returned corev.md to be included at the bottom of riscv.md.

Files Changed:
 * corev.md: Added generic load/ store instructions with lower
   priority than the XCVmem load/ store instructions.
 * riscv.md: Prevent generic load/ store instructions having higher
   priority than XCVmem load/ store if the extension is included.
---
 gcc/common/config/riscv/riscv-common.cc       |   2 +
 gcc/config/riscv/constraints.md               |  29 ++
 gcc/config/riscv/corev.md                     | 270 ++++++++++++++++++
 gcc/config/riscv/predicates.md                |  20 +-
 gcc/config/riscv/riscv-protos.h               |  12 +-
 gcc/config/riscv/riscv.cc                     |  48 +++-
 gcc/config/riscv/riscv.h                      |   4 +-
 gcc/config/riscv/riscv.md                     |  26 +-
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/doc/sourcebuild.texi                      |   3 +
 .../gcc.target/riscv/cv-mem-lb-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lb-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lb-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lh-compile-1.c    |  23 ++
 .../gcc.target/riscv/cv-mem-lh-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lh-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-1.c   |  23 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lw-compile-1.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-3.c    |  22 ++
 .../riscv/cv-mem-operand-compile-1.c          |  19 ++
 .../riscv/cv-mem-operand-compile-2.c          |  20 ++
 .../riscv/cv-mem-operand-compile-3.c          |  28 ++
 .../riscv/cv-mem-operand-compile-4.c          |  21 ++
 .../riscv/cv-mem-operand-compile-5.c          |  25 ++
 .../riscv/cv-mem-operand-compile-6.c          |  21 ++
 .../riscv/cv-mem-operand-compile-7.c          |  24 ++
 .../riscv/cv-mem-operand-compile-8.c          |  18 ++
 .../gcc.target/riscv/cv-mem-sb-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sb-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sb-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sh-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sh-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sh-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sw-compile-1.c    |  36 +++
 .../gcc.target/riscv/cv-mem-sw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sw-compile-3.c    |  30 ++
 gcc/testsuite/lib/target-supports.exp         |  13 +
 43 files changed, 1247 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 0301d170a41..03d1e823c87 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -355,6 +355,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
   {"xcvmac", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xcvalu", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xcvelw", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xcvmem", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1730,6 +1731,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"xcvmac",        &gcc_options::x_riscv_xcv_subext, MASK_XCVMAC},
   {"xcvalu",        &gcc_options::x_riscv_xcv_subext, MASK_XCVALU},
   {"xcvelw",        &gcc_options::x_riscv_xcv_subext, MASK_XCVELW},
+  {"xcvmem",        &gcc_options::x_riscv_xcv_subext, MASK_XCVMEM},
 
   {"xtheadba",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
   {"xtheadbb",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index ee1c12b2e51..f8278dce587 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -262,3 +262,32 @@
   (and (match_code "const_int")
        (and (match_test "IN_RANGE (ival, 0, 1073741823)")
             (match_test "exact_log2 (ival + 1) != -1"))))
+
+(define_memory_constraint "CV_mem_plus"
+  "@internal
+   An address for reg+reg stores and loads"
+  (and (match_code "mem")
+       (match_test "GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG")))
+
+(define_memory_constraint "CV_mem_post"
+  "@internal
+   An address for post-modify or reg+reg stores and loads"
+  (and (match_code "mem")
+       (match_test "(GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+		|| GET_CODE (XEXP (op, 0)) == POST_MODIFY")))
+
+(define_memory_constraint "CV_mem_nopm"
+  "@internal
+   An address that is not base reg + index reg or post modify."
+  (and (match_code "mem")
+       (and (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
+                                                 MEM_ADDR_SPACE (op))")
+            (not (match_test "((GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+                || GET_CODE (XEXP (op, 0)) == POST_MODIFY)
+               && TARGET_XCVMEM")))))
diff --git a/gcc/config/riscv/corev.md b/gcc/config/riscv/corev.md
index adad2409fb6..7dc5774b05b 100644
--- a/gcc/config/riscv/corev.md
+++ b/gcc/config/riscv/corev.md
@@ -706,3 +706,273 @@
 
   [(set_attr "type" "load")
   (set_attr "mode" "SI")])
+
+;; CORE-V Post Increment Load/ Store Instructions
+;; Post Increment Register-Immediate and Register-Register Load/Store
+
+(define_insn "*cv_load<mode>_postinc"
+   [(set (match_operand:ANYI 0 "register_operand" "=r")
+         (match_operand:ANYI 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load_<optab><SHORT:mode>_postinc"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+     (any_extend:SI (match_operand:SHORT 1 "mem_post_inc" "CV_mem_post")))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load><u>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<ANYF:mode>_postinc"
+   [(set (match_operand:ANYF 0 "register_operand" "=r")
+         (match_operand:ANYF 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<mode>_postinc"
+   [(set (match_operand:ANYI 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:ANYI 1 "register_operand" "r"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<ANYF:mode>_postinc"
+   [(set (match_operand:ANYF 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:ANYF 1 "register_operand" "r"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+;; Normal Register-Register Load/Store
+(define_insn "*cv_load<mode>"
+   [(set (match_operand:ANYI 0 "register_operand" "=r")
+         (match_operand:ANYI 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<optab><SHORT:mode>"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+     (any_extend:SI (match_operand:SHORT 1 "mem_plus_reg" "CV_mem_plus")))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load><u>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<ANYF:mode>"
+   [(set (match_operand:ANYF 0 "register_operand" "=r")
+         (match_operand:ANYF 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<mode>"
+   [(set (match_operand:ANYI 0 "mem_plus_reg" "=CV_mem_plus")
+     (match_operand:ANYI 1 "register_operand" "r"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<ANYF:mode>"
+  [(set (match_operand:ANYF 0 "mem_plus_reg"     "=CV_mem_plus")
+        (match_operand:ANYF 1 "register_operand" " r"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "move_type" "store")
+   (set_attr "mode" "<MODE>")])
+
+;;
+;; Generic RISC-V moves for XCVMEM
+;;
+
+(define_insn "*movsi_internal"
+  [(set (match_operand:SI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm,  *f,*f,*r,*CV_mem_nopm,r")
+        (match_operand:SI 1 "move_operand"      " r,T,CV_mem_nopm,rJ,*r*J,*CV_mem_nopm,*f,*f,vp"))]
+  "TARGET_XCVMEM && (register_operand (operands[0], SImode)
+    || reg_or_0_operand (operands[1], SImode))
+    && !(register_operand (operands[1], SImode)
+         && reg_or_subregno (operands[1]) == VL_REGNUM)"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,const,load,store,mtc,fpload,mfc,fpstore,rdvlenb")
+   (set_attr "mode" "SI")
+   (set_attr "type" "move")
+   (set_attr "ext" "base,base,base,base,f,f,f,f,vector")])
+
+(define_insn "*movhi_internal"
+  [(set (match_operand:HI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm,  *f,*r,r")
+        (match_operand:HI 1 "move_operand"            " r,T,CV_mem_nopm,rJ,*r*J,*f,vp"))]
+  "TARGET_XCVMEM && (register_operand (operands[0], HImode)
+    || reg_or_0_operand (operands[1], HImode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+   (set_attr "mode" "HI")
+   (set_attr "type" "move")
+   (set_attr "ext" "base,base,base,base,f,f,vector")])
+
+(define_insn "*movqi_internal"
+  [(set (match_operand:QI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm,  *f,*r,r")
+        (match_operand:QI 1 "move_operand"            " r,I,CV_mem_nopm,rJ,*r*J,*f,vp"))]
+  "TARGET_XCVMEM && (register_operand (operands[0], QImode)
+    || reg_or_0_operand (operands[1], QImode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+   (set_attr "mode" "QI")
+   (set_attr "type" "move")
+   (set_attr "ext" "base,base,base,base,f,f,vector")])
+
+(define_insn "*movhf_hardfloat"
+  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r,  *r,*r,*CV_mem_nopm")
+        (match_operand:HF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*G*r,*CV_mem_nopm,*r"))]
+  "TARGET_ZFHMIN && TARGET_XCVMEM
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "HF")])
+
+(define_insn "*movhf_softfloat"
+  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f, r,r,CV_mem_nopm,*f,*r")
+        (match_operand:HF 1 "move_operand"         " f,Gr,CV_mem_nopm,r,*r,*f"))]
+  "!TARGET_ZFHMIN && TARGET_XCVMEM
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,move,load,store,mtc,mfc")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "HF")])
+
+(define_insn_and_split "*zero_extendhi<GPR:mode>2"
+  [(set (match_operand:GPR    0 "register_operand"     "=r,r")
+        (zero_extend:GPR
+            (match_operand:HI 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+  "@
+   #
+   lhu\t%0,%1"
+  "&& reload_completed
+   && REG_P (operands[1])
+   && !paradoxical_subreg_p (operands[0])"
+  [(set (match_dup 0)
+        (ashift:GPR (match_dup 1) (match_dup 2)))
+   (set (match_dup 0)
+        (lshiftrt:GPR (match_dup 0) (match_dup 2)))]
+  {
+    operands[1] = gen_lowpart (<GPR:MODE>mode, operands[1]);
+    operands[2] = GEN_INT(GET_MODE_BITSIZE(<GPR:MODE>mode) - 16);
+  }
+  [(set_attr "move_type" "shift_shift,load")
+   (set_attr "type" "load")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*zero_extendqi<SUPERQI:mode>2_internal"
+  [(set (match_operand:SUPERQI 0 "register_operand"    "=r,r")
+        (zero_extend:SUPERQI
+            (match_operand:QI 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+  "!TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+  "@
+   andi\t%0,%1,0xff
+   lbu\t%0,%1"
+  [(set_attr "move_type" "andi,load")
+   (set_attr "type" "multi")
+   (set_attr "mode" "<SUPERQI:MODE>")])
+
+(define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2"
+  [(set (match_operand:SUPERQI   0 "register_operand"     "=r,r")
+        (sign_extend:SUPERQI
+            (match_operand:SHORT 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+  "@
+   #
+   l<SHORT:size>\t%0,%1"
+  "&& reload_completed
+   && REG_P (operands[1])
+   && !paradoxical_subreg_p (operands[0])"
+  [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))]
+{
+  operands[0] = gen_lowpart (SImode, operands[0]);
+  operands[1] = gen_lowpart (SImode, operands[1]);
+  operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode)
+                         - GET_MODE_BITSIZE (<SHORT:MODE>mode));
+}
+  [(set_attr "move_type" "shift_shift,load")
+   (set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "*movdf_hardfloat_rv32"
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*zmvf,*zmvr,  *r,*r,*CV_mem_nopm")
+        (match_operand:DF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*zmvr,*zmvf,*r*G,*CV_mem_nopm,*r"))]
+  "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "*movdf_hardfloat_rv64"
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r,  *r,*r,*CV_mem_nopm")
+        (match_operand:DF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*r*G,*CV_mem_nopm,*r"))]
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "*movdf_softfloat"
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "= r,r,CV_mem_nopm")
+        (match_operand:DF 1 "move_operand"         " rG,CV_mem_nopm,rG"))]
+  "!TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "*movsf_hardfloat"
+  [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r,  *r,*r,*CV_mem_nopm")
+        (match_operand:SF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*G*r,*CV_mem_nopm,*r"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "SF")])
+
+(define_insn "*movsf_softfloat"
+  [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "= r,r,CV_mem_nopm")
+        (match_operand:SF 1 "move_operand"         " Gr,CV_mem_nopm,r"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "SF")])
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index b1a79cae50a..066107ebec0 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -252,8 +252,22 @@
   return false;
 })
 
+(define_predicate "mem_post_inc"
+  (and (match_code "mem")
+       (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == POST_MODIFY
+                    && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4")))
+
+(define_predicate "mem_plus_reg"
+  (and (match_code "mem")
+       (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == PLUS
+		    && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4
+		    && REG_P (XEXP (XEXP (op, 0), 1))
+		    && REG_P (XEXP (XEXP (op, 0), 0))")))
+
 (define_predicate "move_operand"
-  (match_operand 0 "general_operand")
+  (and (match_operand 0 "general_operand")
+  (and (not (match_operand 0 "mem_post_inc"))
+       (not (match_operand 0 "mem_plus_reg"))))
 {
   enum riscv_symbol_type symbol_type;
 
@@ -425,6 +439,10 @@
   (ior (match_operand 0 "register_operand")
        (match_code "const_int")))
 
+(define_predicate "nonimmediate_nonpostinc"
+  (and (match_operand 0 "nonimmediate_operand")
+	(not (match_operand 0 "mem_post_inc"))))
+
 ;; Predicates for the V extension.
 (define_special_predicate "vector_length_operand"
   (ior (match_operand 0 "pmode_register_operand")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 00a5b645abe..41c95bb17bc 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -69,7 +69,8 @@ enum riscv_address_type {
   ADDRESS_REG_WB,
   ADDRESS_LO_SUM,
   ADDRESS_CONST_INT,
-  ADDRESS_SYMBOLIC
+  ADDRESS_SYMBOLIC,
+  ADDRESS_REG_INC
 };
 
 /* Information about an address described by riscv_address_type.
@@ -92,7 +93,13 @@ enum riscv_address_type {
        is the type of symbol it references.
 
    ADDRESS_SYMBOLIC
-       SYMBOL_TYPE is the type of symbol that the address references.  */
+       SYMBOL_TYPE is the type of symbol that the address references.
+
+   ADDRESS_REG_INC:
+       A base register + offset address access with post modify side-effect
+       (base register += offset).  The offset is an immediate or index
+       register.
+       */
 struct riscv_address_info {
   enum riscv_address_type type;
   rtx reg;
@@ -102,6 +109,7 @@ struct riscv_address_info {
 };
 
 /* Routines implemented in riscv.cc.  */
+bool riscv_legitimate_xcvmem_address_p (machine_mode, rtx, bool);
 extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx);
 extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *);
 extern int riscv_float_const_rtx_index_for_fli (rtx);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 32183d63180..a3a03162e52 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1176,7 +1176,7 @@ riscv_regno_mode_ok_for_base_p (int regno,
 enum reg_class
 riscv_index_reg_class ()
 {
-  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
+  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX || TARGET_XCVMEM)
     return GR_REGS;
 
   return NO_REGS;
@@ -1452,6 +1452,16 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       info->offset = const0_rtx;
       return riscv_valid_base_register_p (info->reg, mode, strict_p);
 
+    case POST_MODIFY:
+      /* For instructions using post inc, the offset can either be register
+       * or 12-bit immediate. */
+       info->type = ADDRESS_REG_INC;
+       info->reg = XEXP (x, 0);
+       info->offset = XEXP ((XEXP (x, 1)), 1);
+       return (riscv_valid_base_register_p (info->reg, mode, strict_p)
+       && (riscv_valid_base_register_p (info->offset, mode, strict_p)
+	       || riscv_valid_offset_p (info->offset, mode)));
+
     case PLUS:
       /* RVV load/store disallow any offset.  */
       if (riscv_v_ext_mode_p (mode))
@@ -1461,7 +1471,8 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       info->reg = XEXP (x, 0);
       info->offset = XEXP (x, 1);
       return (riscv_valid_base_register_p (info->reg, mode, strict_p)
-	      && riscv_valid_offset_p (info->offset, mode));
+	      && (riscv_valid_offset_p (info->offset, mode)
+		  || (TARGET_XCVMEM && riscv_valid_base_register_p (info->offset, mode, strict_p))));
 
     case LO_SUM:
       /* RVV load/store disallow LO_SUM.  */
@@ -2615,6 +2626,30 @@ riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
   REG_NOTES (insn) = dwarf;
 }
 
+/* Check if post inc instructions are valid. If not, make the address
+ * vaild. */
+bool
+riscv_legitimate_xcvmem_address_p (machine_mode mode, rtx x, bool strict_p)
+{
+  struct riscv_address_info addr;
+
+  switch (GET_CODE (x))
+    {
+    case POST_MODIFY:
+      if (riscv_classify_address (&addr, x, mode, strict_p))
+	return addr.type == ADDRESS_REG_INC;
+      return false;
+
+    case PLUS:
+      if (REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)) && riscv_classify_address (&addr, x, mode, strict_p))
+	return addr.type == ADDRESS_REG;
+      return false;
+
+    default:
+      return false;
+    }
+}
+
 /* If (set DEST SRC) is not a valid move instruction, emit an equivalent
    sequence that is valid.  */
 
@@ -5966,7 +6001,8 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
     switch (addr.type)
       {
       case ADDRESS_REG:
-	output_addr_const (file, riscv_strip_unspec_address (addr.offset));
+	if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+	else output_addr_const (file, riscv_strip_unspec_address (addr.offset));
 	fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
 	return;
 
@@ -5984,6 +6020,12 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
 	output_addr_const (file, riscv_strip_unspec_address (x));
 	return;
 
+      case ADDRESS_REG_INC:
+	fprintf (file, "(%s),", reg_names[REGNO (addr.reg)]);
+	if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+	else output_addr_const (file, addr.offset);
+	return;
+
       default:
 	gcc_unreachable ();
       }
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index b13ccc5aba9..8785fad839e 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -1212,7 +1212,9 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
    e.g. RVVMF64BI vs RVVMF1BI on zvl512b, which is [1, 1] vs [64, 64].  */
 #define MAX_POLY_VARIANT 64
 
-#define HAVE_POST_MODIFY_DISP TARGET_XTHEADMEMIDX
+#define HAVE_POST_MODIFY_DISP (TARGET_XTHEADMEMIDX || TARGET_XCVMEM)
 #define HAVE_PRE_MODIFY_DISP  TARGET_XTHEADMEMIDX
 
+#define HAVE_POST_MODIFY_REG TARGET_XCVMEM
+
 #endif /* ! GCC_RISCV_H */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 84212430dc0..c49f6ef085d 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1777,7 +1777,7 @@
   [(set (match_operand:GPR    0 "register_operand"     "=r,r")
 	(zero_extend:GPR
 	    (match_operand:HI 1 "nonimmediate_operand" " r,m")))]
-  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
   "@
    #
    lhu\t%0,%1"
@@ -1806,7 +1806,7 @@
   [(set (match_operand:SUPERQI 0 "register_operand"    "=r,r")
 	(zero_extend:SUPERQI
 	    (match_operand:QI 1 "nonimmediate_operand" " r,m")))]
-  "!TARGET_XTHEADMEMIDX"
+  "!TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
   "@
    andi\t%0,%1,0xff
    lbu\t%0,%1"
@@ -1848,7 +1848,7 @@
   [(set (match_operand:SUPERQI   0 "register_operand"     "=r,r")
 	(sign_extend:SUPERQI
 	    (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))]
-  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
   "@
    #
    l<SHORT:size>\t%0,%1"
@@ -1908,7 +1908,7 @@
 (define_insn "*movhf_hardfloat"
   [(set (match_operand:HF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:HF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
-  "TARGET_ZFHMIN
+  "TARGET_ZFHMIN && !TARGET_XCVMEM
    && (register_operand (operands[0], HFmode)
        || reg_or_0_operand (operands[1], HFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -1919,7 +1919,7 @@
 (define_insn "*movhf_softfloat"
   [(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
 	(match_operand:HF 1 "move_operand"         " f,Gr,m,r,*r,*f"))]
-  "!TARGET_ZFHMIN
+  "!TARGET_ZFHMIN && !TARGET_XCVMEM
    && (register_operand (operands[0], HFmode)
        || reg_or_0_operand (operands[1], HFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2186,7 +2186,7 @@
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*f,*r,*m,r")
 	(match_operand:SI 1 "move_operand"         " r,T,m,rJ,*r*J,*m,*f,*f,vp"))]
-  "(register_operand (operands[0], SImode)
+  "!TARGET_XCVMEM && (register_operand (operands[0], SImode)
     || reg_or_0_operand (operands[1], SImode))
     && !(register_operand (operands[1], SImode)
          && reg_or_subregno (operands[1]) == VL_REGNUM)"
@@ -2215,7 +2215,7 @@
 (define_insn "*movhi_internal"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
 	(match_operand:HI 1 "move_operand"	   " r,T,m,rJ,*r*J,*f,vp"))]
-  "(register_operand (operands[0], HImode)
+  "!TARGET_XCVMEM && (register_operand (operands[0], HImode)
     || reg_or_0_operand (operands[1], HImode))"
   { return riscv_output_move (operands[0], operands[1]); }
   [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
@@ -2259,7 +2259,7 @@
 (define_insn "*movqi_internal"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
 	(match_operand:QI 1 "move_operand"         " r,I,m,rJ,*r*J,*f,vp"))]
-  "(register_operand (operands[0], QImode)
+  "!TARGET_XCVMEM && (register_operand (operands[0], QImode)
     || reg_or_0_operand (operands[1], QImode))"
   { return riscv_output_move (operands[0], operands[1]); }
   [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
@@ -2281,7 +2281,7 @@
 (define_insn "*movsf_hardfloat"
   [(set (match_operand:SF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:SF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
-  "TARGET_HARD_FLOAT
+  "TARGET_HARD_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], SFmode)
        || reg_or_0_operand (operands[1], SFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2292,7 +2292,7 @@
 (define_insn "*movsf_softfloat"
   [(set (match_operand:SF 0 "nonimmediate_operand" "= r,r,m")
 	(match_operand:SF 1 "move_operand"         " Gr,m,r"))]
-  "!TARGET_HARD_FLOAT
+  "!TARGET_HARD_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], SFmode)
        || reg_or_0_operand (operands[1], SFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2317,7 +2317,7 @@
 (define_insn "*movdf_hardfloat_rv32"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*zmvf,*zmvr,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))]
-  "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
+  "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2328,7 +2328,7 @@
 (define_insn "*movdf_hardfloat_rv64"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))]
-  "TARGET_64BIT && TARGET_DOUBLE_FLOAT
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2339,7 +2339,7 @@
 (define_insn "*movdf_softfloat"
   [(set (match_operand:DF 0 "nonimmediate_operand" "= r,r, m")
 	(match_operand:DF 1 "move_operand"         " rG,m,rG"))]
-  "!TARGET_DOUBLE_FLOAT
+  "!TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 44ed6d69da2..41bc84376cd 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -425,6 +425,8 @@ Mask(XCVALU) Var(riscv_xcv_subext)
 
 Mask(XCVELW) Var(riscv_xcv_subext)
 
+Mask(XCVMEM) Var(riscv_xcv_subext)
+
 TargetVariable
 int riscv_xthead_subext
 
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 3a394e7739b..14701649653 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2505,6 +2505,9 @@ Test system has support for the CORE-V ALU extension.
 @item cv_elw
 Test system has support for the CORE-V ELW extension.
 
+@item cv_mem
+Test system has support for the CORE-V MEM extension.
+
 @end table
 
 @subsubsection Other hardware attributes
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
new file mode 100644
index 00000000000..1850eaa8f92
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    char_sum += array_char[i];
+  }
+
+  return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
new file mode 100644
index 00000000000..3d3ad6d43a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    char_sum += *array_char;
+    array_char+=j*sizeof(array_char);
+  }
+
+  return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
new file mode 100644
index 00000000000..358e34455d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+  return array_char[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
new file mode 100644
index 00000000000..1edc4402fa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    uns_char_sum += array_uchar[i];
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
new file mode 100644
index 00000000000..182e7e6ae96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    uns_char_sum += *array_uchar;
+    array_uchar+=j*sizeof(array_uchar);
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
new file mode 100644
index 00000000000..00099c15b6a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+  return array_uchar[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
new file mode 100644
index 00000000000..a7e74e8978e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    short_sum += array_short[i];
+  }
+
+  return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
new file mode 100644
index 00000000000..4ec9672d6ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n, int j)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    short_sum += *array_short;
+    array_short+=j*sizeof(array_short);
+  }
+
+  return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
new file mode 100644
index 00000000000..3a9b1a1deb8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+  return array_short[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
new file mode 100644
index 00000000000..19963fa706e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    uns_short_sum += array_ushort[i];
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
new file mode 100644
index 00000000000..9669e575511
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n, int j)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    uns_short_sum += *array_ushort;
+    array_ushort+=j*sizeof(array_ushort);
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
new file mode 100644
index 00000000000..baa2731aba2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+  return array_ushort[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
new file mode 100644
index 00000000000..3d61fc0f01c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* We don't generate for some optimization levels. TODO: should support for Os,
+   Oz and Og */
+/* { dg-skip-if "" { *-*-* }  { "-O0" "-Os" "-Oz" "-Og" } { "" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    int_sum += array_int[i];
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    uns_int_sum += array_uint[i];
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
new file mode 100644
index 00000000000..9909981c373
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n, int j)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    int_sum += *array_int;
+    array_int+=j*sizeof(array_int);
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n, int j)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    uns_int_sum += *array_uint;
+    array_uint+=j*sizeof(array_uint);
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
new file mode 100644
index 00000000000..8864927de9c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+  return array_int[i+j];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+  return array_uint[i+j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
new file mode 100644
index 00000000000..05204b41573
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (plus:SI (reg reg)))`.
+ */
+
+struct {
+  double a[3];
+} * b;
+int c;
+
+int
+foo (void)
+{
+  b[0].a[c] -= b[0].a[c];
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
new file mode 100644
index 00000000000..373915f73d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (post_modify:SI (reg reg)))`.
+ */
+
+int bar (double);
+
+int
+foo (void)
+{
+  double *b;
+  int c = 0;
+  for (;; c++)
+    bar (b[c]);
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
new file mode 100644
index 00000000000..c622d60cd2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2 -Wno-int-conversion" } */
+
+/*
+ * Test for illegal XCVmem specific operand in loads.
+ * Instruction `lbu reg,reg(reg)`.
+ */
+
+int a;
+int bar (char);
+
+int
+foo (void)
+{
+  short *d;
+  char *e = (char *)foo;
+  for (;;) {
+    char c = d++;
+    bar (c);
+    short b = e[0] + b;
+    if (b)
+      a = 5;
+    e += 2;
+  }
+}
+
+/* { dg-final { scan-assembler-not "lbu\t\[a-z\]\[0-99\],\[a-z\]\[0-99\]\\(\[a-z\]\[0-99\]\\)" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
new file mode 100644
index 00000000000..4922f9667d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32if_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in flw.
+ * Error: illegal operands `flw fa5,a5(a4)'
+ */
+
+int b, e;
+float *m;
+
+int
+foo (void) {
+  m[1] = m[b];
+  m[b] = e;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "flw\tfa5,a5\\(a4\\)" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
new file mode 100644
index 00000000000..140486ce20b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32" } */
+
+/*
+ * Tests that stores can generate regular reg:imm operands.
+ */
+
+int a[1];
+int b, c, d, e, f;
+float g;
+
+int
+foo (void)
+{
+  int h;
+  for (;; d++)
+    switch (c) {
+    case 8:
+      g = e == f;
+      a[h + d] = g;
+      g = e < f;
+      b = g;
+    }
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
new file mode 100644
index 00000000000..8d6113971a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+
+/*
+ * Test for illegal XCVmem specific operands in lw.
+ */
+
+int
+fooSIsigned (signed int* array_int)
+{
+  return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint)
+{
+  return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.lw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
new file mode 100644
index 00000000000..dc61d859988
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for illegal XCVmem specific operands in register-immediate sw.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i)
+{
+  array_int [3] = i;
+  return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i)
+{
+  array_uint [3] = i;
+  return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.sw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
new file mode 100644
index 00000000000..da7f5166fe7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in sw.
+ */
+
+int a;
+float *b;
+
+int
+foo (void)
+{
+  int c;
+  for (c = 0; c < 10; c++)
+    b[c] = a;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
new file mode 100644
index 00000000000..596283f41e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_char[i] += char_sum;
+  }
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_uchar[i] += uns_char_sum;
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
new file mode 100644
index 00000000000..f907eca2fbf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+  int char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_char += char_sum;
+    array_char+=j*sizeof(array_char);
+  }
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+  int uns_char_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_uchar += uns_char_sum;
+    array_uchar+=j*sizeof(array_uchar);
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
new file mode 100644
index 00000000000..822573d13af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+  int char_sum = 1;
+
+  array_char[i+j] += char_sum;
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+  int uns_char_sum = 1;
+
+  array_uchar[i+j] += uns_char_sum;
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
new file mode 100644
index 00000000000..036836cc419
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_short[i] += short_sum;
+  }
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_ushort[i] += uns_short_sum;
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
new file mode 100644
index 00000000000..c761137395f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int n, int j)
+{
+  int short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_short += short_sum;
+    array_short+=j*sizeof(array_short);
+  }
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int n, int j)
+{
+  int uns_short_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_ushort += uns_short_sum;
+    array_ushort+=j*sizeof(array_ushort);
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
new file mode 100644
index 00000000000..3d8e07f9093
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+  int short_sum = 1;
+
+  array_short[i+j] = short_sum;
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+  int uns_short_sum = 1;
+
+  array_ushort[i+j] += uns_short_sum;
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
new file mode 100644
index 00000000000..230022761cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_int[i] += int_sum;
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i++)
+  {
+    array_uint[i] += uns_int_sum;
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
new file mode 100644
index 00000000000..fc5fcba22ef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int n, int j)
+{
+  int int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_int += int_sum;
+    array_int+=j*sizeof(array_int);
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int n, int j)
+{
+  int uns_int_sum = 1;
+
+  for(int i=0; i<n; i+=j)
+  {
+    *array_uint += uns_int_sum;
+    array_uint+=j*sizeof(array_uint);
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c
new file mode 100644
index 00000000000..c709f2e5fc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+  int int_sum = 1;
+
+  array_int[i+j] = int_sum;
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+  int uns_int_sum = 1;
+
+  array_uint[i+j] = uns_int_sum;
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index d6595315865..6a47449c11d 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -13307,6 +13307,19 @@ proc check_effective_target_cv_elw { } {
     } "-march=rv32i_xcvelw" ]
 }
 
+# Return 1 if the CORE-V MEM extension is available.
+proc check_effective_target_cv_mem { } {
+    if { !([istarget riscv*-*-*]) } {
+         return 0
+     }
+    return [check_no_compiler_messages cv_mem object {
+        void foo (void)
+        {
+          asm ("cv.lw t0, (t1), 4");
+        }
+    } "-march=rv32i_xcvmem" ]
+}
+
 proc check_effective_target_loongarch_sx { } {
     return [check_no_compiler_messages loongarch_lsx assembly {
        #if !defined(__loongarch_sx)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v3 0/1] RISC-V: Support CORE-V XCVMEM extension
  2023-11-09 12:42 [PATCH 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
  2023-11-09 12:42 ` [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
  2024-01-11 14:41 ` [PATCH v2 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
@ 2024-01-25 14:02 ` Mary Bennett
  2024-01-25 14:02   ` [PATCH v3 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
  2 siblings, 1 reply; 7+ messages in thread
From: Mary Bennett @ 2024-01-25 14:02 UTC (permalink / raw)
  To: gcc-patches; +Cc: mary.bennett

This patch series presents the comprehensive implementation of the MEM
extension for CORE-V.

Tested with riscv-gnu-toolchain on binutils, ld, gas and gcc testsuites to
ensure its correctness and compatibility with the existing codebase.
However, your input, reviews, and suggestions are invaluable in making this
extension even more robust.

The CORE-V builtins are described in the specification [1] and work can be
found in the OpenHW group's Github repository [2].

[1] github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md

[2] github.com/openhwgroup/corev-gcc

Contributors:
  Mary Bennett <mary.bennett@embecosm.com>
  Nandni Jamnadas <nandni.jamnadas@embecosm.com>
  Pietra Ferreira <pietra.ferreira@embecosm.com>
  Charlie Keaney
  Jessica Mills
  Craig Blackmore <craig.blackmore@embecosm.com>
  Simon Cook <simon.cook@embecosm.com>
  Jeremy Bennett <jeremy.bennett@embecosm.com>
  Helene Chelin <helene.chelin@embecosm.com>

RISC-V: Add support for XCVmem extension in CV32E40P

 gcc/common/config/riscv/riscv-common.cc       |   2 +
 gcc/config/riscv/constraints.md               |  29 ++
 gcc/config/riscv/corev.md                     | 270 ++++++++++++++++++
 gcc/config/riscv/predicates.md                |  20 +-
 gcc/config/riscv/riscv-protos.h               |  12 +-
 gcc/config/riscv/riscv.cc                     |  48 +++-
 gcc/config/riscv/riscv.h                      |   4 +-
 gcc/config/riscv/riscv.md                     |  26 +-
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/doc/sourcebuild.texi                      |   3 +
 .../gcc.target/riscv/cv-mem-lb-compile-1.c    |  21 ++
 .../gcc.target/riscv/cv-mem-lb-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lb-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-1.c   |  21 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lh-compile-1.c    |  21 ++
 .../gcc.target/riscv/cv-mem-lh-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lh-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-1.c   |  21 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lw-compile-1.c    |  33 +++
 .../gcc.target/riscv/cv-mem-lw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-3.c    |  22 ++
 .../riscv/cv-mem-operand-compile-1.c          |  19 ++
 .../riscv/cv-mem-operand-compile-2.c          |  20 ++
 .../riscv/cv-mem-operand-compile-3.c          |  28 ++
 .../riscv/cv-mem-operand-compile-4.c          |  21 ++
 .../riscv/cv-mem-operand-compile-5.c          |  25 ++
 .../riscv/cv-mem-operand-compile-6.c          |  21 ++
 .../riscv/cv-mem-operand-compile-7.c          |  24 ++
 .../riscv/cv-mem-operand-compile-8.c          |  18 ++
 .../gcc.target/riscv/cv-mem-sb-compile-1.c    |  32 +++
 .../gcc.target/riscv/cv-mem-sb-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sb-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sh-compile-1.c    |  32 +++
 .../gcc.target/riscv/cv-mem-sh-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sh-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sw-compile-1.c    |  32 +++
 .../gcc.target/riscv/cv-mem-sw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sw-compile-3.c    |  30 ++
 gcc/testsuite/lib/target-supports.exp         |  13 +
 43 files changed, 1222 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v3 1/1] RISC-V: Add support for XCVmem extension in CV32E40P
  2024-01-25 14:02 ` [PATCH v3 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
@ 2024-01-25 14:02   ` Mary Bennett
  0 siblings, 0 replies; 7+ messages in thread
From: Mary Bennett @ 2024-01-25 14:02 UTC (permalink / raw)
  To: gcc-patches; +Cc: mary.bennett

XCVmem adds more loads and stores. To prevent non-XCVmem loads and
stores from generating illegal XCVmem specific operands, constraint
'm' was redefined. 'm' does not accept POST_MODIFY or reg + reg
addresses.

Spec: github.com/openhwgroup/core-v-sw/blob/master/specifications/corev-builtin-spec.md

Contributors:
  Mary Bennett <mary.bennett@embecosm.com>
  Nandni Jamnadas <nandni.jamnadas@embecosm.com>
  Pietra Ferreira <pietra.ferreira@embecosm.com>
  Charlie Keaney
  Jessica Mills
  Craig Blackmore <craig.blackmore@embecosm.com>
  Simon Cook <simon.cook@embecosm.com>
  Jeremy Bennett <jeremy.bennett@embecosm.com>
  Helene Chelin <helene.chelin@embecosm.com>

gcc/ChangeLog:
	* common/config/riscv/riscv-common.cc: Add the XCVmem
	  extension.
	* config/riscv/riscv.opt: Likewise.
	* config/riscv/corev.md: Likewise.
	* config/riscv/predicates.md: Likewise.
	* config/riscv/riscv-protos.h: Likewise.
	* config/riscv/riscv.cc: Add POST_MODIFY.
	* config/riscv/riscv.h: Likewise.
	* config/riscv/riscv.md: Prevent XCVmem operands being
	  used in non-XCVmem loads and stores.
        * config/riscv/constraints.md: Likewise.
	* config/riscv/predicates.md: Likewise.
	* doc/sourcebuild.texi: Add XCVmem documentation.

gcc/testsuite/ChangeLog:
	* gcc.target/riscv/cv-mem-operand-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-4.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-5.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-6.c: New test.
	* gcc.target/riscv/cv-mem-operand-compile-7.c: New test.
        * gcc.target/riscv/cv-mem-operand-compile-8.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lb-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lbu-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lh-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lhu-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-lw-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sb-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sh-compile-3.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-1.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-2.c: New test.
	* gcc.target/riscv/cv-mem-sw-compile-3.c: New test.
	* lib/target-supports.exp: Add proc for XCVmem.
---
 gcc/common/config/riscv/riscv-common.cc       |   2 +
 gcc/config/riscv/constraints.md               |  29 ++
 gcc/config/riscv/corev.md                     | 270 ++++++++++++++++++
 gcc/config/riscv/predicates.md                |  20 +-
 gcc/config/riscv/riscv-protos.h               |  12 +-
 gcc/config/riscv/riscv.cc                     |  48 +++-
 gcc/config/riscv/riscv.h                      |   4 +-
 gcc/config/riscv/riscv.md                     |  26 +-
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/doc/sourcebuild.texi                      |   3 +
 .../gcc.target/riscv/cv-mem-lb-compile-1.c    |  21 ++
 .../gcc.target/riscv/cv-mem-lb-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lb-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-1.c   |  21 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lbu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lh-compile-1.c    |  21 ++
 .../gcc.target/riscv/cv-mem-lh-compile-2.c    |  24 ++
 .../gcc.target/riscv/cv-mem-lh-compile-3.c    |  16 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-1.c   |  21 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-2.c   |  24 ++
 .../gcc.target/riscv/cv-mem-lhu-compile-3.c   |  16 ++
 .../gcc.target/riscv/cv-mem-lw-compile-1.c    |  33 +++
 .../gcc.target/riscv/cv-mem-lw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-lw-compile-3.c    |  22 ++
 .../riscv/cv-mem-operand-compile-1.c          |  19 ++
 .../riscv/cv-mem-operand-compile-2.c          |  20 ++
 .../riscv/cv-mem-operand-compile-3.c          |  28 ++
 .../riscv/cv-mem-operand-compile-4.c          |  21 ++
 .../riscv/cv-mem-operand-compile-5.c          |  25 ++
 .../riscv/cv-mem-operand-compile-6.c          |  21 ++
 .../riscv/cv-mem-operand-compile-7.c          |  24 ++
 .../riscv/cv-mem-operand-compile-8.c          |  18 ++
 .../gcc.target/riscv/cv-mem-sb-compile-1.c    |  32 +++
 .../gcc.target/riscv/cv-mem-sb-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sb-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sh-compile-1.c    |  32 +++
 .../gcc.target/riscv/cv-mem-sh-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sh-compile-3.c    |  30 ++
 .../gcc.target/riscv/cv-mem-sw-compile-1.c    |  32 +++
 .../gcc.target/riscv/cv-mem-sw-compile-2.c    |  38 +++
 .../gcc.target/riscv/cv-mem-sw-compile-3.c    |  30 ++
 gcc/testsuite/lib/target-supports.exp         |  13 +
 43 files changed, 1222 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 4da7f37303b..8ceb12490d1 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -358,6 +358,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
   {"xcvmac", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xcvalu", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xcvelw", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"xcvmem", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
   {"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1602,6 +1603,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"xcvmac",        &gcc_options::x_riscv_xcv_subext, MASK_XCVMAC},
   {"xcvalu",        &gcc_options::x_riscv_xcv_subext, MASK_XCVALU},
   {"xcvelw",        &gcc_options::x_riscv_xcv_subext, MASK_XCVELW},
+  {"xcvmem",        &gcc_options::x_riscv_xcv_subext, MASK_XCVMEM},
 
   {"xtheadba",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
   {"xtheadbb",      &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index ee1c12b2e51..f8278dce587 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -262,3 +262,32 @@
   (and (match_code "const_int")
        (and (match_test "IN_RANGE (ival, 0, 1073741823)")
             (match_test "exact_log2 (ival + 1) != -1"))))
+
+(define_memory_constraint "CV_mem_plus"
+  "@internal
+   An address for reg+reg stores and loads"
+  (and (match_code "mem")
+       (match_test "GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG")))
+
+(define_memory_constraint "CV_mem_post"
+  "@internal
+   An address for post-modify or reg+reg stores and loads"
+  (and (match_code "mem")
+       (match_test "(GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+		|| GET_CODE (XEXP (op, 0)) == POST_MODIFY")))
+
+(define_memory_constraint "CV_mem_nopm"
+  "@internal
+   An address that is not base reg + index reg or post modify."
+  (and (match_code "mem")
+       (and (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
+                                                 MEM_ADDR_SPACE (op))")
+            (not (match_test "((GET_CODE (XEXP (op, 0)) == PLUS
+                && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+                && GET_CODE (XEXP (XEXP (op, 0), 1)) == REG)
+                || GET_CODE (XEXP (op, 0)) == POST_MODIFY)
+               && TARGET_XCVMEM")))))
diff --git a/gcc/config/riscv/corev.md b/gcc/config/riscv/corev.md
index adad2409fb6..7dc5774b05b 100644
--- a/gcc/config/riscv/corev.md
+++ b/gcc/config/riscv/corev.md
@@ -706,3 +706,273 @@
 
   [(set_attr "type" "load")
   (set_attr "mode" "SI")])
+
+;; CORE-V Post Increment Load/ Store Instructions
+;; Post Increment Register-Immediate and Register-Register Load/Store
+
+(define_insn "*cv_load<mode>_postinc"
+   [(set (match_operand:ANYI 0 "register_operand" "=r")
+         (match_operand:ANYI 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load_<optab><SHORT:mode>_postinc"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+     (any_extend:SI (match_operand:SHORT 1 "mem_post_inc" "CV_mem_post")))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load><u>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<ANYF:mode>_postinc"
+   [(set (match_operand:ANYF 0 "register_operand" "=r")
+         (match_operand:ANYF 1 "mem_post_inc" "CV_mem_post"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<mode>_postinc"
+   [(set (match_operand:ANYI 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:ANYI 1 "register_operand" "r"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<ANYF:mode>_postinc"
+   [(set (match_operand:ANYF 0 "mem_post_inc" "=CV_mem_post")
+         (match_operand:ANYF 1 "register_operand" "r"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+;; Normal Register-Register Load/Store
+(define_insn "*cv_load<mode>"
+   [(set (match_operand:ANYI 0 "register_operand" "=r")
+         (match_operand:ANYI 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<optab><SHORT:mode>"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+     (any_extend:SI (match_operand:SHORT 1 "mem_plus_reg" "CV_mem_plus")))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))"
+  "cv.<load><u>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_load<ANYF:mode>"
+   [(set (match_operand:ANYF 0 "register_operand" "=r")
+         (match_operand:ANYF 1 "mem_plus_reg" "CV_mem_plus"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[1], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<load>\t%0,%1"
+  [(set_attr "type" "load")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<mode>"
+   [(set (match_operand:ANYI 0 "mem_plus_reg" "=CV_mem_plus")
+     (match_operand:ANYI 1 "register_operand" "r"))]
+  "TARGET_XCVMEM && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "type" "store")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*cv_store<ANYF:mode>"
+  [(set (match_operand:ANYF 0 "mem_plus_reg"     "=CV_mem_plus")
+        (match_operand:ANYF 1 "register_operand" " r"))]
+  "TARGET_XCVMEM
+   && riscv_legitimate_xcvmem_address_p (<MODE>mode, XEXP (operands[0], 0), (lra_in_progress || reload_completed))
+   && (register_operand (operands[0], <MODE>mode)
+       || reg_or_0_operand (operands[1], <MODE>mode))"
+  "cv.<store>\t%1,%0"
+  [(set_attr "move_type" "store")
+   (set_attr "mode" "<MODE>")])
+
+;;
+;; Generic RISC-V moves for XCVMEM
+;;
+
+(define_insn "*movsi_internal"
+  [(set (match_operand:SI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm,  *f,*f,*r,*CV_mem_nopm,r")
+        (match_operand:SI 1 "move_operand"      " r,T,CV_mem_nopm,rJ,*r*J,*CV_mem_nopm,*f,*f,vp"))]
+  "TARGET_XCVMEM && (register_operand (operands[0], SImode)
+    || reg_or_0_operand (operands[1], SImode))
+    && !(register_operand (operands[1], SImode)
+         && reg_or_subregno (operands[1]) == VL_REGNUM)"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,const,load,store,mtc,fpload,mfc,fpstore,rdvlenb")
+   (set_attr "mode" "SI")
+   (set_attr "type" "move")
+   (set_attr "ext" "base,base,base,base,f,f,f,f,vector")])
+
+(define_insn "*movhi_internal"
+  [(set (match_operand:HI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm,  *f,*r,r")
+        (match_operand:HI 1 "move_operand"            " r,T,CV_mem_nopm,rJ,*r*J,*f,vp"))]
+  "TARGET_XCVMEM && (register_operand (operands[0], HImode)
+    || reg_or_0_operand (operands[1], HImode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+   (set_attr "mode" "HI")
+   (set_attr "type" "move")
+   (set_attr "ext" "base,base,base,base,f,f,vector")])
+
+(define_insn "*movqi_internal"
+  [(set (match_operand:QI 0 "nonimmediate_nonpostinc" "=r,r,r,CV_mem_nopm,  *f,*r,r")
+        (match_operand:QI 1 "move_operand"            " r,I,CV_mem_nopm,rJ,*r*J,*f,vp"))]
+  "TARGET_XCVMEM && (register_operand (operands[0], QImode)
+    || reg_or_0_operand (operands[1], QImode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
+   (set_attr "mode" "QI")
+   (set_attr "type" "move")
+   (set_attr "ext" "base,base,base,base,f,f,vector")])
+
+(define_insn "*movhf_hardfloat"
+  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r,  *r,*r,*CV_mem_nopm")
+        (match_operand:HF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*G*r,*CV_mem_nopm,*r"))]
+  "TARGET_ZFHMIN && TARGET_XCVMEM
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "HF")])
+
+(define_insn "*movhf_softfloat"
+  [(set (match_operand:HF 0 "nonimmediate_nonpostinc" "=f, r,r,CV_mem_nopm,*f,*r")
+        (match_operand:HF 1 "move_operand"         " f,Gr,CV_mem_nopm,r,*r,*f"))]
+  "!TARGET_ZFHMIN && TARGET_XCVMEM
+   && (register_operand (operands[0], HFmode)
+       || reg_or_0_operand (operands[1], HFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,move,load,store,mtc,mfc")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "HF")])
+
+(define_insn_and_split "*zero_extendhi<GPR:mode>2"
+  [(set (match_operand:GPR    0 "register_operand"     "=r,r")
+        (zero_extend:GPR
+            (match_operand:HI 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+  "@
+   #
+   lhu\t%0,%1"
+  "&& reload_completed
+   && REG_P (operands[1])
+   && !paradoxical_subreg_p (operands[0])"
+  [(set (match_dup 0)
+        (ashift:GPR (match_dup 1) (match_dup 2)))
+   (set (match_dup 0)
+        (lshiftrt:GPR (match_dup 0) (match_dup 2)))]
+  {
+    operands[1] = gen_lowpart (<GPR:MODE>mode, operands[1]);
+    operands[2] = GEN_INT(GET_MODE_BITSIZE(<GPR:MODE>mode) - 16);
+  }
+  [(set_attr "move_type" "shift_shift,load")
+   (set_attr "type" "load")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*zero_extendqi<SUPERQI:mode>2_internal"
+  [(set (match_operand:SUPERQI 0 "register_operand"    "=r,r")
+        (zero_extend:SUPERQI
+            (match_operand:QI 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+  "!TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+  "@
+   andi\t%0,%1,0xff
+   lbu\t%0,%1"
+  [(set_attr "move_type" "andi,load")
+   (set_attr "type" "multi")
+   (set_attr "mode" "<SUPERQI:MODE>")])
+
+(define_insn_and_split "*extend<SHORT:mode><SUPERQI:mode>2"
+  [(set (match_operand:SUPERQI   0 "register_operand"     "=r,r")
+        (sign_extend:SUPERQI
+            (match_operand:SHORT 1 "nonimmediate_nonpostinc" " r,CV_mem_nopm")))]
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && TARGET_XCVMEM"
+  "@
+   #
+   l<SHORT:size>\t%0,%1"
+  "&& reload_completed
+   && REG_P (operands[1])
+   && !paradoxical_subreg_p (operands[0])"
+  [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))]
+{
+  operands[0] = gen_lowpart (SImode, operands[0]);
+  operands[1] = gen_lowpart (SImode, operands[1]);
+  operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode)
+                         - GET_MODE_BITSIZE (<SHORT:MODE>mode));
+}
+  [(set_attr "move_type" "shift_shift,load")
+   (set_attr "type" "load")
+   (set_attr "mode" "SI")])
+
+(define_insn "*movdf_hardfloat_rv32"
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*zmvf,*zmvr,  *r,*r,*CV_mem_nopm")
+        (match_operand:DF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*zmvr,*zmvf,*r*G,*CV_mem_nopm,*r"))]
+  "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "*movdf_hardfloat_rv64"
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r,  *r,*r,*CV_mem_nopm")
+        (match_operand:DF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*r*G,*CV_mem_nopm,*r"))]
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "*movdf_softfloat"
+  [(set (match_operand:DF 0 "nonimmediate_nonpostinc" "= r,r,CV_mem_nopm")
+        (match_operand:DF 1 "move_operand"         " rG,CV_mem_nopm,rG"))]
+  "!TARGET_DOUBLE_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "*movsf_hardfloat"
+  [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "=f,   f,f,f,CV_mem_nopm,CV_mem_nopm,*f,*r,  *r,*r,*CV_mem_nopm")
+        (match_operand:SF 1 "move_operand"         " f,zfli,G,CV_mem_nopm,f,G,*r,*f,*G*r,*CV_mem_nopm,*r"))]
+  "TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "SF")])
+
+(define_insn "*movsf_softfloat"
+  [(set (match_operand:SF 0 "nonimmediate_nonpostinc" "= r,r,CV_mem_nopm")
+        (match_operand:SF 1 "move_operand"         " Gr,CV_mem_nopm,r"))]
+  "!TARGET_HARD_FLOAT && TARGET_XCVMEM
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "move,load,store")
+   (set_attr "type" "fmove")
+   (set_attr "mode" "SF")])
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 0337da88284..106c4c118b5 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -252,8 +252,22 @@
   return false;
 })
 
+(define_predicate "mem_post_inc"
+  (and (match_code "mem")
+       (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == POST_MODIFY
+                    && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4")))
+
+(define_predicate "mem_plus_reg"
+  (and (match_code "mem")
+       (match_test "TARGET_XCVMEM && GET_CODE (XEXP (op, 0)) == PLUS
+		    && GET_MODE_SIZE (GET_MODE (op)).to_constant () <= 4
+		    && REG_P (XEXP (XEXP (op, 0), 1))
+		    && REG_P (XEXP (XEXP (op, 0), 0))")))
+
 (define_predicate "move_operand"
-  (match_operand 0 "general_operand")
+  (and (match_operand 0 "general_operand")
+  (and (not (match_operand 0 "mem_post_inc"))
+       (not (match_operand 0 "mem_plus_reg"))))
 {
   enum riscv_symbol_type symbol_type;
 
@@ -425,6 +439,10 @@
   (ior (match_operand 0 "register_operand")
        (match_code "const_int")))
 
+(define_predicate "nonimmediate_nonpostinc"
+  (and (match_operand 0 "nonimmediate_operand")
+	(not (match_operand 0 "mem_post_inc"))))
+
 ;; Predicates for the V extension.
 (define_special_predicate "vector_length_operand"
   (ior (match_operand 0 "pmode_register_operand")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 7fe26fcd939..35bab2ea20c 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -69,7 +69,8 @@ enum riscv_address_type {
   ADDRESS_REG_WB,
   ADDRESS_LO_SUM,
   ADDRESS_CONST_INT,
-  ADDRESS_SYMBOLIC
+  ADDRESS_SYMBOLIC,
+  ADDRESS_REG_INC
 };
 
 /* Information about an address described by riscv_address_type.
@@ -92,7 +93,13 @@ enum riscv_address_type {
        is the type of symbol it references.
 
    ADDRESS_SYMBOLIC
-       SYMBOL_TYPE is the type of symbol that the address references.  */
+       SYMBOL_TYPE is the type of symbol that the address references.
+
+   ADDRESS_REG_INC:
+       A base register + offset address access with post modify side-effect
+       (base register += offset).  The offset is an immediate or index
+       register.
+       */
 struct riscv_address_info {
   enum riscv_address_type type;
   rtx reg;
@@ -102,6 +109,7 @@ struct riscv_address_info {
 };
 
 /* Routines implemented in riscv.cc.  */
+bool riscv_legitimate_xcvmem_address_p (machine_mode, rtx, bool);
 extern const char *riscv_asm_output_opcode (FILE *asm_out_file, const char *p);
 extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx);
 extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 3ba45ffaa74..c532b2799a9 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1193,7 +1193,7 @@ riscv_regno_mode_ok_for_base_p (int regno,
 enum reg_class
 riscv_index_reg_class ()
 {
-  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
+  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX || TARGET_XCVMEM)
     return GR_REGS;
 
   return NO_REGS;
@@ -1475,6 +1475,16 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       info->offset = const0_rtx;
       return riscv_valid_base_register_p (info->reg, mode, strict_p);
 
+    case POST_MODIFY:
+      /* For instructions using post inc, the offset can either be register
+       * or 12-bit immediate. */
+       info->type = ADDRESS_REG_INC;
+       info->reg = XEXP (x, 0);
+       info->offset = XEXP ((XEXP (x, 1)), 1);
+       return (riscv_valid_base_register_p (info->reg, mode, strict_p)
+       && (riscv_valid_base_register_p (info->offset, mode, strict_p)
+	       || riscv_valid_offset_p (info->offset, mode)));
+
     case PLUS:
       /* RVV load/store disallow any offset.  */
       if (riscv_v_ext_mode_p (mode))
@@ -1484,7 +1494,8 @@ riscv_classify_address (struct riscv_address_info *info, rtx x,
       info->reg = XEXP (x, 0);
       info->offset = XEXP (x, 1);
       return (riscv_valid_base_register_p (info->reg, mode, strict_p)
-	      && riscv_valid_offset_p (info->offset, mode));
+	      && (riscv_valid_offset_p (info->offset, mode)
+		  || (TARGET_XCVMEM && riscv_valid_base_register_p (info->offset, mode, strict_p))));
 
     case LO_SUM:
       /* RVV load/store disallow LO_SUM.  */
@@ -2638,6 +2649,30 @@ riscv_v_adjust_scalable_frame (rtx target, poly_int64 offset, bool epilogue)
   REG_NOTES (insn) = dwarf;
 }
 
+/* Check if post inc instructions are valid. If not, make the address
+ * vaild. */
+bool
+riscv_legitimate_xcvmem_address_p (machine_mode mode, rtx x, bool strict_p)
+{
+  struct riscv_address_info addr;
+
+  switch (GET_CODE (x))
+    {
+    case POST_MODIFY:
+      if (riscv_classify_address (&addr, x, mode, strict_p))
+	return addr.type == ADDRESS_REG_INC;
+      return false;
+
+    case PLUS:
+      if (REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)) && riscv_classify_address (&addr, x, mode, strict_p))
+	return addr.type == ADDRESS_REG;
+      return false;
+
+    default:
+      return false;
+    }
+}
+
 /* If (set DEST SRC) is not a valid move instruction, emit an equivalent
    sequence that is valid.  */
 
@@ -5919,7 +5954,8 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
     switch (addr.type)
       {
       case ADDRESS_REG:
-	output_addr_const (file, riscv_strip_unspec_address (addr.offset));
+	if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+	else output_addr_const (file, riscv_strip_unspec_address (addr.offset));
 	fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]);
 	return;
 
@@ -5937,6 +5973,12 @@ riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx
 	output_addr_const (file, riscv_strip_unspec_address (x));
 	return;
 
+      case ADDRESS_REG_INC:
+	fprintf (file, "(%s),", reg_names[REGNO (addr.reg)]);
+	if (REG_P (addr.offset)) fprintf (file, "%s", reg_names[REGNO (addr.offset)]);
+	else output_addr_const (file, addr.offset);
+	return;
+
       default:
 	gcc_unreachable ();
       }
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 627eba12548..0c79bc57bcf 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -1217,7 +1217,9 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
    e.g. RVVMF64BI vs RVVMF1BI on zvl512b, which is [1, 1] vs [64, 64].  */
 #define MAX_POLY_VARIANT 64
 
-#define HAVE_POST_MODIFY_DISP TARGET_XTHEADMEMIDX
+#define HAVE_POST_MODIFY_DISP (TARGET_XTHEADMEMIDX || TARGET_XCVMEM)
 #define HAVE_PRE_MODIFY_DISP  TARGET_XTHEADMEMIDX
 
+#define HAVE_POST_MODIFY_REG TARGET_XCVMEM
+
 #endif /* ! GCC_RISCV_H */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index f8a0f7bbfac..0b4588b7205 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1803,7 +1803,7 @@
   [(set (match_operand:GPR    0 "register_operand"     "=r,r")
 	(zero_extend:GPR
 	    (match_operand:HI 1 "nonimmediate_operand" " r,m")))]
-  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
   "@
    #
    lhu\t%0,%1"
@@ -1832,7 +1832,7 @@
   [(set (match_operand:SUPERQI 0 "register_operand"    "=r,r")
 	(zero_extend:SUPERQI
 	    (match_operand:QI 1 "nonimmediate_operand" " r,m")))]
-  "!TARGET_XTHEADMEMIDX"
+  "!TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
   "@
    andi\t%0,%1,0xff
    lbu\t%0,%1"
@@ -1874,7 +1874,7 @@
   [(set (match_operand:SUPERQI   0 "register_operand"     "=r,r")
 	(sign_extend:SUPERQI
 	    (match_operand:SHORT 1 "nonimmediate_operand" " r,m")))]
-  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX"
+  "!TARGET_ZBB && !TARGET_XTHEADBB && !TARGET_XTHEADMEMIDX && !TARGET_XCVMEM"
   "@
    #
    l<SHORT:size>\t%0,%1"
@@ -1934,7 +1934,7 @@
 (define_insn "*movhf_hardfloat"
   [(set (match_operand:HF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:HF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
-  "TARGET_ZFHMIN
+  "TARGET_ZFHMIN && !TARGET_XCVMEM
    && (register_operand (operands[0], HFmode)
        || reg_or_0_operand (operands[1], HFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -1945,7 +1945,7 @@
 (define_insn "*movhf_softfloat"
   [(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
 	(match_operand:HF 1 "move_operand"         " f,Gr,m,r,*r,*f"))]
-  "!TARGET_ZFHMIN
+  "!TARGET_ZFHMIN && !TARGET_XCVMEM
    && (register_operand (operands[0], HFmode)
        || reg_or_0_operand (operands[1], HFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2212,7 +2212,7 @@
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*f,*r,*m,r")
 	(match_operand:SI 1 "move_operand"         " r,T,m,rJ,*r*J,*m,*f,*f,vp"))]
-  "(register_operand (operands[0], SImode)
+  "!TARGET_XCVMEM && (register_operand (operands[0], SImode)
     || reg_or_0_operand (operands[1], SImode))
     && !(register_operand (operands[1], SImode)
          && reg_or_subregno (operands[1]) == VL_REGNUM)"
@@ -2241,7 +2241,7 @@
 (define_insn "*movhi_internal"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
 	(match_operand:HI 1 "move_operand"	   " r,T,m,rJ,*r*J,*f,vp"))]
-  "(register_operand (operands[0], HImode)
+  "!TARGET_XCVMEM && (register_operand (operands[0], HImode)
     || reg_or_0_operand (operands[1], HImode))"
   { return riscv_output_move (operands[0], operands[1]); }
   [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
@@ -2285,7 +2285,7 @@
 (define_insn "*movqi_internal"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r, m,  *f,*r,r")
 	(match_operand:QI 1 "move_operand"         " r,I,m,rJ,*r*J,*f,vp"))]
-  "(register_operand (operands[0], QImode)
+  "!TARGET_XCVMEM && (register_operand (operands[0], QImode)
     || reg_or_0_operand (operands[1], QImode))"
   { return riscv_output_move (operands[0], operands[1]); }
   [(set_attr "move_type" "move,const,load,store,mtc,mfc,rdvlenb")
@@ -2307,7 +2307,7 @@
 (define_insn "*movsf_hardfloat"
   [(set (match_operand:SF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:SF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
-  "TARGET_HARD_FLOAT
+  "TARGET_HARD_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], SFmode)
        || reg_or_0_operand (operands[1], SFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2318,7 +2318,7 @@
 (define_insn "*movsf_softfloat"
   [(set (match_operand:SF 0 "nonimmediate_operand" "= r,r,m")
 	(match_operand:SF 1 "move_operand"         " Gr,m,r"))]
-  "!TARGET_HARD_FLOAT
+  "!TARGET_HARD_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], SFmode)
        || reg_or_0_operand (operands[1], SFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2343,7 +2343,7 @@
 (define_insn "*movdf_hardfloat_rv32"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*zmvf,*zmvr,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))]
-  "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
+  "!TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2354,7 +2354,7 @@
 (define_insn "*movdf_hardfloat_rv64"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))]
-  "TARGET_64BIT && TARGET_DOUBLE_FLOAT
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
@@ -2365,7 +2365,7 @@
 (define_insn "*movdf_softfloat"
   [(set (match_operand:DF 0 "nonimmediate_operand" "= r,r, m")
 	(match_operand:DF 1 "move_operand"         " rG,m,rG"))]
-  "!TARGET_DOUBLE_FLOAT
+  "!TARGET_DOUBLE_FLOAT && !TARGET_XCVMEM
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 65c656204ca..a1304cc2d41 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -425,6 +425,8 @@ Mask(XCVALU) Var(riscv_xcv_subext)
 
 Mask(XCVELW) Var(riscv_xcv_subext)
 
+Mask(XCVMEM) Var(riscv_xcv_subext)
+
 TargetVariable
 int riscv_xthead_subext
 
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 8082100a3c9..649a8ae36f7 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2505,6 +2505,9 @@ Test system has support for the CORE-V ALU extension.
 @item cv_elw
 Test system has support for the CORE-V ELW extension.
 
+@item cv_mem
+Test system has support for the CORE-V MEM extension.
+
 @end table
 
 @subsubsection Other hardware attributes
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
new file mode 100644
index 00000000000..a323ac71746
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+  int char_sum = 1;
+
+  for (int i = 0; i < n; i++)
+    char_sum += array_char [i];
+
+  return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
new file mode 100644
index 00000000000..05dcd894509
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int j)
+{
+  int char_sum = 1;
+
+  for (int i = 0; i < 5; i += j)
+  {
+    char_sum += *array_char;
+    array_char += j * sizeof (array_char);
+  }
+
+  return char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
new file mode 100644
index 00000000000..2e99cd2575c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lb-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+  return array_char [i + j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
new file mode 100644
index 00000000000..5222da46f58
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+  int uns_char_sum = 1;
+
+  for (int i = 0; i < n; i++)
+    uns_char_sum += array_uchar [i];
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
new file mode 100644
index 00000000000..7b378be7b4c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int j)
+{
+  int uns_char_sum = 1;
+
+  for (int i = 0; i < 5; i += j)
+  {
+    uns_char_sum += *array_uchar;
+    array_uchar += j * sizeof (array_uchar);
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
new file mode 100644
index 00000000000..a2c3adc732f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lbu-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+  return array_uchar [i + j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lbu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
new file mode 100644
index 00000000000..4282fd8f03c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short)
+{
+  int short_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    short_sum += array_short [i];
+
+  return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
new file mode 100644
index 00000000000..b84d6e3442d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int j)
+{
+  int short_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    short_sum += *array_short;
+    array_short += j * sizeof (array_short);
+  }
+
+  return short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
new file mode 100644
index 00000000000..26fa7967382
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lh-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+  return array_short [i + j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
new file mode 100644
index 00000000000..ff73b79e941
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort)
+{
+  int uns_short_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    uns_short_sum += array_ushort [i];
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
new file mode 100644
index 00000000000..9a4c5be212c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int j)
+{
+  int uns_short_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    uns_short_sum += *array_ushort;
+    array_ushort += j * sizeof (array_ushort);
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
new file mode 100644
index 00000000000..ffc54fe3585
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lhu-compile-3.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+  return array_ushort [i + j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lhu\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
new file mode 100644
index 00000000000..6c2815811e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-1.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32ic_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* We don't generate for some optimization levels. TODO: should support for Og. */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate loads.
+ */
+
+int
+fooSIsigned (signed int* array_int)
+{
+  int int_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    int_sum += array_int [i];
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint)
+{
+  int uns_int_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    uns_int_sum += array_uint [i];
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
new file mode 100644
index 00000000000..57d4c678fc8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int j)
+{
+  int int_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    int_sum += *array_int;
+    array_int += j * sizeof (array_int);
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int j)
+{
+  int uns_int_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    uns_int_sum += *array_uint;
+    array_uint += j * sizeof (array_uint);
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
new file mode 100644
index 00000000000..fbce11fc697
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-lw-compile-3.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register loads.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+  return array_int [i + j];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+  return array_uint [i + j];
+}
+
+/* { dg-final { scan-assembler-times "cv\\.lw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
new file mode 100644
index 00000000000..05204b41573
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (plus:SI (reg reg)))`.
+ */
+
+struct {
+  double a[3];
+} * b;
+int c;
+
+int
+foo (void)
+{
+  b[0].a[c] -= b[0].a[c];
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
new file mode 100644
index 00000000000..373915f73d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2" } */
+
+/*
+ * Test for illegal XCVmem specific operand.
+ * Pattern: `(mem:DF (post_modify:SI (reg reg)))`.
+ */
+
+int bar (double);
+
+int
+foo (void)
+{
+  double *b;
+  int c = 0;
+  for (;; c++)
+    bar (b[c]);
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
new file mode 100644
index 00000000000..c622d60cd2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-3.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -g -O2 -Wno-int-conversion" } */
+
+/*
+ * Test for illegal XCVmem specific operand in loads.
+ * Instruction `lbu reg,reg(reg)`.
+ */
+
+int a;
+int bar (char);
+
+int
+foo (void)
+{
+  short *d;
+  char *e = (char *)foo;
+  for (;;) {
+    char c = d++;
+    bar (c);
+    short b = e[0] + b;
+    if (b)
+      a = 5;
+    e += 2;
+  }
+}
+
+/* { dg-final { scan-assembler-not "lbu\t\[a-z\]\[0-99\],\[a-z\]\[0-99\]\\(\[a-z\]\[0-99\]\\)" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
new file mode 100644
index 00000000000..4922f9667d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32if_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in flw.
+ * Error: illegal operands `flw fa5,a5(a4)'
+ */
+
+int b, e;
+float *m;
+
+int
+foo (void) {
+  m[1] = m[b];
+  m[b] = e;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "flw\tfa5,a5\\(a4\\)" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
new file mode 100644
index 00000000000..140486ce20b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-5.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32" } */
+
+/*
+ * Tests that stores can generate regular reg:imm operands.
+ */
+
+int a[1];
+int b, c, d, e, f;
+float g;
+
+int
+foo (void)
+{
+  int h;
+  for (;; d++)
+    switch (c) {
+    case 8:
+      g = e == f;
+      a[h + d] = g;
+      g = e < f;
+      b = g;
+    }
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
new file mode 100644
index 00000000000..8d6113971a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+
+/*
+ * Test for illegal XCVmem specific operands in lw.
+ */
+
+int
+fooSIsigned (signed int* array_int)
+{
+  return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint)
+{
+  return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.lw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
new file mode 100644
index 00000000000..dc61d859988
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-7.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for illegal XCVmem specific operands in register-immediate sw.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i)
+{
+  array_int [3] = i;
+  return array_int [3];
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i)
+{
+  array_uint [3] = i;
+  return array_uint [3];
+}
+
+/* { dg-final { scan-assembler-not "cv\\.sw\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
new file mode 100644
index 00000000000..da7f5166fe7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-operand-compile-8.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem" } */
+
+/*
+ * Test for illegal XCVmem specific operand in sw.
+ */
+
+int a;
+float *b;
+
+int
+foo (void)
+{
+  int c;
+  for (c = 0; c < 10; c++)
+    b[c] = a;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
new file mode 100644
index 00000000000..f46f4520d51
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n)
+{
+  int char_sum = 1;
+
+  for (int i = 0; i < n; i++)
+    array_char [i] += char_sum;
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n)
+{
+  int uns_char_sum = 1;
+
+  for (int i = 0; i < n; i++)
+    array_uchar [i] += uns_char_sum;
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),1" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
new file mode 100644
index 00000000000..e9d60eb95ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int n, int j)
+{
+  int char_sum = 1;
+
+  for (int i = 0; i < n; i += j)
+  {
+    *array_char += char_sum;
+    array_char += j * sizeof (array_char);
+  }
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int n, int j)
+{
+  int uns_char_sum = 1;
+
+  for (int i = 0; i < n; i += j)
+  {
+    *array_uchar += uns_char_sum;
+    array_uchar += j * sizeof (array_uchar);
+  }
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
new file mode 100644
index 00000000000..d2990311f2c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sb-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops -fno-tree-vectorize" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooQIsigned (signed char* array_char, int i, int j)
+{
+  int char_sum = 1;
+
+  array_char [i + j] += char_sum;
+
+  return char_sum;
+}
+
+int
+fooQIunsigned (unsigned char* array_uchar, int i, int j)
+{
+  int uns_char_sum = 1;
+
+  array_uchar [i + j] += uns_char_sum;
+
+  return uns_char_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sb\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
new file mode 100644
index 00000000000..7ebc58e698b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short)
+{
+  int short_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    array_short [i] += short_sum;
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort)
+{
+  int uns_short_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    array_ushort [i] += uns_short_sum;
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),2" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
new file mode 100644
index 00000000000..000fed2b85e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int j)
+{
+  int short_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    *array_short += short_sum;
+    array_short += j * sizeof (array_short);
+  }
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int j)
+{
+  int uns_short_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    *array_ushort += uns_short_sum;
+    array_ushort += j * sizeof (array_ushort);
+  }
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
new file mode 100644
index 00000000000..c715c351221
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sh-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooHIsigned (signed short int* array_short, int i, int j)
+{
+  int short_sum = 1;
+
+  array_short [i + j] = short_sum;
+
+  return short_sum;
+}
+
+int
+fooHIunsigned (unsigned short int* array_ushort, int i, int j)
+{
+  int uns_short_sum = 1;
+
+  array_ushort [i + j] += uns_short_sum;
+
+  return uns_short_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sh\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
new file mode 100644
index 00000000000..640adcf521d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-immediate saves.
+ */
+
+int
+fooSIsigned (signed int* array_int)
+{
+  int int_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    array_int [i] += int_sum;
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint)
+{
+  int uns_int_sum = 1;
+
+  for (int i = 0; i < 200; i++)
+    array_uint [i] += uns_int_sum;
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),4" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
new file mode 100644
index 00000000000..941fed353fa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+/*
+ * Test for post-inc register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int j)
+{
+  int int_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    *array_int += int_sum;
+    array_int += j * sizeof (array_int);
+  }
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int j)
+{
+  int uns_int_sum = 1;
+
+  for (int i = 0; i < 200; i += j)
+  {
+    *array_uint += uns_int_sum;
+    array_uint += j * sizeof (array_uint);
+  }
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\),\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c
new file mode 100644
index 00000000000..96eaf391ede
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cv-mem-sw-compile-3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target cv_mem } */
+/* { dg-options "-march=rv32i_xcvmem -mabi=ilp32 -fno-unroll-loops" } */
+/* { dg-skip-if "" { *-*-* }  { "-O0" } { "" } } */
+
+/*
+ * Test for normal register-register saves.
+ */
+
+int
+fooSIsigned (signed int* array_int, int i, int j)
+{
+  int int_sum = 1;
+
+  array_int [i + j] = int_sum;
+
+  return int_sum;
+}
+
+int
+fooSIunsigned (unsigned int* array_uint, int i, int j)
+{
+  int uns_int_sum = 1;
+
+  array_uint [i + j] = uns_int_sum;
+
+  return uns_int_sum;
+}
+
+/* { dg-final { scan-assembler-times "cv\\.sw\t\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\),(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\(\(\?\:t\[0-6\]\|a\[0-7\]\|s\[1-11\]\)\\)" 2 } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 73360cd3a0d..c78a6e7a5ad 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -13357,6 +13357,19 @@ proc check_effective_target_cv_elw { } {
     } "-march=rv32i_xcvelw" ]
 }
 
+# Return 1 if the CORE-V MEM extension is available.
+proc check_effective_target_cv_mem { } {
+    if { !([istarget riscv*-*-*]) } {
+         return 0
+     }
+    return [check_no_compiler_messages cv_mem object {
+        void foo (void)
+        {
+          asm ("cv.lw t0, (t1), 4");
+        }
+    } "-march=rv32i_xcvmem" ]
+}
+
 proc check_effective_target_loongarch_sx { } {
     return [check_no_compiler_messages loongarch_lsx assembly {
        #if !defined(__loongarch_sx)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2024-01-25 14:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-09 12:42 [PATCH 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
2023-11-09 12:42 ` [PATCH 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
2023-11-19  7:55   ` Kito Cheng
2024-01-11 14:41 ` [PATCH v2 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
2024-01-11 14:41   ` [PATCH v2 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett
2024-01-25 14:02 ` [PATCH v3 0/1] RISC-V: Support CORE-V XCVMEM extension Mary Bennett
2024-01-25 14:02   ` [PATCH v3 1/1] RISC-V: Add support for XCVmem extension in CV32E40P Mary Bennett

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).