[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