[PATCH v5 06/18] RISC-V: Add ADD_ANDI macro-fusion recognition
Jin Ma <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
Recognize ADD/ADDI-type instructions followed by ANDI when the result register forms the required dependency. Parameterize the ANDI classifier so the new recognizer and existing B_ALUI logic share RTL parsing. Leave the fusion disabled by default. gcc/ChangeLog: * config/riscv/riscv-fusion.cc (riscv_insn_is_add_addi_p): New function. (riscv_insn_is_andi_type_p): Likewise. (riscv_fuse_b_alui): Reuse the ANDI matcher. (riscv_fuse_add_andi): New function. (riscv_fusion_table): Add RISCV_FUSE_ADD_ANDI. * config/riscv/riscv-protos.h (enum riscv_fusion_pairs): Add RISCV_FUSE_ADD_ANDI. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-add-addi-andi.c: New test. * gcc.target/riscv/fusion-mv-li-andi-rtl.c: Likewise. * gcc.target/riscv/fusion-special-positive-rtl-add-andi.c: Likewise. Signed-off-by: Jin Ma <[email protected]> --- gcc/config/riscv/riscv-fusion.cc | 95 ++++++++++++++++++- gcc/config/riscv/riscv-protos.h | 1 + .../gcc.target/riscv/fusion-add-addi-andi.c | 45 +++++++++ .../gcc.target/riscv/fusion-mv-li-andi-rtl.c | 63 ++++++++++++ .../fusion-special-positive-rtl-add-andi.c | 66 +++++++++++++ 5 files changed, 267 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-add-addi-andi.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-mv-li-andi-rtl.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-add-andi.c diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc index bb4076e9ffc..816c7dea452 100644 --- a/gcc/config/riscv/riscv-fusion.cc +++ b/gcc/config/riscv/riscv-fusion.cc @@ -702,6 +702,57 @@ riscv_insn_is_sub_type_p (rtx_insn *insn) && REG_P (XEXP (src, 1))); } +/* Matches an add- or addi-type instruction. */ + +static bool +riscv_insn_is_add_addi_p (rtx_insn *insn) +{ + return (riscv_insn_is_add_type_p (insn) + || riscv_insn_is_addi_type_p (insn)); +} + +/* Matches an andi: + (set (reg rd) (and (reg rs1) (const_int imm12))) + or an equivalent zero-extend RTL form. Store the normalized operands in + *SRC0 and *SRC1 when requested. */ + +static bool +riscv_insn_is_andi_type_p (rtx_insn *insn, rtx *src0 = NULL, + rtx *src1 = NULL) +{ + rtx set = single_set (insn); + if (!set) + return false; + + rtx src = SET_SRC (set); + if (get_attr_type (insn) == TYPE_LOGICAL + && GET_CODE (src) == AND + && REG_P (XEXP (src, 0)) + && CONST_INT_P (XEXP (src, 1)) + && riscv_regno (SET_DEST (set)) != INVALID_REGNUM) + { + if (src0) + *src0 = XEXP (src, 0); + if (src1) + *src1 = XEXP (src, 1); + return true; + } + + if (get_attr_move_type (insn) == MOVE_TYPE_ANDI + && GET_CODE (src) == ZERO_EXTEND + && riscv_regno (XEXP (src, 0)) != INVALID_REGNUM + && riscv_regno (SET_DEST (set)) != INVALID_REGNUM) + { + if (src0) + *src0 = XEXP (src, 0); + if (src1) + *src1 = GEN_INT (0xff); + return true; + } + + return false; +} + /* Fusion recognizers. */ /* Check for RISCV_FUSE_ZEXTW fusion. @@ -1150,10 +1201,11 @@ riscv_fuse_b_alui (rtx_insn *prev, rtx_insn *curr) return true; /* ctz + andi. */ + rtx andi_src1; if (GET_CODE (SET_SRC (prev_set)) == CTZ - && GET_CODE (SET_SRC (curr_set)) == AND - && CONST_INT_P (XEXP (SET_SRC (curr_set), 1)) - && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 63) + && riscv_insn_is_andi_type_p (curr, NULL, &andi_src1) + && CONST_INT_P (andi_src1) + && INTVAL (andi_src1) == 63) return true; /* sub + smax (abs pattern). */ @@ -1207,6 +1259,41 @@ riscv_fuse_sub_seqz (rtx_insn *prev, rtx_insn *curr) return false; } +/* Check for RISCV_FUSE_ADD_ANDI fusion. + prev (one of the following): + (add) == (set (reg rd1) (plus (reg rs1) (reg rs2))) + (addi) == (set (reg rd1) (plus (reg rs1) (const_int imm12_1))) + (addw) == (set (reg rd1) + (sign_extend (plus (reg rs1) (reg rs2)))) + (addiw) == (set (reg rd1) + (sign_extend (plus (reg rs1) (const_int imm12_1)))) + (add.uw) == (set (reg rd1) (plus (zero_extend (reg rs1)) + (reg rs2))) + (mv) == (set (reg rd1) (reg rs1)) + (li) == (set (reg rd1) (const_int imm12_1)) + (addi) == (set (reg rd1) (lo_sum (reg rs1) symbol)) + curr (one of the following): + (andi) == (set (reg rd2) (and (reg rd1) (const_int imm12_2))) + (andi) == (set (reg rd2) (zero_extend (reg rd1))) + + Constraints: + rd1 == rd2. */ + +static bool +riscv_fuse_add_andi (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_add_addi_p (prev) + && riscv_insn_is_andi_type_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. */ @@ -1260,6 +1347,8 @@ static const struct riscv_fusion_entry riscv_fusion_table[] = riscv_fuse_b_alui, "RISCV_FUSE_B_ALUI" }, { RISCV_FUSE_SUB_SEQZ, riscv_fuse_sub_seqz, "RISCV_FUSE_SUB_SEQZ" }, + { RISCV_FUSE_ADD_ANDI, + riscv_fuse_add_andi, "RISCV_FUSE_ADD_ANDI" }, }; /* 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 0bd26523a98..0848bc0ec4f 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -868,6 +868,7 @@ enum riscv_fusion_pairs RISCV_FUSE_B_ALUI = HOST_WIDE_INT_1U << 12, 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, }; extern bool riscv_macro_fusion_p (void); diff --git a/gcc/testsuite/gcc.target/riscv/fusion-add-addi-andi.c b/gcc/testsuite/gcc.target/riscv/fusion-add-addi-andi.c new file mode 100644 index 00000000000..983d40c8f6b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-add-addi-andi.c @@ -0,0 +1,45 @@ +/* { 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_ADD_ANDI" 5 "sched2" { xfail *-*-* } } } */ + +typedef long int64_t; +typedef unsigned long uint64_t; +typedef int int32_t; +typedef unsigned int uint32_t; + +/* addi + andi should fuse. */ +int64_t +test_addi_andi (int64_t a) +{ + return (a + 16) & 0x55; +} + +/* addiw + andi should fuse. */ +int64_t +test_addiw_andi (int32_t a) +{ + return (int64_t) (a + 5) & 0x55; +} + +/* add + andi should fuse. */ +int64_t +test_add_andi (int64_t a, int64_t b) +{ + return (a + b) & 0x55; +} + +/* addw + andi should fuse. */ +int64_t +test_addw_andi (int32_t a, int32_t b) +{ + return (int64_t) (a + b) & 0x33; +} + +/* add.uw + andi should fuse. */ +uint64_t +test_adduw_andi (uint64_t a, uint64_t b) +{ + return ((uint64_t) (uint32_t) a + b) & -2UL; +} diff --git a/gcc/testsuite/gcc.target/riscv/fusion-mv-li-andi-rtl.c b/gcc/testsuite/gcc.target/riscv/fusion-mv-li-andi-rtl.c new file mode 100644 index 00000000000..507efd0c2c7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-mv-li-andi-rtl.c @@ -0,0 +1,63 @@ +/* { 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_ADD_ANDI" 2 "sched2" { xfail *-*-* } } } */ + +/* mv followed by andi should fuse. */ +long __RTL (startwith ("sched2")) +test_mv_andi (void) +{ +(function "test_mv_andi" + (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) + (reg:DI a1))) + (cinsn 4 (set (reg:DI a0) + (and:DI (reg:DI a0) + (const_int 85)))) + (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_mv_andi" +} + +/* li followed by andi should fuse. */ +long __RTL (startwith ("sched2")) +test_li_andi (void) +{ +(function "test_li_andi" + (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) + (const_int 31))) + (cinsn 4 (set (reg:DI a0) + (and:DI (reg:DI a0) + (const_int 85)))) + (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_li_andi" +} diff --git a/gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-add-andi.c b/gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-add-andi.c new file mode 100644 index 00000000000..40a554e1cbd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-special-positive-rtl-add-andi.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_ADD_ANDI" 2 "sched2" { xfail *-*-* } } } */ + +extern long fusion_low_symbol; + +/* add followed by andi expressed as zero_extend should fuse. */ +long __RTL (startwith ("sched2")) +test_add_zero_extend_andi (void) +{ +(function "test_add_zero_extend_andi" + (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) + (plus:DI (reg:DI a1) + (reg:DI a2)))) + (cinsn 4 (set (reg:DI a0) + (zero_extend:DI + (subreg:QI (reg:DI a0) 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_add_zero_extend_andi" +} +/* lo_sum update followed by andi should fuse. */ +long __RTL (startwith ("sched2")) +test_lo_sum_andi (void) +{ +(function "test_lo_sum_andi" + (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) + (lo_sum:DI + (reg:DI a0) + (symbol_ref:DI ("fusion_low_symbol"))))) + (cinsn 4 (set (reg:DI a0) + (and:DI (reg:DI a0) + (const_int 85)))) + (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_lo_sum_andi" +} -- 2.52.0