[PATCH v5 04/18] RISC-V: Generalize LDINDEXED macro-fusion recognition
Jin Ma <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
Allow LDINDEXED to match ADD, ADDW, or ADD.UW followed by an undisplaced scalar integer load. The load may overwrite the computed address or use a different destination. Share the add-plus-memory structural matching with the following ADD_ST fusion patch. gcc/ChangeLog: * config/riscv/riscv-fusion.cc (riscv_set_is_addw_p): New function. (riscv_insn_is_add_type_p): Likewise. (riscv_fuse_add_mem_p): Likewise. (riscv_fuse_ldindexed): Use the common matcher and accept ADDW, ADD.UW, and either load-destination relationship. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-add-ldst.c: New test. * gcc.target/riscv/fusion-addw-adduw-ldst.c: Likewise. * gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c: Likewise. Signed-off-by: Jin Ma <[email protected]> --- gcc/config/riscv/riscv-fusion.cc | 95 +++++++++++++++---- .../gcc.target/riscv/fusion-add-ldst.c | 18 ++++ .../gcc.target/riscv/fusion-addw-adduw-ldst.c | 67 +++++++++++++ .../fusion-load-dest-equal-rtl-add-ldst.c | 33 +++++++ 4 files changed, 193 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc index 758e576706f..840bad47002 100644 --- a/gcc/config/riscv/riscv-fusion.cc +++ b/gcc/config/riscv/riscv-fusion.cc @@ -308,6 +308,43 @@ riscv_set_is_addiw_p (rtx set, rtx *src0 = NULL) return false; } +/* Matches an addw: + (set (reg:DI rd) + (sign_extend:DI (plus:SI (reg:SI rs1) (reg:SI rs2)))) + or an equivalent word-add RTL form. */ + +static bool +riscv_set_is_addw_p (rtx set) +{ + if (!TARGET_64BIT) + return false; + + rtx src; + return (riscv_set_extract_word_binary_p (set, PLUS, &src) + && REG_P (XEXP (src, 0)) + && REG_P (XEXP (src, 1)) + && riscv_regno (SET_DEST (set)) != INVALID_REGNUM); +} + +/* Matches an add-type instruction: + (set (reg rd) (plus (reg rs1) (reg rs2))) + or an accepted addw or add.uw RTL form. */ + +static bool +riscv_insn_is_add_type_p (rtx_insn *insn) +{ + 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))); +} + /* Matches an mv or li instruction: (set (reg rd) (reg rs1)) or: @@ -581,6 +618,35 @@ riscv_fuse_mem_p (rtx_insn *insn, struct riscv_fusion_mem_info *info) return true; } +/* Extract an add-type instruction followed by an integer load or store that + uses the add result as an undisplaced address. */ + +static bool +riscv_fuse_add_mem_p (rtx_insn *prev, rtx_insn *curr, + rtx *add_set_out, rtx *mem_set_out, + struct riscv_fusion_mem_info *mem) +{ + rtx prev_set, curr_set; + if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set)) + return false; + + rtx add_dest = SET_DEST (prev_set); + if (!riscv_insn_is_add_type_p (prev) + || !riscv_fuse_mem_p (curr, mem) + || mem->fp_p + || mem->addr.type != ADDRESS_REG + || !CONST_INT_P (mem->addr.offset) + || INTVAL (mem->addr.offset) != 0 + || !riscv_fuse_same_reg_p (add_dest, mem->addr.reg)) + return false; + + if (add_set_out) + *add_set_out = prev_set; + if (mem_set_out) + *mem_set_out = curr_set; + return true; +} + /* Check the common RTL for ZEXTW, ZEXTWS and ZEXTH fusion. */ static bool @@ -684,38 +750,27 @@ riscv_fuse_zexth (rtx_insn *prev, rtx_insn *curr) } /* Check for RISCV_FUSE_LDINDEXED fusion. - prev (add) == (set (reg rd1) - (plus (reg rs1) (reg rs2))) + prev (one of the following): + (add) == (set (reg rd1) (plus (reg rs1) (reg rs2))) + (addw) == (set (reg rd1) (sign_extend (plus:SI (reg rs1) + (reg rs2)))) + (add.uw) == (set (reg rd1) (plus (zero_extend (reg rs1)) + (reg rs2))) curr (one of the following): (load) == (set (reg rd2) (mem (reg rd1))) (load) == (set (reg rd2) (any_extend (mem (reg rd1)))) Constraints: - rd1 == rd2. */ + offset == 0. */ static bool riscv_fuse_ldindexed (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_fuse_same_dest_p (prev_set, curr_set)) - return false; - struct riscv_fusion_mem_info mem; - if (riscv_fuse_mem_p (curr, &mem) - && mem.type != SCHED_FUSION_ST - && !mem.fp_p - && mem.addr.type == ADDRESS_REG - && INTVAL (mem.addr.offset) == 0 - && riscv_set_is_add_p (prev_set) - && riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set))) - return true; - - return false; + return (riscv_fuse_add_mem_p (prev, curr, NULL, NULL, &mem) + && mem.type != SCHED_FUSION_ST); } /* Check for RISCV_FUSE_EXPANDED_LD fusion. diff --git a/gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c b/gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c new file mode 100644 index 00000000000..699e5369c24 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-add-ldst.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target { rv64 } } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */ +/* { dg-options "-march=rv64g -mabi=lp64d -mtune=xt-c9501fdvt -O2 -fdump-rtl-sched2-details" } */ +/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDINDEXED" 1 "sched2" { xfail *-*-* } } } */ + +typedef long int64_t; + +extern void use_addr (void *); + +/* add + ld should fuse. */ +int64_t +test_add_ld (int64_t *base, long off) +{ + int64_t *p = (int64_t *) ((char *) base + off); + int64_t v = *p; + use_addr (p); + return v; +} diff --git a/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c b/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c new file mode 100644 index 00000000000..9cb8dbcc457 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-addw-adduw-ldst.c @@ -0,0 +1,67 @@ +/* { 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" } */ +/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDINDEXED" 2 "sched2" { xfail *-*-* } } } */ + +/* addw + ld should fuse. */ +long __RTL (startwith ("sched2")) +test_addw_ld (void) +{ +(function "test_addw_ld" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + ;; addw a0, a1, a2 + (cinsn 3 (set (reg:DI a0) + (sign_extend:DI + (plus:SI (reg:SI a1) + (reg:SI a2))))) + ;; ld a1, 0(a0) + (cinsn 4 (set (reg:DI a1) + (mem:DI (reg:DI a0) [0 S8 A64]))) + (cinsn 5 (use (reg/i:DI a1))) + (cjump_insn 6 (simple_return)) + (edge-to exit) + ) ;; block 2 + (cbarrier 7) + ) ;; insn-chain + (crtl + (return_rtx + (reg/i:DI a1) + ) ;; return_rtx + ) ;; crtl +) ;; function "test_addw_ld" +} + +/* add.uw + ld should fuse. */ +long __RTL (startwith ("sched2")) +test_adduw_ld (void) +{ +(function "test_adduw_ld" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + ;; add.uw a0, a1, a2 + (cinsn 3 (set (reg:DI a0) + (plus:DI (zero_extend:DI (reg:SI a1)) + (reg:DI a2)))) + ;; ld a1, 0(a0) + (cinsn 4 (set (reg:DI a1) + (mem:DI (reg:DI a0) [0 S8 A64]))) + (cinsn 5 (use (reg/i:DI a1))) + (cjump_insn 6 (simple_return)) + (edge-to exit) + ) ;; block 2 + (cbarrier 7) + ) ;; insn-chain + (crtl + (return_rtx + (reg/i:DI a1) + ) ;; return_rtx + ) ;; crtl +) ;; function "test_adduw_ld" +} diff --git a/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c b/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c new file mode 100644 index 00000000000..824b78b461c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-load-dest-equal-rtl-add-ldst.c @@ -0,0 +1,33 @@ +/* { dg-do compile { target { rv64 } } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -O2 -mtune=xt-c9501fdvt -fdump-rtl-sched2-details" } */ +/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LDINDEXED" 1 "sched2" { xfail *-*-* } } } */ + +/* add and load writing the same register should fuse. */ +long __RTL (startwith ("sched2")) +test_add_load_same_destination (void) +{ +(function "test_add_load_same_destination" + (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) + (mem:DI (reg:DI a0) [0 S8 A64]))) + (cinsn 5 (use (reg: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_load_same_destination" +} -- 2.52.0