[PATCH.v1] ifcvt: Account for parallelism when costing noce sequences
wangjue <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
From: juewang <[email protected]> seq_cost treats every instruction in a replacement sequence as serial. This can overestimate simple register-only sequences on superscalar targets and reject profitable if-conversion. Build dependency levels for simple, single-cycle register operations. Cost each level using the target issue rate. Fall back to the serial cost for unsupported sequences, size optimization, and targets without an issue rate hook. gcc/ChangeLog: * ifcvt.cc (noce_parallel_cost_node): New. (noce_parallel_seq_cost): New. (default_noce_conversion_profitable_p): Use it. --- gcc/ifcvt.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc index 5ea25f8fbe7..146c738d32f 100644 --- a/gcc/ifcvt.cc +++ b/gcc/ifcvt.cc @@ -803,6 +803,88 @@ noce_reversed_cond_code (struct noce_if_info *if_info) return reversed_comparison_code (if_info->cond, if_info->jump); } +/* A destination and its dependency level in a noce sequence. */ + +struct noce_parallel_cost_node +{ + rtx dest; + unsigned int level; +}; + +/* Estimate the cost of independent, single-cycle register operations in + SEQ using the target issue rate. + + In an instrumented build of all SPEC CPU2017 Integer rate benchmarks + for RISC-V, the analysis handled 16,947 of 30,120 candidates (56.26%). + It reduced the cost for 15,024 of the handled candidates (88.65%). + The parallel-to-serial cost ratios for the handled candidates were: + + 0.8 < ratio <= 1.0 11.54 percent + 0.6 < ratio <= 0.8 47.31 percent + 0.4 < ratio <= 0.6 40.24 percent + 0.2 < ratio <= 0.4 0.91 percent + 0.0 < ratio <= 0.2 0.00 percent. */ + +static unsigned int +noce_parallel_seq_cost (rtx_insn *seq, bool speed_p) +{ + unsigned int serial_cost = seq_cost (seq, speed_p); + + if (!speed_p) + return serial_cost; + + if (!targetm.sched.issue_rate) + return serial_cost; + + unsigned int issue_rate = MAX (targetm.sched.issue_rate (), 1); + auto_vec<noce_parallel_cost_node> nodes; + auto_vec<unsigned int> insns_per_level; + + /* Build register dependency levels. Place an instruction after its + deepest producer; independent instructions remain at the same level. */ + + for (rtx_insn *insn = seq; insn; insn = NEXT_INSN (insn)) + { + if (!NONDEBUG_INSN_P (insn)) + continue; + + rtx set = single_set (insn); + if (!set) + return serial_cost; + + rtx dest = SET_DEST (set); + rtx src = SET_SRC (set); + + if (!REG_P (dest) + || contains_mem_rtx_p (src) + || side_effects_p (src) + || may_trap_p (src) + || set_rtx_cost (set, speed_p) != COSTS_N_INSNS (1)) + return serial_cost; + + unsigned int level = 0; + for (unsigned int i = 0; i < nodes.length (); ++i) + if (reg_overlap_mentioned_p (nodes[i].dest, src)) + level = MAX (level, nodes[i].level + 1); + + if (insns_per_level.length () <= level) + insns_per_level.safe_grow_cleared (level + 1, true); + ++insns_per_level[level]; + + noce_parallel_cost_node node = { dest, level }; + nodes.safe_push (node); + } + + /* Sum the issue cycles needed for each dependency level. */ + + unsigned int parallel_cost = 0; + for (unsigned int i = 0; i < insns_per_level.length (); ++i) + parallel_cost + += COSTS_N_INSNS (CEIL (insns_per_level[i], issue_rate)); + + return MIN (serial_cost, parallel_cost); +} + /* Return true if SEQ is a good candidate as a replacement for the if-convertible sequence described in IF_INFO. This is the default implementation that targets can override @@ -815,7 +897,7 @@ default_noce_conversion_profitable_p (rtx_insn *seq, bool speed_p = if_info->speed_p; /* Cost up the new sequence. */ - unsigned int cost = seq_cost (seq, speed_p); + unsigned int cost = noce_parallel_seq_cost (seq, speed_p); if (cost <= if_info->original_cost) return true; -- 2.34.1