[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