[PATCH v5 07/18] RISC-V: Add ANDI_ADD macro-fusion recognition

Jin Ma <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
Recognize ANDI followed by an ADD/ADDI-type instruction when the
result register forms the required dependency.  An ADD may use the ANDI
result as both source operands; no source-inequality constraint is
imposed.

Leave the fusion disabled by default.

gcc/ChangeLog:

	* config/riscv/riscv-fusion.cc (riscv_fuse_andi_add): New function.
	(riscv_fusion_table): Add RISCV_FUSE_ANDI_ADD.
	* config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add
	RISCV_FUSE_ANDI_ADD.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/fusion-andi-add-addi.c: New test.
	* gcc.target/riscv/fusion-andi-adduw-rtl.c: Likewise.
	* gcc.target/riscv/fusion-special-positive-rtl-andi-add.c: Likewise.

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 36 ++++++++++
 gcc/config/riscv/riscv-protos.h               |  1 +
 .../gcc.target/riscv/fusion-andi-add-addi.c   | 36 ++++++++++
 .../gcc.target/riscv/fusion-andi-adduw-rtl.c  | 65 ++++++++++++++++++
 .../fusion-special-positive-rtl-andi-add.c    | 66 +++++++++++++++++++
 5 files changed, 204 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-andi-add-addi.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-andi-adduw-rtl.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-andi-add.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index 816c7dea452..3b09e1a4a57 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -1294,6 +1294,40 @@ riscv_fuse_add_andi (rtx_insn *prev, rtx_insn *curr)
   return false;
 }
 
+/* Check for RISCV_FUSE_ANDI_ADD fusion.
+   prev (one of the following):
+     (andi) == (set (reg rd1) (and (reg rs1) (const_int imm12_1)))
+     (andi) == (set (reg rd1) (zero_extend (reg rs1)))
+   curr (one of the following):
+     (add) == (set (reg rd2) (plus (reg rd1) (reg rs2)))
+     (addi) == (set (reg rd2) (plus (reg rd1) (const_int imm12_2)))
+     (addw) == (set (reg rd2)
+		    (sign_extend (plus (reg rd1) (reg rs2))))
+     (addiw) == (set (reg rd2)
+		     (sign_extend (plus (reg rd1) (const_int imm12_2))))
+     (add.uw) == (set (reg rd2) (plus (zero_extend (reg rd1))
+				      (reg rs2)))
+     (mv) == (set (reg rd2) (reg rd1))
+     (addi) == (set (reg rd2) (lo_sum (reg rd1) symbol))
+
+   Constraints:
+     rd1 == rd2.  */
+
+static bool
+riscv_fuse_andi_add (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_insn_is_andi_type_p (prev)
+      && riscv_insn_is_add_addi_p (curr)
+      && riscv_fuse_same_dest_p (prev_set, curr_set, true))
+    return true;
+
+  return false;
+}
+
 /* Type for a fusion checker function.  Takes the two candidate insns
    and returns true if they should be fused.  */
 
@@ -1349,6 +1383,8 @@ static const struct riscv_fusion_entry riscv_fusion_table[] =
     riscv_fuse_sub_seqz, "RISCV_FUSE_SUB_SEQZ" },
   { RISCV_FUSE_ADD_ANDI,
     riscv_fuse_add_andi, "RISCV_FUSE_ADD_ANDI" },
+  { RISCV_FUSE_ANDI_ADD,
+    riscv_fuse_andi_add, "RISCV_FUSE_ANDI_ADD" },
 };
 
 /* 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 0848bc0ec4f..f6863bc4c17 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -869,6 +869,7 @@ enum riscv_fusion_pairs
   RISCV_FUSE_SUB_SEQZ = HOST_WIDE_INT_1U << 13,
   RISCV_FUSE_ADD_ST = HOST_WIDE_INT_1U << 14,
   RISCV_FUSE_ADD_ANDI = HOST_WIDE_INT_1U << 15,
+  RISCV_FUSE_ANDI_ADD = HOST_WIDE_INT_1U << 16,
 };
 
 extern bool riscv_macro_fusion_p (void);
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-andi-add-addi.c b/gcc/testsuite/gcc.target/riscv/fusion-andi-add-addi.c
new file mode 100644
index 00000000000..746f865535d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-andi-add-addi.c
@@ -0,0 +1,36 @@
+/* { 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_ANDI_ADD" 4 "sched2" { xfail *-*-* } } } */
+
+typedef long int64_t;
+typedef int int32_t;
+
+/* andi + addi should fuse.  */
+int64_t
+test_andi_addi (int64_t a)
+{
+  return (a & 0x55) + 1;
+}
+
+/* andi + addiw should fuse.  */
+int64_t
+test_andi_addiw (int64_t a)
+{
+  return (int64_t) ((int32_t) (a & 0x55) + 5);
+}
+
+/* andi + add should fuse.  */
+int64_t
+test_andi_add (int64_t a, int64_t b)
+{
+  return (a & 0x55) + b;
+}
+
+/* andi + addw should fuse.  */
+int64_t
+test_andi_addw (int64_t a, int32_t b)
+{
+  return (int64_t) ((int32_t) (a & 0x55) + b);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-andi-adduw-rtl.c b/gcc/testsuite/gcc.target/riscv/fusion-andi-adduw-rtl.c
new file mode 100644
index 00000000000..996f4914f86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-andi-adduw-rtl.c
@@ -0,0 +1,65 @@
+/* { 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_ANDI_ADD" 2 "sched2" { xfail *-*-* } } } */
+
+/* andi feeding add.uw's zero-extended operand should fuse.  */
+long __RTL (startwith ("sched2"))
+test_andi_adduw (void)
+{
+(function "test_andi_adduw"
+  (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)
+                    (and:DI (reg:DI a1)
+                            (const_int -3))))
+      (cinsn 4 (set (reg:DI a0)
+                    (plus:DI (zero_extend:DI (reg:SI 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_andi_adduw"
+}
+
+/* An add may use andi's result as both sources.  */
+long __RTL (startwith ("sched2"))
+test_andi_add_same_source (void)
+{
+(function "test_andi_add_same_source"
+  (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)
+                    (and:DI (reg:DI a1)
+                            (const_int 85))))
+      (cinsn 4 (set (reg:DI a0)
+                    (plus:DI (reg:DI a0)
+                             (reg:DI 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_andi_add_same_source"
+}
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-andi-add.c b/gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-andi-add.c
new file mode 100644
index 00000000000..4af0e90c798
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-andi-add.c
@@ -0,0 +1,66 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64gc_zbb -mabi=lp64d -mtune=xt-c9501fdvt -O2 -fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_ANDI_ADD" 2 "sched2" { xfail *-*-* } } } */
+
+extern long fusion_low_symbol;
+
+/* andi expressed as zero_extend followed by add should fuse.  */
+long __RTL (startwith ("sched2"))
+test_zero_extend_andi_add (void)
+{
+(function "test_zero_extend_andi_add"
+  (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
+                      (subreg:QI (reg:DI a1) 0))))
+      (cinsn 4 (set (reg:DI a0)
+                    (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_zero_extend_andi_add"
+}
+/* andi followed by a lo_sum update should fuse.  */
+long __RTL (startwith ("sched2"))
+test_andi_lo_sum (void)
+{
+(function "test_andi_lo_sum"
+  (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)
+                    (and:DI (reg:DI a1)
+                            (const_int 85))))
+      (cinsn 4 (set (reg:DI a0)
+                    (lo_sum:DI
+                      (reg:DI a0)
+                      (symbol_ref:DI ("fusion_low_symbol")))))
+      (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_andi_lo_sum"
+}
-- 
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.