[PATCH v5 10/18] RISC-V: Add SRLI_ADD macro-fusion recognition

Jin Ma <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
Recognize SRLI/SRLIW followed by a matching-width ADD-type operation
when the normalized shift amount is two and the required
producer-consumer dependency holds.  Reuse the common shift classifier
and report wordness from the existing add classifier.

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_insn_is_add_type_p): Optionally
	report whether the instruction is a word form.
	(riscv_fuse_srli_add): New function.
	(riscv_fusion_table): Add RISCV_FUSE_SRLI_ADD.
	* config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add
	RISCV_FUSE_SRLI_ADD.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/fusion-srli-add.c: New test.
	* gcc.target/riscv/fusion-word-positive-rtl-srli-add.c: Likewise.

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-srli-add.c        | 32 +++++++++
 .../riscv/fusion-word-positive-rtl-srli-add.c | 67 +++++++++++++++++++
 4 files changed, 153 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-srli-add.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-srli-add.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index ddb86b14e45..c24fb29cbaf 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -328,21 +328,30 @@ riscv_set_is_addw_p (rtx set)
 
 /* Matches an add-type instruction:
      (set (reg rd) (plus (reg rs1) (reg rs2)))
-   or an accepted addw or add.uw RTL form.  */
+   or an accepted addw or add.uw RTL form.  Store whether the instruction is
+   a word form in *WORD_P when requested.  */
 
 static bool
-riscv_insn_is_add_type_p (rtx_insn *insn)
+riscv_insn_is_add_type_p (rtx_insn *insn, bool *word_p = NULL)
 {
   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)));
+  bool is_word_p = false;
+  if (type == TYPE_ARITH && riscv_set_is_add_p (set))
+    is_word_p = TARGET_64BIT && GET_MODE (SET_SRC (set)) == SImode;
+  else if (type == TYPE_ARITH && riscv_set_is_addw_p (set))
+    is_word_p = true;
+  else if (!TARGET_64BIT
+	   || type != TYPE_BITMANIP
+	   || !riscv_set_is_adduw_p (set))
+    return false;
+
+  if (word_p)
+    *word_p = is_word_p;
+  return true;
 }
 
 /* Matches an mv or li instruction:
@@ -1386,6 +1395,41 @@ riscv_fuse_slli_srli (rtx_insn *prev, rtx_insn *curr)
   return riscv_fuse_shift_pair_p (prev, curr, true, false);
 }
 
+/* Check for RISCV_FUSE_SRLI_ADD fusion.
+   prev (srli/srliw) == (set (reg rd1) (lshiftrt (reg rs1)
+						 (const_int 2)))
+   curr (one of the following):
+     (add) == (set (reg rd2) (plus (reg rd1) (reg rs2)))
+     (addw) == (set (reg rd2)
+		  (sign_extend (plus (reg rd1) (reg rs2))))
+     (add.uw) == (set (reg rd2) (plus (zero_extend (reg rd1))
+				   (reg rs2)))
+
+   Constraints:
+     rd1 == rd2
+     both instructions are word forms or both are non-word forms.  */
+
+static bool
+riscv_fuse_srli_add (rtx_insn *prev, rtx_insn *curr)
+{
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set)
+      || get_attr_type (prev) != TYPE_SHIFT)
+    return false;
+
+  bool shift_word_p, add_word_p;
+  HOST_WIDE_INT shift_amount;
+  if (!riscv_set_is_shift_type_p (prev_set, LSHIFTRT, &shift_word_p,
+				  &shift_amount)
+      || !riscv_insn_is_add_type_p (curr, &add_word_p)
+      || shift_word_p != add_word_p
+      || !riscv_fuse_same_dest_p (prev_set, curr_set, true))
+    return false;
+
+  unsigned int mask = shift_word_p ? 0x1f : (TARGET_64BIT ? 0x3f : 0x1f);
+  return (shift_amount & mask) == 2;
+}
+
 /* Check for RISCV_FUSE_B_ALUI fusion.
    prev/curr (one of the following pairs):
      prev (orc.b) == (set (reg rd1)
@@ -1656,6 +1700,8 @@ static const struct riscv_fusion_entry riscv_fusion_table[] =
     riscv_fuse_bfext, "RISCV_FUSE_BFEXT" },
   { RISCV_FUSE_SLLI_SRLI,
     riscv_fuse_slli_srli, "RISCV_FUSE_SLLI_SRLI" },
+  { RISCV_FUSE_SRLI_ADD,
+    riscv_fuse_srli_add, "RISCV_FUSE_SRLI_ADD" },
   { RISCV_FUSE_B_ALUI,
     riscv_fuse_b_alui, "RISCV_FUSE_B_ALUI" },
   { RISCV_FUSE_SUB_SEQZ,
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 2321307484c..c107a574ad6 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -872,6 +872,7 @@ enum riscv_fusion_pairs
   RISCV_FUSE_ANDI_ADD = HOST_WIDE_INT_1U << 16,
   RISCV_FUSE_LOGIC_LOGIC = HOST_WIDE_INT_1U << 17,
   RISCV_FUSE_SLLI_SRLI = HOST_WIDE_INT_1U << 18,
+  RISCV_FUSE_SRLI_ADD = HOST_WIDE_INT_1U << 19,
 };
 
 extern bool riscv_macro_fusion_p (void);
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-srli-add.c b/gcc/testsuite/gcc.target/riscv/fusion-srli-add.c
new file mode 100644
index 00000000000..0fe58cbb785
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-srli-add.c
@@ -0,0 +1,32 @@
+/* { 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" } */
+/* No tune enables these fusion pairs yet.  */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_SRLI_ADD" 3 "sched2" { xfail *-*-* } } } */
+
+typedef long int64_t;
+typedef unsigned long uint64_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+/* srli by 2 followed by add should fuse.  */
+int64_t
+test_srli_add (uint64_t a, int64_t b)
+{
+  return (int64_t) (a >> 2) + b;
+}
+
+/* srliw by 2 followed by addw should fuse.  */
+int32_t
+test_srliw_addw (uint32_t a, int32_t b)
+{
+  return (int32_t) (a >> 2) + b;
+}
+
+/* srli by 2 followed by add.uw should fuse.  */
+uint64_t
+test_srli_adduw (uint64_t a, uint64_t b)
+{
+  return (uint64_t) (uint32_t) (a >> 2) + b;
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-srli-add.c b/gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-srli-add.c
new file mode 100644
index 00000000000..a05e4e83752
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-srli-add.c
@@ -0,0 +1,67 @@
+/* { 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_SRLI_ADD" 2 "sched2" { xfail *-*-* } } } */
+
+/* Raw SImode srli followed by a same-source addw should fuse.  */
+long __RTL (startwith ("sched2"))
+test_raw_srliw_extended_addw (void)
+{
+(function "test_raw_srliw_extended_addw"
+  (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:SI a0)
+                    (lshiftrt:SI (reg:SI a1)
+                                 (const_int 2))))
+      (cinsn 4 (set (reg:DI a0)
+                    (sign_extend:DI
+                      (plus:SI (reg:SI a0)
+                               (reg:SI a0)))))
+      (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_raw_srliw_extended_addw"
+}
+/* Zero-extended srliw followed by addw expressed via truncate.  */
+long __RTL (startwith ("sched2"))
+test_lowpart_srliw_addw (void)
+{
+(function "test_lowpart_srliw_addw"
+  (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)
+                    (zero_extend:DI
+                      (lshiftrt:SI (reg:SI a1)
+                                   (const_int 2)))))
+      (cinsn 4 (set (reg:DI a0)
+                    (sign_extend:DI
+                      (truncate:SI
+                        (plus:DI (reg:DI a0)
+                                 (reg:DI a2))))))
+      (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_lowpart_srliw_addw"
+}
-- 
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.