diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index de6d9734da0..0148a4f2e43 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)
+  if (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX)
     return GR_REGS;
 
   return NO_REGS;
@@ -1097,7 +1097,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/riscv.h b/gcc/config/riscv/riscv.h
index eb162abcb92..1e9813b4f39 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -372,6 +372,8 @@ ASM_MISA_SPEC
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
+#define HARDFP_REG_P(REGNO)  \
+  ((REGNO) >= FP_REG_FIRST && (REGNO) <= FP_REG_LAST)
 #define V_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - V_REG_FIRST) < V_REG_NUM)
 #define VL_REG_P(REGNO) ((REGNO) == VL_REGNUM)
diff --git a/gcc/config/riscv/thead.cc b/gcc/config/riscv/thead.cc
index 237d96ff4b7..a485fb1fba6 100644
--- a/gcc/config/riscv/thead.cc
+++ b/gcc/config/riscv/thead.cc
@@ -614,6 +614,18 @@ is_memidx_mode (machine_mode mode)
   return false;
 }
 
+static bool
+is_fmemidx_mode (machine_mode mode)
+{
+  if (mode == SFmode && TARGET_HARD_FLOAT)
+    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).
@@ -624,7 +636,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)
@@ -781,6 +794,44 @@ th_memidx_output_index (rtx dest, rtx src, machine_mode mode, bool load)
   return "";
 }
 
+/* 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 dest, rtx src, machine_mode mode, bool load)
+{
+  struct riscv_address_info info;
+  char format[24];
+  rtx output_operands[2];
+  rtx x = th_get_move_mem_addr (dest, src, load);
+
+  /* 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 (format, sizeof (format), insn[load][index], uindex ? "u" : "");
+  output_operands[0] = dest;
+  output_operands[1] = src;
+  output_asm_insn (format, output_operands);
+  return "";
+}
+
 /* 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.  */
@@ -831,24 +882,36 @@ th_output_move (rtx dest, rtx src)
 
   if (dest_code == REG && src_code == MEM)
     {
-      if (GET_MODE_CLASS (mode) == MODE_INT)
+      if (GET_MODE_CLASS (mode) == MODE_INT
+	  || (GET_MODE_CLASS (mode) == MODE_FLOAT && GP_REG_P (REGNO (dest))))
 	{
 	  if ((insn = th_memidx_output_index (dest, src, mode, true)))
 	    return insn;
 	  if ((insn = th_memidx_output_modify (dest, src, mode, true)))
 	    return insn;
 	}
+      else if (GET_MODE_CLASS (mode) == MODE_FLOAT && HARDFP_REG_P (REGNO (dest)))
+	{
+	  if ((insn = th_fmemidx_output_index (dest, src, mode, true)))
+	    return insn;
+	}
     }
   else if (dest_code == MEM && (src_code == REG || src == CONST0_RTX (mode)))
     {
       if (GET_MODE_CLASS (mode) == MODE_INT
-	  || src == CONST0_RTX (mode))
+	  || src == CONST0_RTX (mode)
+	  || (GET_MODE_CLASS (mode) == MODE_FLOAT && GP_REG_P (REGNO (src))))
 	{
 	  if ((insn = th_memidx_output_index (dest, src, mode, false)))
 	    return insn;
 	  if ((insn = th_memidx_output_modify (dest, src, mode, false)))
 	    return insn;
 	}
+      else if (GET_MODE_CLASS (mode) == MODE_FLOAT && HARDFP_REG_P (REGNO (src)))
+	{
+	  if ((insn = th_fmemidx_output_index (dest, src, mode, false)))
+	    return insn;
+	}
     }
   return NULL;
 }
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index dfcb6d926ec..2babfafb23c 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -587,15 +587,24 @@ (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>")])
 
+;; All modes that are supported by XTheadMemIdx
 (define_mode_iterator TH_M_ANYI [(QI "TARGET_XTHEADMEMIDX")
                                  (HI "TARGET_XTHEADMEMIDX")
                                  (SI "TARGET_XTHEADMEMIDX")
                                  (DI "TARGET_64BIT && TARGET_XTHEADMEMIDX")])
 
+;; All modes that are supported by XTheadFMemIdx
+(define_mode_iterator TH_M_ANYF [(SF "TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX")
+                                 (DF "TARGET_DOUBLE_FLOAT && TARGET_XTHEADFMEMIDX")])
+
 ;; All non-extension modes that are supported by XTheadMemIdx
 (define_mode_iterator TH_M_NOEXTI [(SI "!TARGET_64BIT && TARGET_XTHEADMEMIDX")
                                    (DI "TARGET_64BIT && TARGET_XTHEADMEMIDX")])
 
+;; All non-extension modes that are supported by XTheadFMemIdx
+(define_mode_iterator TH_M_NOEXTF [(SF "TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX")
+                                   (DF "TARGET_DOUBLE_FLOAT && TARGET_XTHEADFMEMIDX")])
+
 ;; XTheadMemIdx optimizations
 ;; All optimizations attempt to improve the operand utilization of
 ;; XTheadMemIdx instructions, where one sign or zero extended
@@ -812,4 +821,156 @@ (define_insn_and_split "*th_memidx_UZ_c"
         (match_dup 0))]
 )
 
+;; 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")])
+
+;; XTheadFMemIdx optimizations
+;; Similar like XTheadMemIdx optimizations, but less cases.
+;; Note, that we might get GP registers in FP-mode (reg:DF a2)
+;; which cannot be handled by the XTheadFMemIdx instructions.
+;; This might even happend after register allocation.
+;; We could implement splitters that undo the combiner results
+;; if "after_reload && !HARDFP_REG_P (operands[0])", but this
+;; raises even more questions (e.g. split into what?).
+;; So let's solve this by simply requiring XTheadMemIdx
+;; which provides the necessary instructions to cover this case.
+
+(define_insn_and_split "*th_fmemidx_I_a"
+  [(set (match_operand:TH_M_NOEXTF 0 "register_operand" "=f")
+        (mem:TH_M_NOEXTF (plus:X
+          (mult:X (match_operand:X 1 "register_operand" "r")
+                  (match_operand:QI 2 "immediate_operand" "i"))
+          (match_operand:X 3 "register_operand" "r"))))]
+  "TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX
+   && CONST_INT_P (operands[2])
+   && pow2p_hwi (INTVAL (operands[2]))
+   && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+        (mem:TH_M_NOEXTF (plus:X
+          (match_dup 3)
+          (ashift:X (match_dup 1) (match_dup 2)))))]
+  { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2])));
+  }
+)
+
+(define_insn_and_split "*th_fmemidx_I_c"
+  [(set (mem:TH_M_ANYF (plus:X
+          (mult:X (match_operand:X 1 "register_operand" "r")
+                  (match_operand:QI 2 "immediate_operand" "i"))
+          (match_operand:X 3 "register_operand" "r")))
+        (match_operand:TH_M_ANYF 0 "register_operand" "f"))]
+  "TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX
+   && CONST_INT_P (operands[2])
+   && pow2p_hwi (INTVAL (operands[2]))
+   && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)"
+  "#"
+  "&& 1"
+  [(set (mem:TH_M_ANYF (plus:X
+          (match_dup 3)
+          (ashift:X (match_dup 1) (match_dup 2))))
+        (match_dup 0))]
+  { operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2])));
+  }
+)
+
+(define_insn_and_split "*th_fmemidx_US_a"
+  [(set (match_operand:TH_M_NOEXTF 0 "register_operand" "=f")
+        (mem:TH_M_NOEXTF (plus:DI
+          (and:DI
+            (mult:DI (match_operand:DI 1 "register_operand" "r")
+                     (match_operand:QI 2 "immediate_operand" "i"))
+            (match_operand:DI 3 "immediate_operand" "i"))
+          (match_operand:DI 4 "register_operand" "r"))))]
+  "TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX
+   && CONST_INT_P (operands[2])
+   && pow2p_hwi (INTVAL (operands[2]))
+   && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)
+   && CONST_INT_P (operands[3])
+   && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+        (mem:TH_M_NOEXTF (plus:DI
+          (match_dup 4)
+          (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))))]
+  { operands[1] = gen_lowpart (SImode, operands[1]);
+    operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2])));
+  }
+)
+
+(define_insn_and_split "*th_fmemidx_US_c"
+  [(set (mem:TH_M_ANYF (plus:DI
+          (and:DI
+            (mult:DI (match_operand:DI 1 "register_operand" "r")
+                     (match_operand:QI 2 "immediate_operand" "i"))
+            (match_operand:DI 3 "immediate_operand" "i"))
+          (match_operand:DI 4 "register_operand" "r")))
+        (match_operand:TH_M_ANYF 0 "register_operand" "f"))]
+  "TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX
+   && CONST_INT_P (operands[2])
+   && pow2p_hwi (INTVAL (operands[2]))
+   && IN_RANGE (exact_log2 (INTVAL (operands[2])), 1, 3)
+   && CONST_INT_P (operands[3])
+   && (INTVAL (operands[3]) >> exact_log2 (INTVAL (operands[2]))) == 0xffffffff"
+  "#"
+  "&& 1"
+  [(set (mem:TH_M_ANYF (plus:DI
+          (match_dup 4)
+          (ashift:DI (zero_extend:DI (match_dup 1)) (match_dup 2))))
+        (match_dup 0))]
+  { operands[1] = gen_lowpart (SImode, operands[1]);
+    operands[2] = GEN_INT (exact_log2 (INTVAL (operands [2])));
+  }
+)
+
+(define_insn_and_split "*th_fmemidx_UZ_a"
+  [(set (match_operand:TH_M_NOEXTF 0 "register_operand" "=f")
+        (mem:TH_M_NOEXTF (plus:DI
+          (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+          (match_operand:DI 2 "register_operand" "r"))))]
+  "TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX
+   && (!HARD_REGISTER_NUM_P (REGNO (operands[0])) || HARDFP_REG_P (REGNO (operands[0])))"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+        (mem:TH_M_NOEXTF (plus:DI
+          (match_dup 2)
+          (zero_extend:DI (match_dup 1)))))]
+)
+
+(define_insn_and_split "*th_fmemidx_UZ_c"
+  [(set (mem:TH_M_ANYF (plus:DI
+          (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+          (match_operand:DI 2 "register_operand" "r")))
+        (match_operand:TH_M_ANYF 0 "register_operand" "f"))]
+  "TARGET_64BIT && TARGET_XTHEADMEMIDX && TARGET_XTHEADFMEMIDX"
+  "#"
+  "&& 1"
+  [(set (mem:TH_M_ANYF (plus:DI
+          (match_dup 2)
+          (zero_extend:DI (match_dup 1))))
+        (match_dup 0))]
+)
+
 (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..24bbb63d174
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LR_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+LR_REG_IMM_UPD(double, 2)
+#endif
+
+SR_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+SR_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times {\mslli\M} 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times {\mslli\M} 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..3b931a4b980
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LR_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+LR_REG_IMM_UPD(double, 2)
+#endif
+
+SR_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+SR_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times {\mslli\M} 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times {\mslli\M} 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..48858605c24
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LR_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times {\mth\.flrw\t[^\n\r]*0\M} 1 } } */
+#if __riscv_xlen == 64
+LR_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times {\mth\.flrd\t[^\n\r]*2\M} 1 { target { rv64 } } } } */
+#endif
+
+SR_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times {\mth\.fsrw\t[^\n\r]*1\M} 1 } } */
+#if __riscv_xlen == 64
+SR_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times {\mth\.fsrd\t[^\n\r]*3\M} 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..1bb231a9e88
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LR_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times {\mth\.flrw\t[^\n\r]*0\M} 1 } } */
+#if __riscv_xlen == 64
+LR_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times {\mth\.flrd\t[^\n\r]*2\M} 1 { target { rv64 } } } } */
+#endif
+
+SR_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times {\mth\.fsrw\t[^\n\r]*1\M} 1 } } */
+#if __riscv_xlen == 64
+SR_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times {\mth\.fsrd\t[^\n\r]*3\M} 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not {\mslli\M} } } */
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..bc50fa799e0
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LRU_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+LRU_REG_IMM_UPD(double, 2)
+#endif
+
+SRU_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+SRU_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times {\mslli\M} 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times {\mslli\M} 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..242be7af4a4
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LRU_REG_IMM_UPD(float, 0)
+#if __riscv_xlen == 64
+LRU_REG_IMM_UPD(double, 2)
+#endif
+
+SRU_REG_IMM_UPD(float, 1)
+#if __riscv_xlen == 64
+SRU_REG_IMM_UPD(double, 3)
+#endif
+
+/* If the shifted value is used later, we cannot eliminate it.  */
+/* { dg-final { scan-assembler-times {\mslli\M} 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times {\mslli\M} 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..e2a4f36796f
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadbb_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LRU_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times {\mth\.flurw\t[^\n\r]*0\M} 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times {\mth\.flrw\t[^\n\r]*0\M} 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+LRU_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times {\mth\.flurd\t[^\n\r]*2\M} 1 { target { rv64 } } } } */
+#endif
+
+SRU_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times {\mth\.fsurw\t[^\n\r]*1\M} 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times {\mth\.fsrw\t[^\n\r]*1\M} 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+SRU_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times {\mth\.fsurd\t[^\n\r]*3\M} 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not {\mslli\M} } } */
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..32783ebed03
--- /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_xtheadmemidx_xtheadfmemidx" { target { rv64 } } } */
+/* { dg-options "-march=rv32imafc_xtheadmemidx_xtheadfmemidx -mabi=ilp32f" { target { rv32 } } } */
+
+#include "xtheadmemidx-helpers.h"
+
+LRU_REG_IMM(float, 0)
+/* { dg-final { scan-assembler-times {\mth\.flurw\t[^\n\r]*0\M} 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times {\mth\.flrw\t[^\n\r]*0\M} 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+LRU_REG_IMM(double, 2)
+/* { dg-final { scan-assembler-times {\mth\.flurd\t[^\n\r]*2\M} 1 { target { rv64 } } } } */
+#endif
+
+SRU_REG_IMM(float, 1)
+/* { dg-final { scan-assembler-times {\mth\.fsurw\t[^\n\r]*1\M} 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times {\mth\.fsrw\t[^\n\r]*1\M} 1 { target { rv32 } } } } */
+#if __riscv_xlen == 64
+SRU_REG_IMM(double, 3)
+/* { dg-final { scan-assembler-times {\mth\.fsurd\t[^\n\r]*3\M} 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-not {\mslli\M} } } */
+
