[PATCH v5 09/18] RISC-V: Add SLLI_SRLI macro-fusion recognition
Jin Ma <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
Recognize matching-width SLLI/SLLIW followed by SRLI/SRLIW with the required register dependency. Recompose BFEXT and the new fusion from a shared shift-pair matcher. Leave the new fusion disabled by default and XFAIL its positive dump checks until a CPU enables it. gcc/ChangeLog: * config/riscv/riscv-fusion.cc (riscv_set_is_shift_type_p): New function. (riscv_fuse_shift_pair_p): Likewise. (riscv_fuse_bfext): Use riscv_fuse_shift_pair_p. (riscv_fuse_slli_srli): New function. (riscv_fusion_table): Add RISCV_FUSE_SLLI_SRLI. * config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add RISCV_FUSE_SLLI_SRLI. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-slli-srli.c: New test. * gcc.target/riscv/fusion-word-positive-rtl-slli-srli.c: Likewise. Signed-off-by: Jin Ma <[email protected]> --- gcc/config/riscv/riscv-fusion.cc | 170 ++++++++++++++++-- gcc/config/riscv/riscv-protos.h | 1 + .../gcc.target/riscv/fusion-slli-srli.c | 22 +++ .../fusion-word-positive-rtl-slli-srli.c | 66 +++++++ 4 files changed, 249 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-slli-srli.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-slli-srli.c diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc index a4f203347b7..ddb86b14e45 100644 --- a/gcc/config/riscv/riscv-fusion.cc +++ b/gcc/config/riscv/riscv-fusion.cc @@ -480,6 +480,150 @@ riscv_set_is_srai_p (rtx set) return riscv_set_is_shift_p (set, ASHIFTRT); } +/* Match a scalar shift of CODE, including the equivalent RV64 word forms + produced for SLLIW and SRLIW. Store whether the instruction is a word + form in *WORD_P and its effective shift amount in *SHIFT_AMOUNT when + requested. */ + +static bool +riscv_set_is_shift_type_p (rtx set, rtx_code code, bool *word_p, + HOST_WIDE_INT *shift_amount = NULL) +{ + if (riscv_set_is_shift_p (set, code)) + { + rtx src = SET_SRC (set); + *word_p = TARGET_64BIT && GET_MODE (src) == SImode; + if (shift_amount) + *shift_amount = INTVAL (XEXP (src, 1)); + return true; + } + + if (!TARGET_64BIT + || riscv_regno (SET_DEST (set)) == INVALID_REGNUM) + return false; + + rtx src = SET_SRC (set); + if (code == ASHIFT + && GET_CODE (src) == SIGN_EXTEND + && GET_MODE (src) == DImode) + { + src = XEXP (src, 0); + if (GET_CODE (src) == ASHIFT + && GET_MODE (src) == SImode + && riscv_regno (XEXP (src, 0)) != INVALID_REGNUM + && CONST_INT_P (XEXP (src, 1))) + { + *word_p = true; + if (shift_amount) + *shift_amount = INTVAL (XEXP (src, 1)) & 0x1f; + return true; + } + + if (GET_CODE (src) == AND + && GET_MODE (src) == SImode + && GET_CODE (XEXP (src, 0)) == ROTATERT + && riscv_regno (XEXP (XEXP (src, 0), 0)) != INVALID_REGNUM + && CONST_INT_P (XEXP (XEXP (src, 0), 1)) + && CONST_INT_P (XEXP (src, 1))) + { + *word_p = true; + if (shift_amount) + *shift_amount + = (32 - (INTVAL (XEXP (XEXP (src, 0), 1)) & 0x1f)) & 0x1f; + return true; + } + } + + if (code != LSHIFTRT) + return false; + + rtx_code src_code = GET_CODE (src); + if ((src_code == ZERO_EXTEND || src_code == SIGN_EXTEND) + && GET_MODE (src) == DImode) + { + rtx_code extend_code = src_code; + src = XEXP (src, 0); + if (GET_CODE (src) == LSHIFTRT + && GET_MODE (src) == SImode + && riscv_regno (XEXP (src, 0)) != INVALID_REGNUM + && CONST_INT_P (XEXP (src, 1)) + && (extend_code == SIGN_EXTEND + || (INTVAL (XEXP (src, 1)) & 0x1f) != 0)) + { + *word_p = true; + if (shift_amount) + *shift_amount = INTVAL (XEXP (src, 1)) & 0x1f; + return true; + } + return false; + } + + if (src_code == ZERO_EXTRACT + && GET_MODE (src) == DImode + && riscv_regno (XEXP (src, 0)) != INVALID_REGNUM + && CONST_INT_P (XEXP (src, 1)) + && CONST_INT_P (XEXP (src, 2)) + && INTVAL (XEXP (src, 2)) > 0 + && INTVAL (XEXP (src, 1)) + INTVAL (XEXP (src, 2)) == 32) + { + *word_p = true; + if (shift_amount) + *shift_amount = INTVAL (XEXP (src, 2)); + return true; + } + + if (src_code == LT + && GET_MODE (src) == DImode + && riscv_regno (XEXP (src, 0)) != INVALID_REGNUM + && GET_MODE (XEXP (src, 0)) == SImode + && XEXP (src, 1) == const0_rtx) + { + *word_p = true; + if (shift_amount) + *shift_amount = 31; + return true; + } + + return false; +} + +/* Match a left-shift/right-shift fusion pair. ALLOW_WORD_P accepts the + equivalent RV64 word forms and requires both instructions to have the same + wordness. ALLOW_ARITHMETIC_P accepts an arithmetic right shift. */ + +static bool +riscv_fuse_shift_pair_p (rtx_insn *prev, rtx_insn *curr, + bool allow_word_p, bool allow_arithmetic_p) +{ + rtx prev_set, curr_set; + if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set) + || get_attr_type (prev) != TYPE_SHIFT + || get_attr_type (curr) != TYPE_SHIFT) + return false; + + bool prev_word_p = false; + bool curr_word_p = false; + bool prev_match_p + = (allow_word_p + ? riscv_set_is_shift_type_p (prev_set, ASHIFT, &prev_word_p) + : riscv_set_is_slli_p (prev_set)); + bool curr_match_p + = (allow_word_p + ? riscv_set_is_shift_type_p (curr_set, LSHIFTRT, &curr_word_p) + : riscv_set_is_srli_p (curr_set)); + + if (!curr_match_p && allow_arithmetic_p) + curr_match_p = riscv_set_is_srai_p (curr_set); + + if (!prev_match_p + || !curr_match_p + || prev_word_p != curr_word_p + || !riscv_fuse_same_dest_p (prev_set, curr_set, true)) + return false; + + return true; +} + /* Load/store classes used by fusion checks. */ enum sched_fusion_type { @@ -1223,19 +1367,23 @@ riscv_fuse_aligned_std (rtx_insn *prev, rtx_insn *curr) static bool riscv_fuse_bfext (rtx_insn *prev, rtx_insn *curr) { - rtx prev_set, curr_set; - if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set)) - return false; + return riscv_fuse_shift_pair_p (prev, curr, false, true); +} - if (!riscv_fuse_same_dest_p (prev_set, curr_set, true)) - return false; +/* Check for RISCV_FUSE_SLLI_SRLI fusion. + prev (slli/slliw) == (set (reg rd1) (ashift (reg rs1) + (const_int shamt1))) + curr (srli/srliw) == (set (reg rd2) (lshiftrt (reg rd1) + (const_int shamt2))) - if (riscv_set_is_slli_p (prev_set) - && (riscv_set_is_srli_p (curr_set) - || riscv_set_is_srai_p (curr_set))) - return true; + Constraints: + rd1 == rd2 + both instructions are word forms or both are non-word forms. */ - return false; +static bool +riscv_fuse_slli_srli (rtx_insn *prev, rtx_insn *curr) +{ + return riscv_fuse_shift_pair_p (prev, curr, true, false); } /* Check for RISCV_FUSE_B_ALUI fusion. @@ -1506,6 +1654,8 @@ static const struct riscv_fusion_entry riscv_fusion_table[] = riscv_fuse_aligned_std, "RISCV_FUSE_ALIGNED_STD" }, { RISCV_FUSE_BFEXT, riscv_fuse_bfext, "RISCV_FUSE_BFEXT" }, + { RISCV_FUSE_SLLI_SRLI, + riscv_fuse_slli_srli, "RISCV_FUSE_SLLI_SRLI" }, { 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 46f148a9311..2321307484c 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -871,6 +871,7 @@ enum riscv_fusion_pairs RISCV_FUSE_ADD_ANDI = HOST_WIDE_INT_1U << 15, 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, }; extern bool riscv_macro_fusion_p (void); diff --git a/gcc/testsuite/gcc.target/riscv/fusion-slli-srli.c b/gcc/testsuite/gcc.target/riscv/fusion-slli-srli.c new file mode 100644 index 00000000000..5a0665e934a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-slli-srli.c @@ -0,0 +1,22 @@ +/* { 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_SLLI_SRLI" 2 "sched2" { xfail *-*-* } } } */ + +typedef unsigned long uint64_t; +typedef unsigned int uint32_t; + +/* slli + srli should fuse. */ +uint64_t +test_slli_srli (uint64_t a) +{ + return (a << 4) >> 8; +} + +/* slliw + srliw should fuse. */ +uint32_t +test_slliw_srliw (uint32_t a) +{ + return (a << 4) >> 8; +} diff --git a/gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-slli-srli.c b/gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-slli-srli.c new file mode 100644 index 00000000000..d227891501f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-word-positive-rtl-slli-srli.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_SLLI_SRLI" 2 "sched2" { xfail *-*-* } } } */ + +/* Raw SImode slli followed by raw SImode srli should fuse. */ +int __RTL (startwith ("sched2")) +test_raw_slliw_srliw (void) +{ +(function "test_raw_slliw_srliw" + (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) + (ashift:SI (reg:SI a1) + (const_int 4)))) + (cinsn 4 (set (reg:SI a0) + (lshiftrt:SI (reg:SI a0) + (const_int 8)))) + (cinsn 5 (use (reg/i:SI a0))) + (cjump_insn 6 (simple_return)) + (edge-to exit) + ) ;; block 2 + (cbarrier 7) + ) ;; insn-chain + (crtl + (return_rtx + (reg/i:SI a0) + ) ;; return_rtx + ) ;; crtl +) ;; function "test_raw_slliw_srliw" +} +/* Rotate-and-mask slliw followed by a sign-bit srliw should fuse. */ +long __RTL (startwith ("sched2")) +test_slliw_srliw_31 (void) +{ +(function "test_slliw_srliw_31" + (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 + (and:SI + (rotatert:SI (reg:SI a1) + (const_int 28)) + (const_int -16))))) + (cinsn 4 (set (reg:DI a0) + (lt:DI (reg:SI 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_slliw_srliw_31" +} -- 2.52.0