public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Biener <rguenther@suse.de>
To: gcc-patches@gcc.gnu.org
Cc: Jan Hubicka <hubicka@ucw.cz>
Subject: Re: [PATCH] unswitch most profitable condition first
Date: Mon, 7 Nov 2022 08:59:15 +0000 (UTC)	[thread overview]
Message-ID: <nycvar.YFH.7.77.849.2211070859070.4294@jbgna.fhfr.qr> (raw)

On Tue, 25 Oct 2022, Richard Biener wrote:

> When doing the loop unswitching re-org we promised to followup
> with improvements on the cost modeling.  The following makes sure we
> try to unswitch on the most profitable condition first.  As most profitable
> we pick the condition leading to the edge with the highest profile count.
> 
> Note the profile is only applied when picking the first unswitching
> opportunity since the profile counts are not updated with earlier
> unswitchings in mind.  Further opportunities are picked in DFS order.
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
> 
> Any comments?

I have now pushed this.

Richard.

> Thanks,
> Richard.
> 
> 	* tree-ssa-loop-unswitch.cc (unswitch_predicate::count): New.
> 	(unswitch_predicate::unswitch_predicate): Initialize count.
> 	(init_loop_unswitch_info): First collect candidates and
> 	determine the outermost loop to unswitch.
> 	(tree_ssa_unswitch_loops): First perform all guard hoisting,
> 	then perform unswitching on innermost loop predicates.
> 	(find_unswitching_predicates_for_bb): Keep track of the
> 	most profitable predicate to unswitch on.
> 	(tree_unswitch_single_loop): Unswitch given predicate if
> 	not NULL.
> ---
>  gcc/tree-ssa-loop-unswitch.cc | 66 ++++++++++++++++++++++++++++-------
>  1 file changed, 54 insertions(+), 12 deletions(-)
> 
> diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc
> index 7d6781d1505..dfe75f52f12 100644
> --- a/gcc/tree-ssa-loop-unswitch.cc
> +++ b/gcc/tree-ssa-loop-unswitch.cc
> @@ -118,6 +118,7 @@ struct unswitch_predicate
>      if (!false_range.varying_p ()
>  	&& !false_range.undefined_p ())
>        false_range.invert ();
> +    count = e->count ();
>      num = predicates->length ();
>      predicates->safe_push (this);
>    }
> @@ -126,7 +127,8 @@ struct unswitch_predicate
>    unswitch_predicate (gcond *stmt)
>      : switch_p (false)
>    {
> -    if (EDGE_SUCC (gimple_bb (stmt), 0)->flags & EDGE_TRUE_VALUE)
> +    basic_block bb = gimple_bb (stmt);
> +    if (EDGE_SUCC (bb, 0)->flags & EDGE_TRUE_VALUE)
>        edge_index = 0;
>      else
>        edge_index = 1;
> @@ -134,6 +136,7 @@ struct unswitch_predicate
>      tree rhs = gimple_cond_rhs (stmt);
>      enum tree_code code = gimple_cond_code (stmt);
>      condition = build2 (code, boolean_type_node, lhs, rhs);
> +    count = EDGE_SUCC (bb, 0)->count ().max (EDGE_SUCC (bb, 1)->count ());
>      if (irange::supports_p (TREE_TYPE (lhs)))
>        {
>  	auto range_op = range_op_handler (code, TREE_TYPE (lhs));
> @@ -180,6 +183,9 @@ struct unswitch_predicate
>    /* Index of the edge the predicate belongs to in the successor vector.  */
>    int edge_index;
>  
> +  /* The profile count of this predicate.  */
> +  profile_count count;
> +
>    /* Whether the predicate was created from a switch statement.  */
>    bool switch_p;
>  
> @@ -206,10 +212,14 @@ static class loop *tree_unswitch_loop (class loop *, edge, tree);
>  static bool tree_unswitch_single_loop (class loop *, dump_user_location_t,
>  				       predicate_vector &predicate_path,
>  				       unsigned loop_size, unsigned &budget,
> -				       int ignored_edge_flag, bitmap);
> +				       int ignored_edge_flag, bitmap,
> +				       unswitch_predicate * = NULL,
> +				       basic_block = NULL);
>  static void
>  find_unswitching_predicates_for_bb (basic_block bb, class loop *loop,
> -				    vec<unswitch_predicate *> &candidates);
> +				    vec<unswitch_predicate *> &candidates,
> +				    unswitch_predicate *&hottest,
> +				    basic_block &hottest_bb);
>  static bool tree_unswitch_outer_loop (class loop *);
>  static edge find_loop_guard (class loop *, vec<gimple *>&);
>  static bool empty_bb_without_guard_p (class loop *, basic_block,
> @@ -242,7 +252,8 @@ set_predicates_for_bb (basic_block bb, vec<unswitch_predicate *> predicates)
>     Return total number of instructions in the loop.  */
>  
>  static unsigned
> -init_loop_unswitch_info (class loop *loop)
> +init_loop_unswitch_info (class loop *loop, unswitch_predicate *&hottest,
> +			 basic_block &hottest_bb)
>  {
>    unsigned total_insns = 0;
>  
> @@ -259,13 +270,16 @@ init_loop_unswitch_info (class loop *loop)
>        total_insns += insns;
>      }
>  
> +  hottest = NULL;
> +  hottest_bb = NULL;
>    /* Find all unswitching candidates.  */
>    for (unsigned i = 0; i != loop->num_nodes; i++)
>      {
>        /* Find a bb to unswitch on.  */
>        vec<unswitch_predicate *> candidates;
>        candidates.create (1);
> -      find_unswitching_predicates_for_bb (bbs[i], loop, candidates);
> +      find_unswitching_predicates_for_bb (bbs[i], loop, candidates,
> +					  hottest, hottest_bb);
>        if (!candidates.is_empty ())
>  	set_predicates_for_bb (bbs[i], candidates);
>        else
> @@ -329,7 +343,10 @@ tree_ssa_unswitch_loops (function *fun)
>  	  unswitch_predicate::predicates = new vec<unswitch_predicate *> ();
>  
>  	  /* Unswitch innermost loop.  */
> -	  unsigned int loop_size = init_loop_unswitch_info (loop);
> +	  unswitch_predicate *hottest;
> +	  basic_block hottest_bb;
> +	  unsigned int loop_size = init_loop_unswitch_info (loop, hottest,
> +							    hottest_bb);
>  	  unsigned int budget = loop_size + param_max_unswitch_insns;
>  
>  	  predicate_vector predicate_path;
> @@ -338,7 +355,8 @@ tree_ssa_unswitch_loops (function *fun)
>  	  changed_unswitch
>  	    |= tree_unswitch_single_loop (loop, loc, predicate_path,
>  					  loop_size, budget,
> -					  ignored_edge_flag, handled);
> +					  ignored_edge_flag, handled,
> +					  hottest, hottest_bb);
>  	  predicate_path.release ();
>  
>  	  for (auto predlist : bb_predicates)
> @@ -449,7 +467,9 @@ is_maybe_undefined (const tree name, gimple *stmt, class loop *loop)
>  
>  static void
>  find_unswitching_predicates_for_bb (basic_block bb, class loop *loop,
> -				    vec<unswitch_predicate *> &candidates)
> +				    vec<unswitch_predicate *> &candidates,
> +				    unswitch_predicate *&hottest,
> +				    basic_block &hottest_bb)
>  {
>    gimple *last, *def;
>    tree use;
> @@ -489,6 +509,14 @@ find_unswitching_predicates_for_bb (basic_block bb, class loop *loop,
>  
>        unswitch_predicate *predicate = new unswitch_predicate (stmt);
>        candidates.safe_push (predicate);
> +      /* If we unswitch on this predicate we isolate both paths, so
> +	 pick the highest count for updating of the hottest predicate
> +	 to unswitch on first.  */
> +      if (!hottest || predicate->count > hottest->count)
> +	{
> +	  hottest = predicate;
> +	  hottest_bb = bb;
> +	}
>      }
>    else if (gswitch *stmt = safe_dyn_cast <gswitch *> (last))
>      {
> @@ -561,6 +589,11 @@ find_unswitching_predicates_for_bb (basic_block bb, class loop *loop,
>  					  edge_index, e,
>  					  edge_range[edge_index]);
>  	      candidates.safe_push (predicate);
> +	      if (!hottest || predicate->count > hottest->count)
> +		{
> +		  hottest = predicate;
> +		  hottest_bb = bb;
> +		}
>  	    }
>  	}
>      }
> @@ -888,13 +921,15 @@ evaluate_loop_insns_for_predicate (class loop *loop,
>  
>  /* Unswitch single LOOP.  PREDICATE_PATH contains so far used predicates
>     for unswitching.  BUDGET is number of instruction for which we can increase
> -   the loop and is updated when unswitching occurs.  */
> +   the loop and is updated when unswitching occurs.  If HOTTEST is not
> +   NULL then pick this candidate as the one to unswitch on.  */
>  
>  static bool
>  tree_unswitch_single_loop (class loop *loop, dump_user_location_t loc,
>  			   predicate_vector &predicate_path,
>  			   unsigned loop_size, unsigned &budget,
> -			   int ignored_edge_flag, bitmap handled)
> +			   int ignored_edge_flag, bitmap handled,
> +			   unswitch_predicate *hottest, basic_block hottest_bb)
>  {
>    class loop *nloop;
>    bool changed = false;
> @@ -939,8 +974,15 @@ tree_unswitch_single_loop (class loop *loop, dump_user_location_t loc,
>  	}
>        return false;
>      };
> -  /* Check predicates of reachable blocks.  */
> -  evaluate_bbs (loop, NULL, ignored_edge_flag, check_predicates);
> +
> +  if (hottest)
> +    {
> +      predicate = hottest;
> +      predicate_bb = hottest_bb;
> +    }
> +  else
> +    /* Check predicates of reachable blocks.  */
> +    evaluate_bbs (loop, NULL, ignored_edge_flag, check_predicates);
>  
>    if (predicate != NULL)
>      {
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

             reply	other threads:[~2022-11-07  8:59 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-07  8:59 Richard Biener [this message]
  -- strict thread matches above, loose matches on Subject: below --
2022-10-25 13:09 Richard Biener

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=nycvar.YFH.7.77.849.2211070859070.4294@jbgna.fhfr.qr \
    --to=rguenther@suse.de \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=hubicka@ucw.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).