[11/11] riscv: thead: Add support for the XTheadFMemIdx ISA extension

Message ID 20230428062314.2995571-2-christoph.muellner@vrull.eu
State Accepted
Headers
Series Improvements for XThead* support |

Checks

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

Commit Message

Christoph Müllner April 28, 2023, 6:23 a.m. UTC
  From: Christoph Müllner <christoph.muellner@vrull.eu>

The XTheadFMemIdx ISA extension provides additional load and store
instructions for floating-point registers with new addressing modes.

The following memory accesses types are supported:
* ftype = [w,d] (single-precision, double-precision)

The following addressing modes are supported:
* register offset with additional immediate offset (4 instructions):
  flr<type>, fsr<type>
* zero-extended register offset with additional immediate offset
  (4 instructions): flur<type>, fsur<type>

These addressing modes are also part of the similar XTheadMemIdx
ISA extension support, whose code is reused and extended to support
floating-point registers.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_index_reg_class): Also allow
	for XTheadFMemIdx.
	(riscv_regno_ok_for_index_p): Likewise.
	* config/riscv/thead-peephole.md (TARGET_64BIT):
	Generalize peepholes for XTheadFMemIdx.
	* config/riscv/thead.cc (is_fmemidx_mode): New function.
	(th_memidx_classify_address_index): Add support for
	XTheadFMemIdx.
	(th_fmemidx_output_index): New function.
	(th_output_move): Add support for XTheadFMemIdx.
	* config/riscv/thead.md (*th_fmemidx_movsf_hardfloat): New INSN.
	(*th_fmemidx_movdf_hardfloat_rv64): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadmemidx-helpers.h: Add helpers for
	  XTheadMemFIdx.
	* gcc.target/riscv/xtheadfmemidx-index-update.c: New test.
	* gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c: New test.
	* gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c: New test.
	* gcc.target/riscv/xtheadfmemidx-index.c: New test.
	* gcc.target/riscv/xtheadfmemidx-uindex-update.c: New test.
	* gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c: New test.
	* gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c: New test.
	* gcc.target/riscv/xtheadfmemidx-uindex.c: New test.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/riscv.cc                     |  4 +-
 gcc/config/riscv/thead-peephole.md            | 24 ++++---
 gcc/config/riscv/thead.cc                     | 68 +++++++++++++++++-
 gcc/config/riscv/thead.md                     | 22 ++++++
 .../riscv/xtheadfmemidx-index-update.c        | 20 ++++++
 .../xtheadfmemidx-index-xtheadbb-update.c     | 20 ++++++
 .../riscv/xtheadfmemidx-index-xtheadbb.c      | 22 ++++++
 .../gcc.target/riscv/xtheadfmemidx-index.c    | 22 ++++++
 .../riscv/xtheadfmemidx-uindex-update.c       | 20 ++++++
 .../xtheadfmemidx-uindex-xtheadbb-update.c    | 20 ++++++
 .../riscv/xtheadfmemidx-uindex-xtheadbb.c     | 24 +++++++
 .../gcc.target/riscv/xtheadfmemidx-uindex.c   | 25 +++++++
 .../gcc.target/riscv/xtheadmemidx-helpers.h   | 70 +++++++++++++++++++
 13 files changed, 348 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-update.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-update.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex.c
  

Comments

Jeff Law June 10, 2023, 5:54 p.m. UTC | #1
On 4/28/23 00:23, Christoph Muellner wrote:
> From: Christoph Müllner <christoph.muellner@vrull.eu>
> 
> The XTheadFMemIdx ISA extension provides additional load and store
> instructions for floating-point registers with new addressing modes.
> 
> The following memory accesses types are supported:
> * ftype = [w,d] (single-precision, double-precision)
> 
> The following addressing modes are supported:
> * register offset with additional immediate offset (4 instructions):
>    flr<type>, fsr<type>
> * zero-extended register offset with additional immediate offset
>    (4 instructions): flur<type>, fsur<type>
> 
> These addressing modes are also part of the similar XTheadMemIdx
> ISA extension support, whose code is reused and extended to support
> floating-point registers.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_index_reg_class): Also allow
> 	for XTheadFMemIdx.
> 	(riscv_regno_ok_for_index_p): Likewise.
> 	* config/riscv/thead-peephole.md (TARGET_64BIT):
> 	Generalize peepholes for XTheadFMemIdx.
> 	* config/riscv/thead.cc (is_fmemidx_mode): New function.
> 	(th_memidx_classify_address_index): Add support for
> 	XTheadFMemIdx.
> 	(th_fmemidx_output_index): New function.
> 	(th_output_move): Add support for XTheadFMemIdx.
> 	* config/riscv/thead.md (*th_fmemidx_movsf_hardfloat): New INSN.
> 	(*th_fmemidx_movdf_hardfloat_rv64): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/xtheadmemidx-helpers.h: Add helpers for
> 	  XTheadMemFIdx.
> 	* gcc.target/riscv/xtheadfmemidx-index-update.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-index.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-uindex-update.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c: New test.
> 	* gcc.target/riscv/xtheadfmemidx-uindex.c: New test.
Same core questions/comments as in patch #10 of this series.

jeff
  
Christoph Müllner June 28, 2023, 12:39 p.m. UTC | #2
On Sat, Jun 10, 2023 at 7:54 PM Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
> On 4/28/23 00:23, Christoph Muellner wrote:
> > From: Christoph Müllner <christoph.muellner@vrull.eu>
> >
> > The XTheadFMemIdx ISA extension provides additional load and store
> > instructions for floating-point registers with new addressing modes.
> >
> > The following memory accesses types are supported:
> > * ftype = [w,d] (single-precision, double-precision)
> >
> > The following addressing modes are supported:
> > * register offset with additional immediate offset (4 instructions):
> >    flr<type>, fsr<type>
> > * zero-extended register offset with additional immediate offset
> >    (4 instructions): flur<type>, fsur<type>
> >
> > These addressing modes are also part of the similar XTheadMemIdx
> > ISA extension support, whose code is reused and extended to support
> > floating-point registers.
> >
> > gcc/ChangeLog:
> >
> >       * config/riscv/riscv.cc (riscv_index_reg_class): Also allow
> >       for XTheadFMemIdx.
> >       (riscv_regno_ok_for_index_p): Likewise.
> >       * config/riscv/thead-peephole.md (TARGET_64BIT):
> >       Generalize peepholes for XTheadFMemIdx.
> >       * config/riscv/thead.cc (is_fmemidx_mode): New function.
> >       (th_memidx_classify_address_index): Add support for
> >       XTheadFMemIdx.
> >       (th_fmemidx_output_index): New function.
> >       (th_output_move): Add support for XTheadFMemIdx.
> >       * config/riscv/thead.md (*th_fmemidx_movsf_hardfloat): New INSN.
> >       (*th_fmemidx_movdf_hardfloat_rv64): Likewise.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * gcc.target/riscv/xtheadmemidx-helpers.h: Add helpers for
> >         XTheadMemFIdx.
> >       * gcc.target/riscv/xtheadfmemidx-index-update.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-index.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-uindex-update.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c: New test.
> >       * gcc.target/riscv/xtheadfmemidx-uindex.c: New test.
> Same core questions/comments as in patch #10 of this series.

The basic support for this extension is already merged.

The documentation can be found here:
  https://github.com/T-head-Semi/thead-extension-spec/tree/master

The extension's name and a link to the documentation has also been
registered here:
 https://github.com/riscv-non-isa/riscv-toolchain-conventions#list-of-vendor-extensions

The XTheadFMemIdx extension is part of the T-Head C906 and C910 SoCs.
The C906 was launched in October 2021.

Thanks,
Christoph

>
> jeff
>
  

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 1691ecf3a94..d1e08974023 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -834,7 +834,7 @@  riscv_regno_mode_ok_for_base_p (int regno,
 enum reg_class
 riscv_index_reg_class ()
 {
-  if (TARGET_XTHEADMEMIDX)
+  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
     return GR_REGS;
 
   return NO_REGS;
@@ -847,7 +847,7 @@  riscv_index_reg_class ()
 int
 riscv_regno_ok_for_index_p (int regno)
 {
-  if (TARGET_XTHEADMEMIDX)
+  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
     return riscv_regno_mode_ok_for_base_p (regno, VOIDmode, 1);
 
   return 0;
diff --git a/gcc/config/riscv/thead-peephole.md b/gcc/config/riscv/thead-peephole.md
index 2a4c734a220..e3de9b8e8d3 100644
--- a/gcc/config/riscv/thead-peephole.md
+++ b/gcc/config/riscv/thead-peephole.md
@@ -73,11 +73,15 @@  (define_peephole2
   th_mempair_order_operands (operands, true, SImode);
 })
 
-;; All modes that are supported by XTheadMemIdx
-(define_mode_iterator TH_M_ANY [QI HI SI (DI "TARGET_64BIT")])
+;; All modes that are supported by XTheadMemIdx and XTheadFMemIdx
+(define_mode_iterator TH_M_ANY [QI HI SI (DI "TARGET_64BIT")
+                                (SF "TARGET_HARD_FLOAT")
+                                (DF "TARGET_DOUBLE_FLOAT")])
 
-;; All non-extension modes that are supported by XTheadMemIdx
-(define_mode_iterator TH_M_NOEXT [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
+;; All non-extension modes that are supported by XTheadMemIdx and XTheadFMemIdx
+(define_mode_iterator TH_M_NOEXT [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")
+                                  (SF "TARGET_HARD_FLOAT")
+                                  (DF "TARGET_DOUBLE_FLOAT")])
 
 ;; XTheadMemIdx overview:
 ;; All peephole passes attempt to improve the operand utilization of
@@ -125,7 +129,7 @@  (define_peephole2
         (mem:TH_M_NOEXT (plus:X
           (match_dup 0)
           (match_operand:X 4 "register_operand" ""))))]
-  "TARGET_XTHEADMEMIDX
+  "(TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
    && peep2_reg_dead_p (2, operands[0])
    && IN_RANGE (INTVAL (operands[2]), 0, 3)"
   [(set (match_dup 3)
@@ -161,7 +165,7 @@  (define_peephole2
           (match_dup 0)
           (match_operand:X 4 "register_operand" "")))
         (match_operand:TH_M_ANY 3 "register_operand" ""))]
-  "TARGET_XTHEADMEMIDX
+  "(TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
    && peep2_reg_dead_p (2, operands[0])
    && IN_RANGE (INTVAL (operands[2]), 0, 3)"
   [(set (mem:TH_M_ANY (plus:X
@@ -180,7 +184,7 @@  (define_peephole2
         (mem:TH_M_NOEXT (plus:DI
           (match_dup 3)
           (match_operand:DI 6 "register_operand" ""))))]
-  "TARGET_64BIT && TARGET_XTHEADMEMIDX
+  "TARGET_64BIT && (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
    && peep2_reg_dead_p (3, operands[0])
    && peep2_reg_dead_p (3, operands[3])
    && IN_RANGE (INTVAL (operands[4]), 29, 32)"
@@ -226,7 +230,7 @@  (define_peephole2
           (match_dup 3)
           (match_operand:DI 6 "register_operand" "")))
         (match_operand:TH_M_ANY 5 "register_operand" ""))]
-  "TARGET_64BIT && TARGET_XTHEADMEMIDX
+  "TARGET_64BIT && (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
    && peep2_reg_dead_p (3, operands[0])
    && peep2_reg_dead_p (3, operands[3])
    && IN_RANGE (INTVAL (operands[4]), 29, 32)"
@@ -247,7 +251,7 @@  (define_peephole2
         (mem:TH_M_NOEXT (plus:DI
           (match_dup 0)
           (match_operand:DI 4 "register_operand" ""))))]
-  "TARGET_64BIT && TARGET_XTHEADMEMIDX
+  "TARGET_64BIT && (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
    && peep2_reg_dead_p (2, operands[0])"
   [(set (match_dup 3)
         (mem:TH_M_NOEXT (plus:DI
@@ -279,7 +283,7 @@  (define_peephole2
           (match_dup 0)
           (match_operand:DI 4 "register_operand" "")))
         (match_operand:TH_M_ANY 3 "register_operand" ""))]
-  "TARGET_64BIT && TARGET_XTHEADMEMIDX
+  "TARGET_64BIT && (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
    && peep2_reg_dead_p (2, operands[0])"
   [(set (mem:TH_M_ANY (plus:DI
           (match_dup 4)
diff --git a/gcc/config/riscv/thead.cc b/gcc/config/riscv/thead.cc
index bfe035250af..3671f1bf9ac 100644
--- a/gcc/config/riscv/thead.cc
+++ b/gcc/config/riscv/thead.cc
@@ -591,6 +591,21 @@  is_memidx_mode (machine_mode mode)
   return false;
 }
 
+static bool
+is_fmemidx_mode (machine_mode mode)
+{
+  if (!TARGET_HARD_FLOAT)
+    return false;
+
+  if (mode == SFmode)
+    return true;
+
+  if (mode == DFmode && TARGET_DOUBLE_FLOAT)
+    return true;
+
+  return false;
+}
+
 /* Return true if X is a valid address for T-Head's memory addressing modes
    with scaled register offsets for machine mode MODE.
    If it is, fill in INFO appropriately (if non-NULL).
@@ -601,7 +616,8 @@  th_memidx_classify_address_index (struct riscv_address_info *info, rtx x,
 				  machine_mode mode, bool strict_p)
 {
   /* Ensure that the mode is supported.  */
-  if (!(TARGET_XTHEADMEMIDX && is_memidx_mode (mode)))
+  if (!(TARGET_XTHEADMEMIDX && is_memidx_mode (mode))
+      && !(TARGET_XTHEADFMEMIDX && is_fmemidx_mode (mode)))
     return false;
 
   if (GET_CODE (x) != PLUS)
@@ -757,6 +773,40 @@  th_memidx_output_index (rtx x, machine_mode mode, bool load)
   return buf;
 }
 
+/* Provide a buffer for a th.flX/th.fluX/th.fsX/th.fsuX instruction
+   for the given MODE. If LOAD is true, a load instruction will be
+   provided (otherwise, a store instruction). If X is not suitable
+   return NULL.  */
+
+static const char *
+th_fmemidx_output_index (rtx x, machine_mode mode, bool load)
+{
+  struct riscv_address_info info;
+  static char buf[128] = {0};
+
+  /* Validate x.  */
+  if (!th_memidx_classify_address_index (&info, x, mode, false))
+    return NULL;
+
+  int index = exact_log2 (GET_MODE_SIZE (mode).to_constant ()) - 2;
+  bool uindex = info.type == ADDRESS_REG_UREG;
+
+  const char *const insn[][2] = {
+    {
+      "th.fs%srw\t%%z1,%%0",
+      "th.fs%srd\t%%z1,%%0"
+    },
+    {
+      "th.fl%srw\t%%0,%%1",
+      "th.fl%srd\t%%0,%%1"
+    }
+  };
+
+  snprintf (buf, sizeof (buf), insn[load][index], uindex ? "u" : "");
+
+  return buf;
+}
+
 /* Return true if X is a valid address for T-Head's memory addressing modes
    for machine mode MODE.  If it is, fill in INFO appropriately (if non-NULL).
    If STRICT_P is true then REG_OK_STRICT is in effect.  */
@@ -811,6 +861,14 @@  th_output_move (rtx dest, rtx src)
       if ((insn = th_memidx_output_modify (x, mode, true)))
 	return insn;
     }
+  else if (dest_code == REG && FP_REG_P (REGNO (dest)) && src_code == MEM)
+    {
+      rtx x = XEXP (src, 0);
+      mode = GET_MODE (src);
+
+      if ((insn = th_fmemidx_output_index (x, mode, true)))
+	return insn;
+    }
   else if (((src_code == REG && GP_REG_P (REGNO (src)))
 	    || (src == CONST0_RTX (mode)))
 	   && dest_code == MEM)
@@ -824,6 +882,14 @@  th_output_move (rtx dest, rtx src)
 	if ((insn = th_memidx_output_modify (x, mode, false)))
 	  return insn;
     }
+  else if (src_code == REG && FP_REG_P (REGNO (src)) && dest_code == MEM)
+    {
+      rtx x = XEXP (dest, 0);
+      mode = GET_MODE (dest);
+
+      if ((insn = th_fmemidx_output_index (x, mode, false)))
+	return insn;
+    }
 
   return NULL;
 }
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index 5536500e4ff..e8759e1b77d 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -555,4 +555,26 @@  (define_insn "*th_memidx_bb_extendqi<SUPERQI:mode>2"
   [(set_attr "move_type" "shift_shift,load,load,load,load,load")
    (set_attr "mode" "<SUPERQI:MODE>")])
 
+;; XTheadFMemIdx
+
+(define_insn "*th_fmemidx_movsf_hardfloat"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,th_m_mir,f,th_m_miu")
+	(match_operand:SF 1 "move_operand"         " th_m_mir,f,th_m_miu,f"))]
+  "TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX
+   && (register_operand (operands[0], SFmode)
+       || reg_or_0_operand (operands[1], SFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fpload,fpstore,fpload,fpstore")
+   (set_attr "mode" "SF")])
+
+(define_insn "*th_fmemidx_movdf_hardfloat_rv64"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,th_m_mir,f,th_m_miu")
+	(match_operand:DF 1 "move_operand"         " th_m_mir,f,th_m_miu,f"))]
+  "TARGET_64BIT && TARGET_DOUBLE_FLOAT && TARGET_XTHEADFMEMIDX
+   && (register_operand (operands[0], DFmode)
+       || reg_or_0_operand (operands[1], DFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fpload,fpstore,fpload,fpstore")
+   (set_attr "mode" "DF")])
+
 (include "thead-peephole.md")
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-update.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-update.c
new file mode 100644
index 00000000000..cc97fd2f786
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-update.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLR_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+FLR_REG_IMM_UPD(double, 2)
+#endif
+
+FSR_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+FSR_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times "slli" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "slli" 3 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c
new file mode 100644
index 00000000000..3b3a7fbdd4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb-update.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadbb_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLR_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+FLR_REG_IMM_UPD(double, 2)
+#endif
+
+FSR_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+FSR_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times "slli" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "slli" 3 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c
new file mode 100644
index 00000000000..55d1f651bd2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index-xtheadbb.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadbb_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLR_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times "th.flrw\t\[^\n\r\]*0\[\n\r\]" 1 } } */
+#if __riscv_xlen == 64
+FLR_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times "th.flrd\t\[^\n\r\]*2\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+FSR_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times "th.fsrw\t\[^\n\r\]*1\[\n\r\]" 1 } } */
+#if __riscv_xlen == 64
+FSR_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times "th.fsrd\t\[^\n\r\]*3\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not "slli" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index.c
new file mode 100644
index 00000000000..b92f4adc0b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-index.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLR_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times "th.flrw\t\[^\n\r\]*0\[\n\r\]" 1 } } */
+#if __riscv_xlen == 64
+FLR_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times "th.flrd\t\[^\n\r\]*2\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+FSR_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times "th.fsrw\t\[^\n\r\]*1\[\n\r\]" 1 } } */
+#if __riscv_xlen == 64
+FSR_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times "th.fsrd\t\[^\n\r\]*3\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not "slli" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-update.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-update.c
new file mode 100644
index 00000000000..075cefdb971
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-update.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLUR_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+FLUR_REG_IMM_UPD(double, 2)
+#endif
+
+FSUR_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+FSUR_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times "slli" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "slli" 3 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c
new file mode 100644
index 00000000000..a677e82768a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb-update.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadbb_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLUR_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+FLUR_REG_IMM_UPD(double, 2)
+#endif
+
+FSUR_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+FSUR_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times "slli" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "slli" 3 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c
new file mode 100644
index 00000000000..3377c26963b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex-xtheadbb.c
@@ -0,0 +1,24 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadbb_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLUR_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times "th.flurw\t\[^\n\r\]*0\[\n\r\]" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.flrw\t\[^\n\r\]*0\[\n\r\]" 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+FLUR_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times "th.flurd\t\[^\n\r\]*2\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+FSUR_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times "th.fsurw\t\[^\n\r\]*1\[\n\r\]" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.fsrw\t\[^\n\r\]*1\[\n\r\]" 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+FSUR_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times "th.fsurd\t\[^\n\r\]*3\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not "slli" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex.c
new file mode 100644
index 00000000000..0c84a651eb6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-uindex.c
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+/* { dg-options "-march=rv64gc_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+FLUR_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times "th.flurw\t\[^\n\r\]*0\[\n\r\]" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.flrw\t\[^\n\r\]*0\[\n\r\]" 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+FLUR_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times "th.flurd\t\[^\n\r\]*2\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+FSUR_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times "th.fsurw\t\[^\n\r\]*1\[\n\r\]" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.fsrw\t\[^\n\r\]*1\[\n\r\]" 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+FSUR_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times "th.fsurd\t\[^\n\r\]*3\[\n\r\]" 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not "slli" } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadmemidx-helpers.h b/gcc/testsuite/gcc.target/riscv/xtheadmemidx-helpers.h
index a97f08c5cc1..62c4f67f968 100644
--- a/gcc/testsuite/gcc.target/riscv/xtheadmemidx-helpers.h
+++ b/gcc/testsuite/gcc.target/riscv/xtheadmemidx-helpers.h
@@ -149,4 +149,74 @@ 
     *rs2 = t;								\
   }
 
+#define FLR_REG_IMM(T, IMM)						\
+  T									\
+  flr_reg_imm_ ## T ## _ ## IMM (intX_t rs1, intX_t rs2)		\
+  {									\
+    return *(T*)(rs1 + (rs2 << IMM));					\
+  }
+
+#define FSR_REG_IMM(T, IMM)						\
+  void									\
+  sr_reg_imm_ ## T ## _ ## IMM (intX_t rs1, intX_t rs2, T val)		\
+  {									\
+    *(T*)(rs1 + (rs2 << IMM)) = val;					\
+  }
+
+#define FLR_REG_IMM_UPD(T, IMM)						\
+  T									\
+  flr_reg_imm_upd_ ## T ## _ ## IMM (intX_t rs1, intX_t *rs2)		\
+  {									\
+    intX_t addr = rs1 + (*rs2 << IMM);					\
+    T val = *(T*)addr;							\
+    *rs2 = addr;							\
+    return val;								\
+  }
+
+#define FSR_REG_IMM_UPD(T, IMM)						\
+  void									\
+  sr_reg_imm_upd_ ## T ## _ ## IMM (intX_t rs1, intX_t *rs2, T val)	\
+  {									\
+    intX_t addr = rs1 + (*rs2 << IMM);					\
+    *(T*)addr = val;							\
+    *rs2 = addr;							\
+  }
+
+#define FLUR_REG_IMM(T, IMM)						\
+  T									\
+  flr_reg_imm_ ## T ## _ ## IMM (intX_t rs1, intX_t rs2)		\
+  {									\
+    rs2 = (uint32_t)rs2;						\
+    return *(T*)(rs1 + (rs2 << IMM));					\
+  }
+
+#define FSUR_REG_IMM(T, IMM)						\
+  void									\
+  sr_reg_imm_ ## T ## _ ## IMM (intX_t rs1, intX_t rs2, T val)		\
+  {									\
+    rs2 = (uint32_t)rs2;						\
+    *(T*)(rs1 + (rs2 << IMM)) = val;					\
+  }
+
+#define FLUR_REG_IMM_UPD(T, IMM)					\
+  T									\
+  flr_reg_imm_upd_ ## T ## _ ## IMM (intX_t rs1, intX_t *rs2)		\
+  {									\
+    intX_t rs2_32 = (uint32_t)*rs2;					\
+    intX_t addr = rs1 + (rs2_32 << IMM);				\
+    T val = *(T*)addr;							\
+    *rs2 = addr;							\
+    return val;								\
+  }
+
+#define FSUR_REG_IMM_UPD(T, IMM)					\
+  void									\
+  sr_reg_imm_upd_ ## T ## _ ## IMM (intX_t rs1, intX_t *rs2, T val)	\
+  {									\
+    intX_t rs2_32 = (uint32_t)*rs2;					\
+    intX_t addr = rs1 + (rs2_32 << IMM);				\
+    *(T*)addr = val;							\
+    *rs2 = addr;							\
+  }
+
 #endif /* XTHEADMEMIDX_HELPERS_H */