[PATCH v5 04/18] RISC-V: Generalize LDINDEXED macro-fusion recognition

Jin Ma <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
Allow LDINDEXED to match ADD, ADDW, or ADD.UW followed by an
undisplaced scalar integer load.  The load may overwrite the computed
address or use a different destination.

Share the add-plus-memory structural matching with the following
ADD_ST fusion patch.

gcc/ChangeLog:

	* config/riscv/riscv-fusion.cc (riscv_set_is_addw_p): New function.
	(riscv_insn_is_add_type_p): Likewise.
	(riscv_fuse_add_mem_p): Likewise.
	(riscv_fuse_ldindexed): Use the common matcher and accept ADDW,
	ADD.UW, and either load-destination relationship.

gcc/testsuite/ChangeLog:

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

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 95 +++++++++++++++----
 .../gcc.target/riscv/fusion-add-ldst.c        | 18 ++++
 .../gcc.target/riscv/fusion-addw-adduw-ldst.c | 67 +++++++++++++
 .../fusion-load-dest-equal-rtl-add-ldst.c     | 33 +++++++
 4 files changed, 193 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index 758e576706f..840bad47002 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -308,6 +308,43 @@ riscv_set_is_addiw_p (rtx set, rtx *src0 = NULL)
   return false;
 }
 
+/* Matches an addw:
+     (set (reg:DI rd)
+	  (sign_extend:DI (plus:SI (reg:SI rs1) (reg:SI rs2))))
+   or an equivalent word-add RTL form.  */
+
+static bool
+riscv_set_is_addw_p (rtx set)
+{
+  if (!TARGET_64BIT)
+    return false;
+
+  rtx src;
+  return (riscv_set_extract_word_binary_p (set, PLUS, &src)
+	  && REG_P (XEXP (src, 0))
+	  && REG_P (XEXP (src, 1))
+	  && riscv_regno (SET_DEST (set)) != INVALID_REGNUM);
+}
+
+/* Matches an add-type instruction:
+     (set (reg rd) (plus (reg rs1) (reg rs2)))
+   or an accepted addw or add.uw RTL form.  */
+
+static bool
+riscv_insn_is_add_type_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  enum attr_type type = get_attr_type (insn);
+  return ((type == TYPE_ARITH
+	   && (riscv_set_is_add_p (set) || riscv_set_is_addw_p (set)))
+	  || (TARGET_64BIT
+	      && type == TYPE_BITMANIP
+	      && riscv_set_is_adduw_p (set)));
+}
+
 /* Matches an mv or li instruction:
      (set (reg rd) (reg rs1))
    or:
@@ -581,6 +618,35 @@ riscv_fuse_mem_p (rtx_insn *insn, struct riscv_fusion_mem_info *info)
   return true;
 }
 
+/* Extract an add-type instruction followed by an integer load or store that
+   uses the add result as an undisplaced address.  */
+
+static bool
+riscv_fuse_add_mem_p (rtx_insn *prev, rtx_insn *curr,
+			rtx *add_set_out, rtx *mem_set_out,
+			struct riscv_fusion_mem_info *mem)
+{
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
+    return false;
+
+  rtx add_dest = SET_DEST (prev_set);
+  if (!riscv_insn_is_add_type_p (prev)
+      || !riscv_fuse_mem_p (curr, mem)
+      || mem->fp_p
+      || mem->addr.type != ADDRESS_REG
+      || !CONST_INT_P (mem->addr.offset)
+      || INTVAL (mem->addr.offset) != 0
+      || !riscv_fuse_same_reg_p (add_dest, mem->addr.reg))
+    return false;
+
+  if (add_set_out)
+    *add_set_out = prev_set;
+  if (mem_set_out)
+    *mem_set_out = curr_set;
+  return true;
+}
+
 /* Check the common RTL for ZEXTW, ZEXTWS and ZEXTH fusion.  */
 
 static bool
@@ -684,38 +750,27 @@ riscv_fuse_zexth (rtx_insn *prev, rtx_insn *curr)
 }
 
 /* Check for RISCV_FUSE_LDINDEXED fusion.
-   prev (add) == (set (reg rd1)
-		      (plus (reg rs1) (reg rs2)))
+   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):
      (load) == (set (reg rd2) (mem (reg rd1)))
      (load) == (set (reg rd2)
 		    (any_extend (mem (reg rd1))))
 
    Constraints:
-     rd1 == rd2.  */
+     offset == 0.  */
 
 static bool
 riscv_fuse_ldindexed (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_ST
-      && !mem.fp_p
-      && mem.addr.type == ADDRESS_REG
-      && INTVAL (mem.addr.offset) == 0
-      && riscv_set_is_add_p (prev_set)
-      && riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
-    return true;
-
-  return false;
+  return (riscv_fuse_add_mem_p (prev, curr, NULL, NULL, &mem)
+	  && mem.type != SCHED_FUSION_ST);
 }
 
 /* Check for RISCV_FUSE_EXPANDED_LD fusion.
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c b/gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c
new file mode 100644
index 00000000000..699e5369c24
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c
@@ -0,0 +1,18 @@
+/* { 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_LDINDEXED" 1 "sched2" { xfail *-*-* } } } */
+
+typedef long int64_t;
+
+extern void use_addr (void *);
+
+/* add + ld should fuse.  */
+int64_t
+test_add_ld (int64_t *base, long off)
+{
+  int64_t *p = (int64_t *) ((char *) base + off);
+  int64_t v = *p;
+  use_addr (p);
+  return v;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c b/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c
new file mode 100644
index 00000000000..9cb8dbcc457
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.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_LDINDEXED" 2 "sched2" { xfail *-*-* } } } */
+
+/* addw + ld should fuse.  */
+long __RTL (startwith ("sched2"))
+test_addw_ld (void)
+{
+(function "test_addw_ld"
+  (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)))))
+      ;; ld a1, 0(a0)
+      (cinsn 4 (set (reg:DI a1)
+                    (mem:DI (reg:DI a0) [0  S8 A64])))
+      (cinsn 5 (use (reg/i:DI a1)))
+      (cjump_insn 6 (simple_return))
+      (edge-to exit)
+    ) ;; block 2
+    (cbarrier 7)
+  ) ;; insn-chain
+  (crtl
+    (return_rtx
+      (reg/i:DI a1)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test_addw_ld"
+}
+
+/* add.uw + ld should fuse.  */
+long __RTL (startwith ("sched2"))
+test_adduw_ld (void)
+{
+(function "test_adduw_ld"
+  (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))))
+      ;; ld a1, 0(a0)
+      (cinsn 4 (set (reg:DI a1)
+                    (mem:DI (reg:DI a0) [0  S8 A64])))
+      (cinsn 5 (use (reg/i:DI a1)))
+      (cjump_insn 6 (simple_return))
+      (edge-to exit)
+    ) ;; block 2
+    (cbarrier 7)
+  ) ;; insn-chain
+  (crtl
+    (return_rtx
+      (reg/i:DI a1)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test_adduw_ld"
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c b/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c
new file mode 100644
index 00000000000..824b78b461c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.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 -O2 -mtune=xt-c9501fdvt -fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDINDEXED" 1 "sched2" { xfail *-*-* } } } */
+
+/* add and load writing the same register should fuse.  */
+long __RTL (startwith ("sched2"))
+test_add_load_same_destination (void)
+{
+(function "test_add_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)
+                    (plus:DI (reg:DI a1)
+                             (reg:DI a2))))
+      (cinsn 4 (set (reg:DI a0)
+                    (mem:DI (reg:DI a0) [0  S8 A64])))
+      (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_add_load_same_destination"
+}
-- 
2.52.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.