[v3,11/11] riscv: thead: Add support for the XTheadFMemIdx ISA extension
Checks
Commit Message
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
> +
> +(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
> > +(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.
@@ -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)")))
@@ -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);
@@ -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:
@@ -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) \
@@ -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"))]
new file mode 100644
@@ -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 } } */