https://gcc.gnu.org/g:075310d3a3ef1a8b483b62d9535887b37f291ee4

commit r16-4255-g075310d3a3ef1a8b483b62d9535887b37f291ee4
Author: Jan Hubicka <[email protected]>
Date:   Mon Oct 6 21:35:22 2025 +0200

    Update profile in tree-ssa-dce
    
    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.

Diff:
---
 gcc/tree-cfgcleanup.cc |  2 +-
 gcc/tree-ssa-dce.cc    | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc
index 5aaa18df0c55..58e8af5efcf5 100644
--- a/gcc/tree-cfgcleanup.cc
+++ b/gcc/tree-cfgcleanup.cc
@@ -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
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index ba9cd6536aeb..438690883226 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -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)

Reply via email to