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, 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:
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.
---
gcc/ifcvt.cc | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 103 insertions(+), 1 deletion(-)
diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 5ea25f8fbe7..b458b0db253 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;
--
2.34.1