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

Reply via email to