@@ -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;
@@ -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)
@@ -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;
}
@@ -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")
new file mode 100644
@@ -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 } } } } */
new file mode 100644
@@ -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 } } } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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 } } } } */
new file mode 100644
@@ -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 } } } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
+
@@ -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 */