Recognize a scalar integer or floating-point load followed by a
non-word ADDI-type in-place update of its base register.  Reuse the
indexed-memory helper shared with the pre-index rules and accept either
load-destination relationship.

Leave the fusion disabled by default and XFAIL its positive dump
checks until a CPU enables it.

gcc/ChangeLog:

        * config/riscv/riscv-fusion.cc (riscv_fuse_postindex_ld): New
        function.
        (riscv_fusion_table): Add RISCV_FUSE_POSTINDEX_LD.
        * config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add
        RISCV_FUSE_POSTINDEX_LD.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/fusion-load-dest-equal-rtl-postindex.c: New test.
        * gcc.target/riscv/fusion-postindex-ldst.c: Likewise.

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 24 +++++++++++++
 gcc/config/riscv/riscv-protos.h               |  1 +
 .../fusion-load-dest-equal-rtl-postindex.c    | 34 +++++++++++++++++++
 .../gcc.target/riscv/fusion-postindex-ldst.c  | 34 +++++++++++++++++++
 4 files changed, 93 insertions(+)
 create mode 100644 
gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-postindex.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-postindex-ldst.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index b8d3c6d7fa6..0d9870d4b1e 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -1217,6 +1217,28 @@ riscv_fuse_preindex_st (rtx_insn *prev, rtx_insn *curr)
   return riscv_fuse_indexed_mem_p (prev, curr, false, true);
 }
 
+/* Check for RISCV_FUSE_POSTINDEX_LD fusion.
+   prev (one of the following):
+     (load) == (set (reg rd1) (mem addr))
+     (load) == (set (reg rd1) (any_extend (mem addr)))
+     (fpload) == (set (reg frd) (mem addr))
+   addr (one of the following):
+     (rd2, offset)
+     (lo_sum (reg rd2) symbol1)
+   curr (one of the following):
+     (addi) == (set (reg rd2) (plus (reg rd2) (const_int imm12)))
+     (self-mv) == (set (reg rd2) (reg rd2))
+     (addi) == (set (reg rd2) (lo_sum (reg rd2) symbol2))
+
+   Constraints:
+     the ADDI-type instruction is not a word form.  */
+
+static bool
+riscv_fuse_postindex_ld (rtx_insn *prev, rtx_insn *curr)
+{
+  return riscv_fuse_indexed_mem_p (prev, curr, true, false);
+}
+
 /* Check for RISCV_FUSE_LUI_ADDI fusion.
    prev (one of the following):
      (lui) == (set (reg rd1) (const_int imm20))
@@ -1738,6 +1760,8 @@ static const struct riscv_fusion_entry 
riscv_fusion_table[] =
     riscv_fuse_ldpreincrement, "RISCV_FUSE_LDPREINCREMENT" },
   { RISCV_FUSE_PREINDEX_ST,
     riscv_fuse_preindex_st, "RISCV_FUSE_PREINDEX_ST" },
+  { RISCV_FUSE_POSTINDEX_LD,
+    riscv_fuse_postindex_ld, "RISCV_FUSE_POSTINDEX_LD" },
   { RISCV_FUSE_LUI_ADDI,
     riscv_fuse_lui_addi, "RISCV_FUSE_LUI_ADDI" },
   { RISCV_FUSE_AUIPC_ADDI,
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index a40c7d56233..557c8db9111 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -874,6 +874,7 @@ enum riscv_fusion_pairs
   RISCV_FUSE_SLLI_SRLI = HOST_WIDE_INT_1U << 18,
   RISCV_FUSE_SRLI_ADD = HOST_WIDE_INT_1U << 19,
   RISCV_FUSE_PREINDEX_ST = HOST_WIDE_INT_1U << 20,
+  RISCV_FUSE_POSTINDEX_LD = HOST_WIDE_INT_1U << 21,
 };
 
 extern bool riscv_macro_fusion_p (void);
diff --git 
a/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-postindex.c 
b/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-postindex.c
new file mode 100644
index 00000000000..72eb79e1ad9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-postindex.c
@@ -0,0 +1,34 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O2 -mtune=xt-c9501fdvt 
-fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_POSTINDEX_LD" 1 "sched2" { 
xfail *-*-* } } } */
+
+/* An unsigned load and update writing the same register should fuse.  */
+long __RTL (startwith ("sched2"))
+test_postindex_load_same_destination (void)
+{
+(function "test_postindex_load_same_destination"
+  (insn-chain
+    (block 2
+      (edge-from entry (flags "FALLTHRU"))
+      (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (cnote 2 NOTE_INSN_FUNCTION_BEG)
+      (cinsn 3 (set (reg:DI a0)
+                    (zero_extend:DI
+                      (mem:QI (reg:DI a0) [0 S1 A8]))))
+      (cinsn 4 (set (reg:DI a0)
+                    (plus:DI (reg:DI a0)
+                             (const_int 1))))
+      (cinsn 5 (use (reg: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_postindex_load_same_destination"
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-postindex-ldst.c 
b/gcc/testsuite/gcc.target/riscv/fusion-postindex-ldst.c
new file mode 100644
index 00000000000..6e45da46a95
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-postindex-ldst.c
@@ -0,0 +1,34 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-funroll-loops" 
"-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=xt-c9501fdvt -O2 
-fno-tree-vectorize -fno-unroll-loops -fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_POSTINDEX_LD" 2 "sched2" { 
xfail *-*-* } } } */
+
+typedef signed char int8_t;
+
+extern void use_ptr (void *);
+
+int8_t
+post_lb (int8_t *src, int n)
+{
+  int8_t sum = 0;
+  for (int i = 0; i < n; ++i)
+    {
+      sum += *src;
+      ++src;
+    }
+  use_ptr (src);
+  return sum;
+}
+
+double
+post_fld (double *src, int n)
+{
+  double sum = 0;
+  for (int i = 0; i < n; ++i)
+    {
+      sum += *src;
+      ++src;
+    }
+  use_ptr (src);
+  return sum;
+}
-- 
2.52.0

Reply via email to