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

Message ID 20230224055127.2500953-12-christoph.muellner@vrull.eu
State Committed
Headers
Series RISC-V: Add XThead* extension support |

Commit Message

Christoph Müllner Feb. 24, 2023, 5:51 a.m. UTC
  From: "moiz.hussain" <muhammad.hussain@vrull.eu>

The XTheadFMemIdx ISA extension provides register-indexed
addressing modes to floating-point load and store instructions.

gcc/ChangeLog:

	* config/riscv/constraints.md (Qmx): New constraint.
	* config/riscv/riscv-protos.h (riscv_output_move_index_float):
	New prototyp.
	* config/riscv/riscv.cc (riscv_classify_address_index): Adjust
	for XTheadFMemIdx.
	(riscv_classify_address_modify): Likewise.
	(riscv_output_move_index_float): New function.
	(riscv_rtx_costs): Adjust for XTheadFMemIdx.
	(riscv_split_64bit_move_p): Likewise.
	(riscv_output_move): Likewise.
	* config/riscv/riscv.h (INDEX_REG_CLASS): Likewise.
	(REGNO_OK_FOR_INDEX_P): Likewise.
	* config/riscv/riscv.md (*movsf_hardfloat): New pattern.
	(*movdf_hardfloat_rv32): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadfmemidx-fldr-fstr.c: New test.

Signed-off-by: M. Moiz Hussain <muhammad.hussain@vrull.eu>
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/constraints.md               |  7 ++
 gcc/config/riscv/riscv-protos.h               |  2 +
 gcc/config/riscv/riscv.cc                     | 70 ++++++++++++++++++-
 gcc/config/riscv/riscv.h                      |  4 +-
 gcc/config/riscv/riscv.md                     | 28 ++++++++
 .../riscv/xtheadfmemidx-fldr-fstr.c           | 58 +++++++++++++++
 6 files changed, 164 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmemidx-fldr-fstr.c
  

Comments

Kito Cheng Feb. 24, 2023, 7:53 a.m. UTC | #1
> +
> +(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)")))

Check TARGET_XTHEADFMEMIDX, and I don't quite understand why it
comes with `!` for the riscv_legitimize_address_index_p,
but saying it's an address valid for GPR?

According to the comment it sounds like (mem (reg)) but seems like not?


> 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")])
> +

Plz move to thead.md and named with prefix *th

>  (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")])
> +

Ditto
  
Kito Cheng Feb. 24, 2023, 9:46 a.m. UTC | #2
> > +(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)")))
>
> Check TARGET_XTHEADFMEMIDX, and I don't quite understand why it

I changed my mind, don't check TARGET_XTHEADFMEMIDX here,
check ext in the pattern instead.
  

Patch

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 } } */