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

Reply via email to