diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index a007cf0b4f5..711268d05f6 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -202,3 +202,10 @@ (define_memory_constraint "Qmu"
   (and (match_code "mem")
        (match_test "riscv_legitimize_address_index_p (
 		    XEXP (op, 0), GET_MODE (op), true)")))
+
+(define_memory_constraint "Qmx"
+  "@internal
+   An address valid for GPR."
+  (and (match_code "mem")
+       (match_test "!riscv_legitimize_address_index_p (
+		    XEXP (op, 0), GET_MODE (op), false)")))
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 019a0e08285..ba53bf710d7 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -77,6 +77,8 @@ extern const char *
 riscv_output_move_index (rtx x, machine_mode mode, bool ldr);
 extern const char *
 riscv_output_move_modify (rtx x, machine_mode mode, bool ldi);
+extern const char *
+riscv_output_move_index_float (rtx x, machine_mode mode, bool ldr);
 
 extern bool
 riscv_legitimize_address_index_p (rtx x, machine_mode mode, bool uindex);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 2980dbd69f9..caa30eed8d6 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1316,7 +1316,7 @@ riscv_classify_address_index (struct riscv_address_info *info, rtx x,
   rtx index;
   int shift = 0;
 
-  if (!TARGET_XTHEADMEMIDX)
+  if (!(TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX))
     return false;
 
   if (!TARGET_64BIT && mode == DImode)
@@ -1326,6 +1326,8 @@ riscv_classify_address_index (struct riscv_address_info *info, rtx x,
     {
       if (!TARGET_HARD_FLOAT)
 	return false;
+      if (!(TARGET_HARD_FLOAT && TARGET_XTHEADFMEMIDX))
+	return false;
       if (GET_MODE_SIZE (mode).to_constant () == 2)
 	return false;
     }
@@ -1422,7 +1424,7 @@ riscv_classify_address_modify (struct riscv_address_info *info, rtx x,
   ? (SHIFT) + 1 \
   : 0)
 
-  if (!TARGET_XTHEADMEMIDX)
+  if (!(TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX))
     return false;
 
   if (!(INTEGRAL_MODE_P (mode) && GET_MODE_SIZE (mode).to_constant () <= 8))
@@ -1562,6 +1564,42 @@ riscv_output_move_index (rtx x, machine_mode mode, bool ldr)
   return buf;
 }
 
+const char *
+riscv_output_move_index_float (rtx x, machine_mode mode, bool ldr)
+{
+  static char buf[128] = {0};
+
+  int index = exact_log2 (GET_MODE_SIZE (mode).to_constant ());
+  if (!IN_RANGE (index, 2, 3))
+    return NULL;
+
+  if (!riscv_legitimize_address_index_p (x, mode, false))
+    return NULL;
+
+  bool uindex = riscv_legitimize_address_index_p (x, mode, true);
+
+  /* Not using index, 0, 1, as they are not implemented
+     for xtheadfmemidx yet.  */
+  const char *const insn[][4] = {
+    {
+      "th.fs%srb\t%%z1,%%0",
+      "th.fs%srh\t%%z1,%%0",
+      "th.fs%srw\t%%z1,%%0",
+      "th.fs%srd\t%%z1,%%0"
+    },
+    {
+      "th.fl%srb\t%%0,%%1",
+      "th.fl%srh\t%%0,%%1",
+      "th.fl%srw\t%%0,%%1",
+      "th.fl%srd\t%%0,%%1"
+    }
+  };
+
+  snprintf (buf, sizeof (buf), insn[ldr][index], uindex ? "u" : "");
+
+  return buf;
+}
+
 /* Emit an instruction of the form (set TARGET SRC).  */
 
 static rtx
@@ -2739,7 +2777,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	}
       /* bit extraction pattern (xtheadmemidx, xtheadfmemidx).  */
       if (outer_code == SET
-	  && TARGET_XTHEADMEMIDX)
+	  && (TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX))
 	{
 	  *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
 	  return true;
@@ -3071,6 +3109,20 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
   if (TARGET_64BIT)
     return false;
 
+  if (TARGET_XTHEADFMEMIDX)
+    {
+      if (MEM_P (src) && SCALAR_FLOAT_MODE_P (GET_MODE (src))
+	  && riscv_legitimize_address_index_p (XEXP (src, 0),
+					       GET_MODE (src), false)
+	  && FP_REG_RTX_P (dest))
+	return false;
+      if (MEM_P (dest) && SCALAR_FLOAT_MODE_P (GET_MODE (dest))
+	  && riscv_legitimize_address_index_p (XEXP (dest, 0),
+					       GET_MODE (dest), false)
+	  && FP_REG_RTX_P (src))
+	return false;
+    }
+
   /* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case
      of zeroing an FPR with FCVT.D.W.  */
   if (TARGET_DOUBLE_FLOAT
@@ -3269,6 +3321,12 @@ riscv_output_move (rtx dest, rtx src)
 
       if (dest_code == MEM)
 	{
+	  const char *insn = NULL;
+	  insn = riscv_output_move_index_float (XEXP (dest, 0),
+						GET_MODE (dest), false);
+	  if (insn)
+	    return insn;
+
 	  switch (width)
 	    {
 	    case 2:
@@ -3284,6 +3342,12 @@ riscv_output_move (rtx dest, rtx src)
     {
       if (src_code == MEM)
 	{
+	  const char *insn = NULL;
+	  insn = riscv_output_move_index_float (XEXP (src, 0),
+						GET_MODE (src), true);
+	  if (insn)
+	    return insn;
+
 	  switch (width)
 	    {
 	    case 2:
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 199bb30162e..13764d60257 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -535,7 +535,7 @@ enum reg_class
    factor or added to another register (as well as added to a
    displacement).  */
 
-#define INDEX_REG_CLASS ((TARGET_XTHEADMEMIDX) ? \
+#define INDEX_REG_CLASS ((TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX) ? \
 			GR_REGS : NO_REGS)
 
 /* We generally want to put call-clobbered registers ahead of
@@ -707,7 +707,7 @@ typedef struct {
 /* Addressing modes, and classification of registers for them.  */
 
 #define REGNO_OK_FOR_INDEX_P(REGNO) \
-  ((TARGET_XTHEADMEMIDX) ? \
+  ((TARGET_XTHEADMEMIDX || TARGET_XTHEADFMEMIDX) ? \
   riscv_regno_mode_ok_for_base_p (REGNO, VOIDmode, 1) : 0)
 
 #define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index df31a1fffff..9d0207b8d6f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1866,6 +1866,20 @@ (define_insn "*movsf_hardfloat"
 	     "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "SF")])
 
+(define_insn "*movsf_hardfloat"
+  [(set (match_operand:SF 0
+	"nonimmediate_operand" "=f,f,f,m,Qmx,*f,*r,  *r,*r,*Qmx")
+	(match_operand:SF 1
+	"move_operand" " f,G,m,f,G,*r,*f,*G*r,*Qmx,*r"))]
+  "!TARGET_64BIT
+   && 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"
+	      "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+   (set_attr "mode" "SF")])
+
 (define_insn "*movsf_softfloat"
   [(set (match_operand:SF 0 "nonimmediate_operand" "= r,r,m")
 	(match_operand:SF 1 "move_operand"         " Gr,m,r"))]
@@ -1900,6 +1914,20 @@ (define_insn "*movdf_hardfloat_rv32"
 	     "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
+(define_insn "*movdf_hardfloat_rv32"
+  [(set (match_operand:DF 0
+	"nonimmediate_operand" "=f,f,f,m,Qmx,  *r,*r,*Qmx")
+	(match_operand:DF 1
+	"move_operand" " f,G,m,f,G,*r*G,*Qmx,*r"))]
+  "!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"
+	     "fmove,mtc,fpload,fpstore,store,move,load,store")
+   (set_attr "mode" "DF")])
+
 (define_insn "*movdf_hardfloat_rv64"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
 	(match_operand:DF 1 "move_operand"         " f,G,m,f,G,*r,*f,*r*G,*m,*r"))]
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-fldr-fstr.c b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-fldr-fstr.c
new file mode 100644
index 00000000000..006038ce3c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmemidx-fldr-fstr.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-g" "-Oz" "-Os"} } */
+/* { dg-options "-march=rv64gc_xtheadfmemidx --save-temps -O2" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_xtheadfmemidx --save-temps -O2" { target { rv32 } } } */
+
+float func_f(float *a, int b)
+{
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.flrw" } } */
+
+double func_d(double *a, int b)
+{
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.flrd" } } */
+
+float func_sf(float *a, int b, float c)
+{
+    a[b] = c;
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.fsrw" } } */
+
+double func_sd(double *a, int b, double c)
+{
+    a[b] = c;
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.fsrd" } } */
+
+float func_uf(float *a, unsigned int b)
+{
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.flurw" { target { rv64 } } } } */
+
+double func_ud(double *a, unsigned int b)
+{
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.flurd" { target { rv64 } } } } */
+
+float func_usf(float *a, unsigned int b, float c)
+{
+    a[b] = c;
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.fsurw" { target { rv64 } } } } */
+
+double func_usd(double *a, unsigned int b, double c)
+{
+    a[b] = c;
+    return a[b];
+}
+/* { dg-final { scan-assembler "th.fsurd" { target { rv64 } } } } */
+
+/* { dg-final { cleanup-saved-temps } } */
