https://gcc.gnu.org/g:a79ae28a3ca2b8c9e9b015f96b3198a3648716a0
commit r17-3863-ga79ae28a3ca2b8c9e9b015f96b3198a3648716a0 Author: wangjue <[email protected]> Date: Wed Sep 2 08:55:05 2026 -0600 [PATCH v4] ifcvt: Account for parallelism when costing noce sequences 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, unit-cost 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. Changes since v1: v4: Format the multi-line conditional according to GNU coding style. v3: Refactor instruction validation and dependency-level calculation into separate helpers. Add comments explaining the intent of the parallel cost model. v2: Guard against calling targetm.sched.issue_rate when the hook is not defined. gcc/ChangeLog: * ifcvt.cc (noce_parallel_cost_node): New. (noce_parallel_costed_insn_p): New. (noce_dependency_level): New. (noce_parallel_seq_cost): New. (default_noce_conversion_profitable_p): Use it. Diff: --- gcc/ifcvt.cc | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc index 9927605385ab..8df6c3a6527a 100644 --- a/gcc/ifcvt.cc +++ b/gcc/ifcvt.cc @@ -803,6 +803,108 @@ noce_reversed_cond_code (struct noce_if_info *if_info) return reversed_comparison_code (if_info->cond, if_info->jump); } +/* A register definition and its dependency level. */ + +struct noce_parallel_cost_node +{ + rtx dest; + unsigned int level; +}; + +/* Return true if INSN is a unit-cost register SET supported by the parallel + cost model. Store the SET in *SET. */ + +static bool +noce_parallel_costed_insn_p (rtx_insn *insn, bool speed_p, rtx *set) +{ + *set = single_set (insn); + if (!*set) + return false; + + rtx dest = SET_DEST (*set); + rtx src = SET_SRC (*set); + + return (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 the dependency level for an instruction reading SRC. A use of a + register defined at level N requires level N + 1. */ + +static unsigned int +noce_dependency_level (const vec<noce_parallel_cost_node> &defs, rtx src) +{ + unsigned int level = 0; + + for (unsigned int i = 0; i < defs.length (); ++i) + if (reg_overlap_mentioned_p (defs[i].dest, src)) + level = MAX (level, defs[i].level + 1); + + return level; +} + +/* Estimate the cost of SEQ using the target issue rate. Unit-cost register + operations are grouped by RAW dependency level. The cost of each level is + its instruction count divided by the issue rate, rounded up. Fall back to + serial cost if any instruction cannot be modeled. + + 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 || !targetm.sched.issue_rate) + return serial_cost; + + unsigned int issue_rate = MAX (targetm.sched.issue_rate (), 1); + + /* Track prior definitions and instruction counts per dependency level. */ + auto_vec<noce_parallel_cost_node> defs; + auto_vec<unsigned int> insns_per_level; + + for (rtx_insn *insn = seq; insn; insn = NEXT_INSN (insn)) + { + rtx set; + + if (!NONDEBUG_INSN_P (insn)) + continue; + + if (!noce_parallel_costed_insn_p (insn, speed_p, &set)) + return serial_cost; + + unsigned int level = noce_dependency_level (defs, SET_SRC (set)); + + if (insns_per_level.length () <= level) + insns_per_level.safe_grow_cleared (level + 1, true); + ++insns_per_level[level]; + + noce_parallel_cost_node node = { SET_DEST (set), level }; + defs.safe_push (node); + } + + 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)); + + /* set_rtx_cost and insn_cost can disagree, so cap the estimate at the + serial cost. */ + 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 +917,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;
