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

Reply via email to