]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Update profile in tree-ssa-dce
authorJan Hubicka <hubicka@ucw.cz>
Mon, 6 Oct 2025 19:35:22 +0000 (21:35 +0200)
committerJan Hubicka <hubicka@ucw.cz>
Mon, 6 Oct 2025 19:35:22 +0000 (21:35 +0200)
The profile mismatches uncovered by my merge_blocks change are actually caused
by tree-ssa-dce not updating profile of blocks with no statements for whose it
optimized away control dependencies.  In most cases those basic blocks are
merged or skipped as forwarders.  I tried to simply set their count as
uninitialized but that upsets verifier since in some cases we keep the block
around (for example, when it is header of a loop).

In all cases I debugged we optimized away an unnecesary loop and while merging
old code picked porfile of loop preheader, while we now pick loop header.  This
is however not guaranteed and we may process blocks in different order and pick
wrong profile.

Since regions of dead basic blocks must be acyclic it is easy to propagate the
frequencies as implemented by this patch.

Bootstrapped/regtested x86_64-linux. Comitted

gcc/ChangeLog:

PR middle-end/122122
* tree-cfgcleanup.cc (tree_forwarder_block_p): Cleanup.
* tree-ssa-dce.cc (propagate_counts): New function.
(eliminate_unnecessary_stmts): Use it.

gcc/tree-cfgcleanup.cc
gcc/tree-ssa-dce.cc

index 5aaa18df0c558bdb27c454f26a05c54a21b31b11..58e8af5efcf5605c35698f828279588d91c433c7 100644 (file)
@@ -392,7 +392,7 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
   location_t locus;
 
   /* BB must have a single outgoing edge.  */
-  if (single_succ_p (bb) != 1
+  if (!single_succ_p (bb)
       /* If PHI_WANTED is false, BB must not have any PHI nodes.
         Otherwise, BB must have PHI nodes.  */
       || gimple_seq_empty_p (phi_nodes (bb)) == phi_wanted
index ba9cd6536aeb19345823883e8d0aa2c564c8324a..43869088322610632380880168a9613bdeab45bf 100644 (file)
@@ -1457,6 +1457,70 @@ control_parents_preserved_p (basic_block bb)
   return true;
 }
 
+/* If basic block is empty, we can remove conditionals that controls
+   its execution.  However in some cases the empty BB can stay live
+   (such as when it was a header of empty loop).  In this case we
+   need to update its count.  Since regions of dead BBs are acyclic
+   we simply propagate counts forward from live BBs to dead ones.  */
+
+static void
+propagate_counts ()
+{
+  basic_block bb;
+  auto_vec<basic_block, 16> queue;
+  hash_map <basic_block, int> cnt;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    if (!bitmap_bit_p (bb_contains_live_stmts, bb->index))
+      {
+       int n = 0;
+       for (edge e : bb->preds)
+         if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
+             && !bitmap_bit_p (bb_contains_live_stmts, e->src->index))
+           n++;
+       if (!n)
+         queue.safe_push (bb);
+       cnt.put (bb, n);
+      }
+  while (!queue.is_empty ())
+    {
+      basic_block bb = queue.pop ();
+      profile_count sum = profile_count::zero ();
+
+      for (edge e : bb->preds)
+       {
+         sum += e->count ();
+         gcc_checking_assert (!cnt.get (e->src));
+       }
+      /* If we have partial profile and some counts of incomming edges are
+        unknown, it is probably better to keep the existing count.
+        We could also propagate bi-directionally.  */
+      if (sum.initialized_p () && !(sum == bb->count))
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "Updating count of empty bb %i from ",
+                      bb->index);
+             bb->count.dump (dump_file);
+             fprintf (dump_file, " to ");
+             sum.dump (dump_file);
+             fprintf (dump_file, "\n");
+           }
+         bb->count = sum;
+       }
+      cnt.remove (bb);
+      for (edge e : bb->succs)
+       if (int *n = cnt.get (e->dest))
+         {
+           (*n)--;
+           if (!*n)
+             queue.safe_push (e->dest);
+         }
+    }
+  /* Do not check that all blocks has been processed, since for
+     empty infinite loops this is not the case.  */
+}
+
 /* Eliminate unnecessary statements. Any instruction not marked as necessary
    contributes nothing to the program, and can be deleted.  */
 
@@ -1800,6 +1864,8 @@ eliminate_unnecessary_stmts (bool aggressive)
                }
            }
        }
+      if (bb_contains_live_stmts)
+       propagate_counts ();
     }
 
   if (bb_postorder)