[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