[PATCH v5 19/22] RISC-V: Add load/store macro-fusion scheduling priorities
Jin Ma <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
The sched_fusion pass can bring independent memory accesses together before sched2. Add a priority hook that groups scalar load/store-pair candidates by register file, access kind, mode and base register, then orders each group by offset. Prefer decreasing offsets when both directions are available, matching frame save/restore memory order. Enable scheduling fusion by default for load/store-pair tunes while preserving an explicit -f[no-]schedule-fusion option. Keep the positive test as XFAIL until the tuning patch enables the pairs. Static sched2 macro-fusion counts for SPEC CPU 2017 Integer built with -O3 -flto, measured independently of ready-list reordering against a baseline with xt-c9501fdvt fusion pairs enabled: Benchmark Baseline With patch Change 500.perlbench_r 15302 17077 +11.6% 502.gcc_r 72806 78135 +7.3% 505.mcf_r 63 85 +34.9% 520.omnetpp_r 20479 22084 +7.8% 523.xalancbmk_r 42442 44651 +5.2% 525.x264_r 6232 7033 +12.9% 531.deepsjeng_r 299 328 +9.7% 541.leela_r 794 851 +7.2% 548.exchange2_r 353 426 +20.7% 557.xz_r 1217 1321 +8.5% SUM 159987 171991 +7.5% gcc/ChangeLog: * config/riscv/riscv-fusion.cc (riscv_sched_fusion_priority): New function. * config/riscv/riscv-protos.h (riscv_sched_fusion_priority): Declare. * config/riscv/riscv.cc (riscv_override_options_internal): Set the scheduling-fusion default for the current tune. (TARGET_SCHED_FUSION_PRIORITY): Define. gcc/testsuite/ChangeLog: * gcc.target/riscv/sched-fusion-priority.c: New test. Signed-off-by: Jin Ma <[email protected]> --- gcc/config/riscv/riscv-fusion.cc | 68 +++++++++++++++++++ gcc/config/riscv/riscv-protos.h | 1 + gcc/config/riscv/riscv.cc | 10 +++ .../gcc.target/riscv/sched-fusion-priority.c | 49 +++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/sched-fusion-priority.c diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc index 332f64bd7cc..06cdab5694d 100644 --- a/gcc/config/riscv/riscv-fusion.cc +++ b/gcc/config/riscv/riscv-fusion.cc @@ -907,6 +907,74 @@ riscv_fuse_ldst_pair_p (rtx_insn *prev, rtx_insn *curr, return diff == access_size; } +/* Implement TARGET_SCHED_FUSION_PRIORITY. Group load/store pair candidates + by register file, access kind, mode and base register, then by offset. */ + +void +riscv_sched_fusion_priority (rtx_insn *insn, int max_pri, + int *fusion_pri, int *pri) +{ + struct riscv_fusion_mem_info mem; + unsigned HOST_WIDE_INT fusible_ops; + enum riscv_fusion_pairs inc_op, dec_op; + HOST_WIDE_INT access_size; + unsigned int base_regno; + bool isload_p, fp_p, inc_p; + int fusion_type, tmp; + + gcc_assert (INSN_P (insn)); + + tmp = max_pri - 1; + *fusion_pri = tmp; + *pri = tmp; + + if (!riscv_fuse_mem_p (insn, &mem) + || mem.type == SCHED_FUSION_LD_ZERO_EXTEND + || mem.addr.type != ADDRESS_REG + || !CONST_INT_P (mem.addr.offset)) + return; + + base_regno = riscv_regno (mem.addr.reg); + if (base_regno >= FIRST_PSEUDO_REGISTER) + return; + + isload_p = mem.type != SCHED_FUSION_ST; + fp_p = mem.fp_p; + access_size = GET_MODE_SIZE (mem.mode).to_constant (); + if (access_size != 4 && access_size != 8) + return; + + inc_op = fp_p ? RISCV_FUSE_FLDFST_PAIR_INC : RISCV_FUSE_LDST_PAIR_INC; + dec_op = fp_p ? RISCV_FUSE_FLDFST_PAIR_DEC : RISCV_FUSE_LDST_PAIR_DEC; + fusible_ops = riscv_get_fusible_ops (); + if (!(fusible_ops & (inc_op | dec_op))) + return; + + /* Prefer decreasing offsets to match frame save/restore order. */ + inc_p = !(fusible_ops & dec_op); + + /* Give each load/store class and base register a distinct priority below + that of unrelated instructions. */ + fusion_type = (fp_p ? 4 : 0) + (isload_p ? 0 : 2); + fusion_type += access_size == 8; + fusion_type++; + *fusion_pri -= (fusion_type * FIRST_PSEUDO_REGISTER + + (int) base_regno); + + tmp /= 2; + HOST_WIDE_INT off_val = INTVAL (mem.addr.offset); + unsigned HOST_WIDE_INT magnitude = off_val < 0 + ? -(unsigned HOST_WIDE_INT) off_val + : off_val; + int offset_pri = magnitude & 0xfffff; + + /* Order offsets in the preferred pair direction. */ + if (inc_p == (off_val >= 0)) + *pri = tmp - offset_pri; + else + *pri = tmp + offset_pri; +} + /* Check the common RTL for ZEXTW, ZEXTWS and ZEXTH fusion. */ static bool diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index cf36efccf75..0921b3a7618 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -884,6 +884,7 @@ enum riscv_fusion_pairs extern bool riscv_macro_fusion_p (void); extern bool riscv_macro_fusion_pair_p (rtx_insn *, rtx_insn *); +extern void riscv_sched_fusion_priority (rtx_insn *, int, int *, int *); extern unsigned HOST_WIDE_INT riscv_get_fusible_ops (void); /* Routines implemented in thead.cc. */ diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index a2a51c019ec..9f0c1d704c2 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -12121,6 +12121,14 @@ riscv_override_options_internal (struct gcc_options *opts) ? &optimize_size_tune_info : cpu->tune_param; + /* Enable scheduling fusion for load/store-pair tunes. */ + if (!OPTION_SET_P (flag_schedule_fusion)) + opts->x_flag_schedule_fusion + = (riscv_get_fusible_ops () + & (RISCV_FUSE_LDST_PAIR_INC | RISCV_FUSE_LDST_PAIR_DEC + | RISCV_FUSE_FLDFST_PAIR_INC | RISCV_FUSE_FLDFST_PAIR_DEC)) + != RISCV_FUSE_NOTHING; + /* If not optimizing for size, set the default alignment to what the target wants. */ if (!opts->x_optimize_size) @@ -16617,6 +16625,8 @@ riscv_memtag_tag_bitsize () #define TARGET_SCHED_MACRO_FUSION_P riscv_macro_fusion_p #undef TARGET_SCHED_MACRO_FUSION_PAIR_P #define TARGET_SCHED_MACRO_FUSION_PAIR_P riscv_macro_fusion_pair_p +#undef TARGET_SCHED_FUSION_PRIORITY +#define TARGET_SCHED_FUSION_PRIORITY riscv_sched_fusion_priority #undef TARGET_SCHED_INIT #define TARGET_SCHED_INIT riscv_sched_init diff --git a/gcc/testsuite/gcc.target/riscv/sched-fusion-priority.c b/gcc/testsuite/gcc.target/riscv/sched-fusion-priority.c new file mode 100644 index 00000000000..3d2c100a408 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sched-fusion-priority.c @@ -0,0 +1,49 @@ +/* { dg-do compile { target { rv64 } } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=xt-c9501fdvt -O2" } */ +/* { dg-additional-options "-fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* Start before sched_fusion and disable sched2 to isolate the priority + hook. */ + +/* +**sched_fusion_load_pair: { xfail *-*-* } +** ... +** ld [a-z][0-9]+,8\(a0\) +** ld [a-z][0-9]+,0\(a0\) +** ... +** ret +*/ +long __RTL (startwith ("compgotos")) +sched_fusion_load_pair (void) +{ +(function "sched_fusion_load_pair" + (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 a1) + (mem:DI (reg:DI a0) [0 S8 A64]))) + (cinsn 4 (set (reg:DI a3) + (plus:DI (reg:DI a4) (reg:DI a5)))) + (cinsn 5 (set (reg:DI a2) + (mem:DI + (plus:DI (reg:DI a0) + (const_int 8)) [0 S8 A64]))) + (cinsn 6 (use (reg:DI a1))) + (cinsn 7 (use (reg:DI a2))) + (cinsn 8 (use (reg:DI a3))) + (cjump_insn 9 (simple_return)) + (edge-to exit) + ) ;; block 2 + (cbarrier 10) + ) ;; insn-chain + (crtl + (return_rtx + (reg/i:DI a0) + ) ;; return_rtx + ) ;; crtl +) ;; function "sched_fusion_load_pair" +} -- 2.52.0