On Thu, Nov 13, 2025 at 6:02 AM Andrew Pinski <[email protected]> wrote: > > This moves the checks that were in pass_merge_phi::execute into > remove_forwarder_block_with_phi > or tree_forwarder_block_p to make easier to merge > remove_forwarder_block_with_phi with remove_forwarder_block. > This also simplifies the code slightly because we can do `return false` > rather than break > in one location.
So this puts back one O(num-stmts) loop into CFG cleanup which I previously tried to make sure to be O(CFG size). But looking we're already doing O(#debug-stmts + #labels) work here, so this is a moot point. So OK to this (and the previous in the series). Richard. > gcc/ChangeLog: > > * tree-cfgcleanup.cc (pass_merge_phi::execute): Move > check for abnormal or no phis to remove_forwarder_block_with_phi > and the check on dominated to tree_forwarder_block_p. > (remove_forwarder_block_with_phi): here. > > Signed-off-by: Andrew Pinski <[email protected]> > --- > gcc/tree-cfgcleanup.cc | 102 +++++++++++++++++++---------------------- > 1 file changed, 48 insertions(+), 54 deletions(-) > > diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc > index 2f4fa0a7b8a..9f526492b72 100644 > --- a/gcc/tree-cfgcleanup.cc > +++ b/gcc/tree-cfgcleanup.cc > @@ -456,6 +456,43 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted) > } > } > > + /* If BB has PHIs and does not dominate DEST, > + then the PHI nodes at DEST must be the only > + users of the results of the PHI nodes at BB. > + So only check when BB dominates dest. */ > + if (!gimple_seq_empty_p (phi_nodes (bb)) > + && dominated_by_p (CDI_DOMINATORS, dest, bb)) > + { > + gphi_iterator gsi; > + unsigned int dest_idx = single_succ_edge (bb)->dest_idx; > + > + /* BB dominates DEST. There may be many users of the PHI > + nodes in BB. However, there is still a trivial case we > + can handle. If the result of every PHI in BB is used > + only by a PHI in DEST, then we can trivially merge the > + PHI nodes from BB into DEST. */ > + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); > + gsi_next (&gsi)) > + { > + gphi *phi = gsi.phi (); > + tree result = gimple_phi_result (phi); > + use_operand_p imm_use; > + gimple *use_stmt; > + > + /* If the PHI's result is never used, then we can just > + ignore it an. */ > + if (has_zero_uses (result)) > + continue; > + > + /* Get the single use of the result of this PHI node. */ > + if (!single_imm_use (result, &imm_use, &use_stmt) > + || gimple_code (use_stmt) != GIMPLE_PHI > + || gimple_bb (use_stmt) != dest > + || gimple_phi_arg_def (use_stmt, dest_idx) != result) > + return false; > + } > + } > + > if (current_loops) > { > /* Protect loop headers. */ > @@ -1247,6 +1284,14 @@ remove_forwarder_block_with_phi (basic_block bb) > basic_block dest = succ->dest; > basic_block dombb, domdest, dom; > > + /* We have to feed into another basic block with PHI > + nodes. */ > + if (gimple_seq_empty_p (phi_nodes (dest)) > + /* We don't want to deal with a basic block with > + abnormal edges. */ > + || bb_has_abnormal_pred (bb)) > + return false; > + > /* Record BB's single pred in case we need to update the father > loop's latch information later. */ > basic_block pred = NULL; > @@ -1429,65 +1474,14 @@ pass_merge_phi::execute (function *fun) > unsigned n = last_basic_block_for_fn (fun); > for (unsigned i = NUM_FIXED_BLOCKS; i < n; i++) > { > - basic_block dest; > basic_block bb = BASIC_BLOCK_FOR_FN (fun, i); > if (!bb) > continue; > > /* Look for a forwarder block with PHI nodes. */ > - if (!tree_forwarder_block_p (bb, true)) > - continue; > - > - dest = single_succ (bb); > - > - /* We have to feed into another basic block with PHI > - nodes. */ > - if (gimple_seq_empty_p (phi_nodes (dest)) > - /* We don't want to deal with a basic block with > - abnormal edges. */ > - || bb_has_abnormal_pred (bb)) > - continue; > - > - /* If BB does not dominate DEST, then the PHI nodes at > - DEST must be the only users of the results of the PHI > - nodes at BB. So only check when BB dominates dest. */ > - if (dominated_by_p (CDI_DOMINATORS, dest, bb)) > - { > - gphi_iterator gsi; > - unsigned int dest_idx = single_succ_edge (bb)->dest_idx; > - > - /* BB dominates DEST. There may be many users of the PHI > - nodes in BB. However, there is still a trivial case we > - can handle. If the result of every PHI in BB is used > - only by a PHI in DEST, then we can trivially merge the > - PHI nodes from BB into DEST. */ > - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); > - gsi_next (&gsi)) > - { > - gphi *phi = gsi.phi (); > - tree result = gimple_phi_result (phi); > - use_operand_p imm_use; > - gimple *use_stmt; > - > - /* If the PHI's result is never used, then we can just > - ignore it. */ > - if (has_zero_uses (result)) > - continue; > - > - /* Get the single use of the result of this PHI node. */ > - if (!single_imm_use (result, &imm_use, &use_stmt) > - || gimple_code (use_stmt) != GIMPLE_PHI > - || gimple_bb (use_stmt) != dest > - || gimple_phi_arg_def (use_stmt, dest_idx) != result) > - break; > - } > - > - /* If the loop above iterated through all the PHI nodes > - in BB, then we can merge the PHIs from BB into DEST. */ > - if (!gsi_end_p (gsi)) > - continue; > - } > - changed |= remove_forwarder_block_with_phi (bb); > + if (tree_forwarder_block_p (bb, true) > + && remove_forwarder_block_with_phi (bb)) > + changed = true; > } > > /* Removing forwarder blocks can cause formerly irreducible loops > -- > 2.43.0 >
