Recognize the descending-address counterpart of the integer
load/store pair fusion.  Reuse the common pair matcher and select the
reversed one-access-size offset 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_ldst_pair_dec): New
        function.
        (riscv_fusion_table): Add RISCV_FUSE_LDST_PAIR_DEC.
        * config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add
        RISCV_FUSE_LDST_PAIR_DEC.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/fusion-ldst-pair-dec.c: New test.

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 22 +++++++++++++
 gcc/config/riscv/riscv-protos.h               |  1 +
 .../gcc.target/riscv/fusion-ldst-pair-dec.c   | 33 +++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-ldst-pair-dec.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index 419628a5038..e150b53c63b 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -1533,6 +1533,26 @@ riscv_fuse_ldst_pair_inc (rtx_insn *prev, rtx_insn *curr)
   return riscv_fuse_ldst_pair_p (prev, curr, true, false);
 }
 
+/* Check for RISCV_FUSE_LDST_PAIR_DEC fusion.
+   prev/curr (one of the following pairs):
+     prev (lw/ld) == (set (reg rd1) (mem (rs1, offset1)))
+     curr (lw/ld) == (set (reg rd2) (mem (rs1, offset2)))
+
+     prev (sw/sd) == (set (mem (rs1, offset1)) (reg rs2))
+     curr (sw/sd) == (set (mem (rs1, offset2)) (reg rs3))
+
+   Constraints:
+     access size is 4 or 8 bytes
+     offset1 - offset2 equals the access size
+     loads are not zero-extending
+     for loads, rd1 != rd2 and rd1 != rs1.  */
+
+static bool
+riscv_fuse_ldst_pair_dec (rtx_insn *prev, rtx_insn *curr)
+{
+  return riscv_fuse_ldst_pair_p (prev, curr, false, false);
+}
+
 /* Check for RISCV_FUSE_BFEXT fusion.
    prev (slli) == (set (reg rd1)
                       (ashift (reg rs1) (const_int shamt1)))
@@ -1878,6 +1898,8 @@ static const struct riscv_fusion_entry 
riscv_fusion_table[] =
     riscv_fuse_aligned_std, "RISCV_FUSE_ALIGNED_STD" },
   { RISCV_FUSE_LDST_PAIR_INC,
     riscv_fuse_ldst_pair_inc, "RISCV_FUSE_LDST_PAIR_INC" },
+  { RISCV_FUSE_LDST_PAIR_DEC,
+    riscv_fuse_ldst_pair_dec, "RISCV_FUSE_LDST_PAIR_DEC" },
   { RISCV_FUSE_BFEXT,
     riscv_fuse_bfext, "RISCV_FUSE_BFEXT" },
   { RISCV_FUSE_SLLI_SRLI,
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index de4476a2d66..3a14108ef19 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -877,6 +877,7 @@ enum riscv_fusion_pairs
   RISCV_FUSE_POSTINDEX_LD = HOST_WIDE_INT_1U << 21,
   RISCV_FUSE_POSTINDEX_ST = HOST_WIDE_INT_1U << 22,
   RISCV_FUSE_LDST_PAIR_INC = HOST_WIDE_INT_1U << 23,
+  RISCV_FUSE_LDST_PAIR_DEC = HOST_WIDE_INT_1U << 24,
 };
 
 extern bool riscv_macro_fusion_p (void);
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-ldst-pair-dec.c 
b/gcc/testsuite/gcc.target/riscv/fusion-ldst-pair-dec.c
new file mode 100644
index 00000000000..1a9373cd2d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-ldst-pair-dec.c
@@ -0,0 +1,33 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=xt-c9501fdvt -O2 
-fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDST_PAIR_DEC" 4 "sched2" { 
xfail *-*-* } } } */
+
+typedef int int32_t;
+typedef long int64_t;
+
+int64_t
+test_ld_pair_dec (int64_t *p)
+{
+  return p[1] + p[0];
+}
+
+int64_t
+test_lw_pair_dec (int32_t *p)
+{
+  return (int64_t) p[1] + p[0];
+}
+
+void
+test_sd_pair_dec (int64_t *p, int64_t a, int64_t b)
+{
+  p[1] = b;
+  p[0] = a;
+}
+
+void
+test_sw_pair_dec (int32_t *p, int32_t a, int32_t b)
+{
+  p[1] = b;
+  p[0] = a;
+}
-- 
2.52.0

Reply via email to