Allow LDPREINCREMENT to match non-word ADDI-type in-place address
updates followed by scalar integer or floating-point loads.  Support
register-plus-offset and LO_SUM addresses, self moves, and either
load-destination relationship.

Put the common pre/post-index load/store constraints in a
parameterized helper for later fusion rules.

gcc/ChangeLog:

        * config/riscv/riscv-fusion.cc (riscv_fuse_indexed_mem_p): New
        function.
        (riscv_fuse_ldpreincrement): Use it and accept scalar integer or
        floating-point loads.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/fusion-preindex-load.c: New test.
        * gcc.target/riscv/fusion-preindex-load-rtl.c: Likewise.

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 77 +++++++++++++------
 .../riscv/fusion-preindex-load-rtl.c          | 66 ++++++++++++++++
 .../gcc.target/riscv/fusion-preindex-load.c   | 31 ++++++++
 3 files changed, 149 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-preindex-load-rtl.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-preindex-load.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index c24fb29cbaf..c6e7073cb23 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -800,6 +800,45 @@ riscv_fuse_add_mem_p (rtx_insn *prev, rtx_insn *curr,
   return true;
 }
 
+/* Match an in-place ADDI-type address update and a scalar load or store using
+   the updated address.  LOAD_P selects loads rather than stores, and
+   PREINDEX_P selects whether the update precedes the memory instruction.  */
+
+static bool
+riscv_fuse_indexed_mem_p (rtx_insn *prev, rtx_insn *curr,
+                           bool load_p, bool preindex_p)
+{
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
+    return false;
+
+  rtx_insn *update_insn = preindex_p ? prev : curr;
+  rtx_insn *mem_insn = preindex_p ? curr : prev;
+  rtx update_set = preindex_p ? prev_set : curr_set;
+  rtx mem_set = preindex_p ? curr_set : prev_set;
+  rtx update_dest = SET_DEST (update_set);
+  rtx update_base = NULL_RTX;
+  struct riscv_fusion_mem_info mem;
+
+  if (!riscv_insn_is_addi_type_p (update_insn, false, &update_base)
+      || update_base == NULL_RTX
+      || !riscv_fuse_mem_p (mem_insn, &mem)
+      || (load_p
+         ? mem.type == SCHED_FUSION_ST
+         : mem.type != SCHED_FUSION_ST)
+      || !(mem.addr.type == ADDRESS_REG
+          || mem.addr.type == ADDRESS_LO_SUM)
+      || riscv_regno (update_dest) == INVALID_REGNUM
+      || !riscv_fuse_same_reg_p (update_base, update_dest)
+      || !riscv_fuse_same_reg_p (mem.addr.reg, update_dest))
+    return false;
+
+  if (load_p)
+    return true;
+
+  return !riscv_fuse_same_reg_p (SET_SRC (mem_set), update_dest);
+}
+
 /* Check the common RTL for ZEXTW, ZEXTWS and ZEXTH fusion.  */
 
 static bool
@@ -1134,37 +1173,25 @@ riscv_fuse_expanded_ld (rtx_insn *prev, rtx_insn *curr)
 }
 
 /* Check for RISCV_FUSE_LDPREINCREMENT fusion.
-   prev (addi) == (set (reg rd1)
-                      (plus (reg rd1) (const_int offset)))
-   curr (load) == (set (reg rd2) (mem (reg rd1)))
+   prev (one of the following):
+     (addi) == (set (reg rd1) (plus (reg rd1) (const_int imm12)))
+     (self-mv) == (set (reg rd1) (reg rd1))
+     (addi) == (set (reg rd1) (lo_sum (reg rd1) symbol1))
+   curr (one of the following):
+     (load) == (set (reg rd2) (mem addr))
+     (load) == (set (reg rd2) (any_extend (mem addr)))
+     (fpload) == (set (reg frd) (mem addr))
+   addr (one of the following):
+     (rd1, offset)
+     (lo_sum (reg rd1) symbol2)
 
    Constraints:
-     rd1 == rd2.  */
+     the ADDI-type instruction is not a word form.  */
 
 static bool
 riscv_fuse_ldpreincrement (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set, curr_set;
-  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
-    return false;
-
-  if (!riscv_fuse_same_dest_p (prev_set, curr_set))
-    return false;
-
-  struct riscv_fusion_mem_info mem;
-
-  if (riscv_fuse_mem_p (curr, &mem)
-      && mem.type == SCHED_FUSION_LD
-      && !mem.fp_p
-      && mem.addr.type == ADDRESS_REG
-      && INTVAL (mem.addr.offset) == 0
-      && riscv_set_is_addi_p (prev_set)
-      && riscv_fuse_same_reg_p (XEXP (SET_SRC (prev_set), 0),
-                                 SET_DEST (prev_set))
-      && riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
-    return true;
-
-  return false;
+  return riscv_fuse_indexed_mem_p (prev, curr, true, true);
 }
 
 /* Check for RISCV_FUSE_LUI_ADDI fusion.
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-preindex-load-rtl.c 
b/gcc/testsuite/gcc.target/riscv/fusion-preindex-load-rtl.c
new file mode 100644
index 00000000000..c8cceb4740a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-preindex-load-rtl.c
@@ -0,0 +1,66 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mexplicit-relocs -O2 
-mtune=xt-c9501fdvt -fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDPREINCREMENT" 2 "sched2" { 
xfail *-*-* } } } */
+
+extern double preindex_symbol;
+
+/* The load may write the address-update destination.  */
+long __RTL (startwith ("sched2"))
+test_preindex_same_destination (void)
+{
+(function "test_preindex_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)
+                    (plus:DI (reg:DI a0) (const_int 1))))
+      (cinsn 4 (set (reg:DI a0)
+                    (zero_extend:DI
+                      (mem:QI (reg:DI a0) [0 S1 A8]))))
+      (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))
+  ) ;; crtl
+) ;; function "test_preindex_same_destination"
+}
+
+/* LO_SUM updates and addresses are accepted for floating-point loads.  */
+long __RTL (startwith ("sched2"))
+test_preindex_lo_sum_fload (void)
+{
+(function "test_preindex_lo_sum_fload"
+  (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)
+                    (lo_sum:DI
+                      (reg:DI a0)
+                      (symbol_ref:DI ("preindex_symbol")))))
+      (cinsn 4 (set (reg:DF fa0)
+                    (mem:DF
+                      (lo_sum:DI
+                        (reg:DI a0)
+                        (symbol_ref:DI ("preindex_symbol")))
+                      [0 S8 A64])))
+      (cinsn 5 (use (reg:DI a0)))
+      (cinsn 6 (use (reg:DF fa0)))
+      (cjump_insn 7 (simple_return))
+      (edge-to exit)
+    ) ;; block 2
+    (cbarrier 8)
+  ) ;; insn-chain
+  (crtl
+    (return_rtx (reg/i:DI a0))
+  ) ;; crtl
+) ;; function "test_preindex_lo_sum_fload"
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-preindex-load.c 
b/gcc/testsuite/gcc.target/riscv/fusion-preindex-load.c
new file mode 100644
index 00000000000..6fd83652d55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-preindex-load.c
@@ -0,0 +1,31 @@
+/* { 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 
-fdump-rtl-sched2-details" } */
+/* No tune enables this fusion pair yet.  */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDPREINCREMENT" 2 "sched2" { 
xfail *-*-* } } } */
+
+typedef signed char int8_t;
+
+int8_t
+test_preindex_lb (int8_t *p, int n)
+{
+  int8_t sum = 0;
+  for (int i = 0; i < n; ++i)
+    {
+      p += 2;
+      sum += *p;
+    }
+  return sum;
+}
+
+double
+test_preindex_fld (double *p, int n)
+{
+  double sum = 0;
+  for (int i = 0; i < n; ++i)
+    {
+      p += 2;
+      sum += *p;
+    }
+  return sum;
+}
-- 
2.52.0

Reply via email to