Recognize ADD, ADDW, or ADD.UW followed by an undisplaced scalar
integer store that uses the add result as its address. Keep the
store-data constraint separate from the common add-memory matcher.
Leave the fusion disabled by default.
gcc/ChangeLog:
* config/riscv/riscv-fusion.cc (riscv_fuse_add_st): New function.
(riscv_fusion_table): Add RISCV_FUSE_ADD_ST.
* config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add
RISCV_FUSE_ADD_ST.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/fusion-add-st.c: New test.
* gcc.target/riscv/fusion-addw-adduw-st.c: Likewise.
Signed-off-by: Jin Ma <[email protected]>
---
gcc/config/riscv/riscv-fusion.cc | 29 ++++++++
gcc/config/riscv/riscv-protos.h | 1 +
.../gcc.target/riscv/fusion-add-st.c | 13 ++++
.../gcc.target/riscv/fusion-addw-adduw-st.c | 67 +++++++++++++++++++
4 files changed, 110 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-add-st.c
create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-st.c
diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index 840bad47002..bb4076e9ffc 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -773,6 +773,33 @@ riscv_fuse_ldindexed (rtx_insn *prev, rtx_insn *curr)
&& mem.type != SCHED_FUSION_ST);
}
+/* Check for RISCV_FUSE_ADD_ST fusion.
+ prev (one of the following):
+ (add) == (set (reg rd1) (plus (reg rs1) (reg rs2)))
+ (addw) == (set (reg rd1) (sign_extend (plus:SI (reg rs1)
+ (reg rs2))))
+ (add.uw) == (set (reg rd1) (plus (zero_extend (reg rs1))
+ (reg rs2)))
+ curr (one of the following):
+ (store) == (set (mem (rd1, offset)) (reg rs3))
+ (store) == (set (mem (rd1, offset)) (const_int 0))
+
+ Constraints:
+ rd1 != rs3 for a register-source store
+ offset == 0. */
+
+static bool
+riscv_fuse_add_st (rtx_insn *prev, rtx_insn *curr)
+{
+ rtx add_set, mem_set;
+ struct riscv_fusion_mem_info mem;
+
+ return (riscv_fuse_add_mem_p (prev, curr, &add_set, &mem_set, &mem)
+ && mem.type == SCHED_FUSION_ST
+ && !riscv_fuse_same_reg_p (SET_DEST (add_set),
+ SET_SRC (mem_set)));
+}
+
/* Check for RISCV_FUSE_EXPANDED_LD fusion.
prev (one of the following):
(add) == (set (reg rd1) (plus (reg rs1) (reg rs2)))
@@ -1211,6 +1238,8 @@ static const struct riscv_fusion_entry
riscv_fusion_table[] =
riscv_fuse_zexth, "RISCV_FUSE_ZEXTH" },
{ RISCV_FUSE_LDINDEXED,
riscv_fuse_ldindexed, "RISCV_FUSE_LDINDEXED" },
+ { RISCV_FUSE_ADD_ST,
+ riscv_fuse_add_st, "RISCV_FUSE_ADD_ST" },
{ RISCV_FUSE_EXPANDED_LD,
riscv_fuse_expanded_ld, "RISCV_FUSE_EXPANDED_LD" },
{ RISCV_FUSE_LDPREINCREMENT,
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 20781e14313..0bd26523a98 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -867,6 +867,7 @@ enum riscv_fusion_pairs
RISCV_FUSE_EXPANDED_LD = HOST_WIDE_INT_1U << 11,
RISCV_FUSE_B_ALUI = HOST_WIDE_INT_1U << 12,
RISCV_FUSE_SUB_SEQZ = HOST_WIDE_INT_1U << 13,
+ RISCV_FUSE_ADD_ST = HOST_WIDE_INT_1U << 14,
};
extern bool riscv_macro_fusion_p (void);
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-add-st.c
b/gcc/testsuite/gcc.target/riscv/fusion-add-st.c
new file mode 100644
index 00000000000..e0cebe27972
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-add-st.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64g -mabi=lp64d -mtune=xt-c9501fdvt -O2
-fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_ADD_ST" 1 "sched2" { xfail
*-*-* } } } */
+
+typedef long int64_t;
+
+/* add + sd should fuse. */
+void
+test_add_sd (int64_t *base, long off, int64_t v)
+{
+ *(int64_t *) ((char *) base + off) = v;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-st.c
b/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-st.c
new file mode 100644
index 00000000000..19989e0b902
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-st.c
@@ -0,0 +1,67 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64gc_zba -mabi=lp64d -mtune=xt-c9501fdvt -O2
-fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_ADD_ST" 2 "sched2" { xfail
*-*-* } } } */
+
+/* addw + sd should fuse. */
+long __RTL (startwith ("sched2"))
+test_addw_sd (void)
+{
+(function "test_addw_sd"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ ;; addw a0, a1, a2
+ (cinsn 3 (set (reg:DI a0)
+ (sign_extend:DI
+ (plus:SI (reg:SI a1)
+ (reg:SI a2)))))
+ ;; sd a3, 0(a0)
+ (cinsn 4 (set (mem:DI (reg:DI a0) [0 S8 A64])
+ (reg:DI a3)))
+ (cinsn 5 (use (reg/i:DI a0)))
+ (cjump_insn 6 (simple_return))
+ (edge-to exit)
+ ) ;; block 2
+ (cbarrier 7)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:DI a0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_addw_sd"
+}
+
+/* add.uw + sd should fuse. */
+long __RTL (startwith ("sched2"))
+test_adduw_sd (void)
+{
+(function "test_adduw_sd"
+ (insn-chain
+ (block 2
+ (edge-from entry (flags "FALLTHRU"))
+ (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+ (cnote 2 NOTE_INSN_FUNCTION_BEG)
+ ;; add.uw a0, a1, a2
+ (cinsn 3 (set (reg:DI a0)
+ (plus:DI (zero_extend:DI (reg:SI a1))
+ (reg:DI a2))))
+ ;; sd a3, 0(a0)
+ (cinsn 4 (set (mem:DI (reg:DI a0) [0 S8 A64])
+ (reg:DI a3)))
+ (cinsn 5 (use (reg/i:DI a0)))
+ (cjump_insn 6 (simple_return))
+ (edge-to exit)
+ ) ;; block 2
+ (cbarrier 7)
+ ) ;; insn-chain
+ (crtl
+ (return_rtx
+ (reg/i:DI a0)
+ ) ;; return_rtx
+ ) ;; crtl
+) ;; function "test_adduw_sd"
+}
--
2.52.0