[PATCH v5 03/18] RISC-V: Add SUB_SEQZ macro-fusion recognition

Jin Ma <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
Recognize SUB/SUBW followed by SEQZ/SNEZ when the operations have
the required producer-consumer and destination relationships.  Leave
the fusion disabled by default.

gcc/ChangeLog:

	* config/riscv/riscv-fusion.cc (riscv_insn_is_sub_type_p): New
	function.
	(riscv_fuse_sub_seqz): Likewise.
	(riscv_fusion_table): Add RISCV_FUSE_SUB_SEQZ.
	* config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add
	RISCV_FUSE_SUB_SEQZ.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/fusion-sub-seqz-snez.c: New test.

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 60 +++++++++++++++++
 gcc/config/riscv/riscv-protos.h               |  1 +
 .../gcc.target/riscv/fusion-sub-seqz-snez.c   | 66 +++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-sub-seqz-snez.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index 88735b580f1..758e576706f 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -610,6 +610,32 @@ riscv_fuse_zext_common (rtx_insn *prev, rtx_insn *curr,
   return false;
 }
 
+/* Matches a sub or subw:
+     (set (reg rd) (minus (reg rs1) (reg rs2)))
+   or:
+     (set (reg:DI rd)
+	  (sign_extend:DI (minus:SI (reg:SI rs1) (reg:SI rs2))))
+   or an equivalent word-sub RTL form.  */
+
+static bool
+riscv_insn_is_sub_type_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set
+      || get_attr_type (insn) != TYPE_ARITH
+      || riscv_regno (SET_DEST (set)) == INVALID_REGNUM)
+    return false;
+
+  rtx src = SET_SRC (set);
+  if (GET_CODE (src) == MINUS)
+    return (REG_P (XEXP (src, 0))
+	    && REG_P (XEXP (src, 1)));
+
+  return (riscv_set_extract_word_binary_p (set, MINUS, &src)
+	  && REG_P (XEXP (src, 0))
+	  && REG_P (XEXP (src, 1)));
+}
+
 /* Fusion recognizers.  */
 
 /* Check for RISCV_FUSE_ZEXTW fusion.
@@ -1067,6 +1093,38 @@ riscv_fuse_b_alui (rtx_insn *prev, rtx_insn *curr)
   return false;
 }
 
+/* Check for RISCV_FUSE_SUB_SEQZ fusion.
+   prev (one of the following):
+     (sub) == (set (reg rd1) (minus (reg rs1) (reg rs2)))
+     (subw) == (set (reg rd1)
+		    (sign_extend (minus:SI (reg:SI rs1) (reg:SI rs2))))
+   curr (one of the following):
+     (seqz) == (set (reg rd2) (eq (reg rd1) (const_int 0)))
+     (snez) == (set (reg rd2) (ne (reg rd1) (const_int 0)))
+
+   Constraints:
+     rd1 == rd2.  */
+
+static bool
+riscv_fuse_sub_seqz (rtx_insn *prev, rtx_insn *curr)
+{
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
+    return false;
+
+  rtx curr_src = SET_SRC (curr_set);
+  rtx_code curr_code = GET_CODE (curr_src);
+
+  if (riscv_insn_is_sub_type_p (prev)
+      && get_attr_type (curr) == TYPE_SLT
+      && (curr_code == EQ || curr_code == NE)
+      && riscv_fuse_same_dest_p (prev_set, curr_set, true)
+      && XEXP (curr_src, 1) == const0_rtx)
+    return true;
+
+  return false;
+}
+
 /* Type for a fusion checker function.  Takes the two candidate insns
    and returns true if they should be fused.  */
 
@@ -1116,6 +1174,8 @@ static const struct riscv_fusion_entry riscv_fusion_table[] =
     riscv_fuse_bfext, "RISCV_FUSE_BFEXT" },
   { RISCV_FUSE_B_ALUI,
     riscv_fuse_b_alui, "RISCV_FUSE_B_ALUI" },
+  { RISCV_FUSE_SUB_SEQZ,
+    riscv_fuse_sub_seqz, "RISCV_FUSE_SUB_SEQZ" },
 };
 
 /* Implement TARGET_SCHED_MACRO_FUSION_PAIR_P.  Return true if PREV and CURR
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index e9612cca1a1..20781e14313 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -866,6 +866,7 @@ enum riscv_fusion_pairs
   RISCV_FUSE_BFEXT = HOST_WIDE_INT_1U << 10,
   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,
 };
 
 extern bool riscv_macro_fusion_p (void);
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-sub-seqz-snez.c b/gcc/testsuite/gcc.target/riscv/fusion-sub-seqz-snez.c
new file mode 100644
index 00000000000..20c841c9019
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-sub-seqz-snez.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 -mtune=xt-c9501fdvt -O2 -fdump-rtl-sched2-details" } */
+/* No tune enables these fusion pairs yet.  */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_SUB_SEQZ" 2 "sched2" { xfail *-*-* } } } */
+
+/* sub + seqz should fuse.  */
+long __RTL (startwith ("sched2"))
+test_sub_seqz (void)
+{
+(function "test_sub_seqz"
+  (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)
+                    (minus:DI (reg:DI a1)
+                              (reg:DI a2))))
+      (cinsn 4 (set (reg:DI a0)
+                    (eq:DI (reg:DI a0)
+                           (const_int 0))))
+      (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_sub_seqz"
+}
+
+/* subw + snez should fuse.  */
+long __RTL (startwith ("sched2"))
+test_subw_snez (void)
+{
+(function "test_subw_snez"
+  (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)
+                    (sign_extend:DI
+                      (minus:SI (reg:SI a1)
+                                (reg:SI a2)))))
+      (cinsn 4 (set (reg:DI a0)
+                    (ne:DI (reg:DI a0)
+                           (const_int 0))))
+      (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_subw_snez"
+}
-- 
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.