public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jeff Law <law@redhat.com>
To: Bin Cheng <Bin.Cheng@arm.com>,
	"gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>
Cc: nd <nd@arm.com>
Subject: Re: [PATCH GCC][2/2]Refine CFG and bound information for split loops
Date: Fri, 30 Jun 2017 16:09:00 -0000	[thread overview]
Message-ID: <bc67be58-7bdc-9ef5-a8cc-3973e8944f84@redhat.com> (raw)
In-Reply-To: <VI1PR0802MB21764A3511EE944657C64543E7C30@VI1PR0802MB2176.eurprd08.prod.outlook.com>

On 06/14/2017 07:08 AM, Bin Cheng wrote:
> Hi,
> Loop split currently generates below control flow graph for split loops:
> +
> +               .------ guard1  ------.
> +               v                     v
> +         pre1(loop1)    .---------->pre2(loop2)
> +              |         |            |
> +        .--->h1         |           h2<----.
> +        |     |         |            |     |
> +        |    ex1---.    |       .---ex2    |
> +        |    /     v    |       |     \    |
> +        '---l1 guard2---'       |     l2---'
> +                   |            |
> +                   |            |
> +                   '--->join<---'
> +
> In which,
> +   LOOP2 is the second loop after split, GUARD1 and GUARD2 are the two bbs
> +   controling if loop2 should be executed.
> 
> Take added test case as an example, the second loop only iterates for 1 time,
> as a result, the CFG and loop niter bound information can be refined.  In general,
> guard1/guard2 can be folded to true/false if loop2's niters is known at compilation
> time.  This patch does such improvement by analyzing and refining niters of
> loop2; as well as using that information to simplify CFG.  With this patch,
> the second split loop as in test can be completely unrolled by later passes.
In your testcase the second loop iterates precisely once, right?  In
fact, we know it always executes precisely one time regardless of the
incoming value of LEN.  That's the property you're trying to detect and
exploit, right?


> 
> Bootstrap and test on x86_64 and AArch64.  Is it OK?
> 
> Thanks,
> bin
> 2017-06-12  Bin Cheng  <bin.cheng@arm.com>
> 
> 	* tree-ssa-loop-split.c (compute_new_first_bound): Compute and
> 	return bound information for the second split loop.
> 	(adjust_loop_split): New function.
> 	(split_loop): Update calls to above functions.
> 
> gcc/testsuite/ChangeLog
> 2017-06-12  Bin Cheng  <bin.cheng@arm.com>
> 
> 	* gcc.dg/loop-split-1.c: New test.
> 
> 
> 0002-lsplit-refine-cfg-niter-bound-20170601.txt
> 
> 
> From 61855c74c7db6178008f007198aedee9a03f13e6 Mon Sep 17 00:00:00 2001
> From: amker <amker@amker-laptop.(none)>
> Date: Sun, 4 Jun 2017 02:26:34 +0800
> Subject: [PATCH 2/2] lsplit-refine-cfg-niter-bound-20170601.txt
> 
> ---
>  gcc/testsuite/gcc.dg/loop-split-1.c |  16 +++
>  gcc/tree-ssa-loop-split.c           | 197 ++++++++++++++++++++++++++++++++----
>  2 files changed, 194 insertions(+), 19 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/loop-split-1.c
> 
> diff --git a/gcc/tree-ssa-loop-split.c b/gcc/tree-ssa-loop-split.c
> index f8fe8e6..73c7dc2 100644
> --- a/gcc/tree-ssa-loop-split.c
> +++ b/gcc/tree-ssa-loop-split.c
> @@ -387,28 +386,41 @@ connect_loops (struct loop *loop1, struct loop *loop2)
>  
>     Depending on the direction of the IVs and if the exit tests
>     are strict or non-strict we need to use MIN or MAX,
> -   and add or subtract 1.  This routine computes newend above.  */
> +   and add or subtract 1.  This routine computes newend above.
> +
> +   After computing the new bound (on j), we may be able to compare the
> +   first loop's iteration space against the original loop's.  If it is
> +   comparable at compilation time, we may be able to compute the niter
> +   bound of the second loop.  Record the second loop's iteration bound
> +   to SECOND_LOOP_NITER_BOUND which has below meaning:
> +
> +     -3: Don't know anything about the second loop;
> +     -2: The second loop must not be executed;
> +     -1: The second loop must be executed, but niter bound is unknown;
> +      n: The second loop must be executed, niter bound is n (>= 0);
> +
> +   Note we compute niter bound for the second loop's latch.  */
How hard would it be to have a test for each of the 4 cases above?  I
don't always ask for this, but ISTM this is a good chance to make sure
most of the new code gets covered by testing.

Does case -2 really occur in practice or are you just being safe?  ISTM
that if case -2 occurs then the loop shouldn't have been split to begin
with.  If this happens in practice, do we clean up all the dead code if
the bounds are set properly.

Similarly for N = 0, presumably meaning the second loop iterates exactly
once, but never traverses its backedge, is there any value in changing
the loop latch test so that it's always false?  Or will that get cleaned
up later?


>  
>  static tree
> -compute_new_first_bound (gimple_seq *stmts, struct tree_niter_desc *niter,
> -			 tree border,
> -			 enum tree_code guard_code, tree guard_init)
> +compute_new_first_bound (struct tree_niter_desc *niter, tree border,
> +			 enum tree_code guard_code, tree guard_init,
> +			 tree step, HOST_WIDE_INT *second_loop_niter_bound)
>  {
> -  /* The niter structure contains the after-increment IV, we need
> -     the loop-enter base, so subtract STEP once.  */
>    tree controlbase = niter->control.base;
>    tree controlstep = niter->control.step;
>    tree enddiff, end = niter->bound;
>    tree type;
>  
> -  /* Compute end-beg.  */
> +  /* Compute end-beg.
> +     Note the niter structure contains the after-increment IV, we need the
> +     loop-enter base, so subtract STEP once.  */
>    if (POINTER_TYPE_P (TREE_TYPE (controlbase)))
>      {
>        controlstep = fold_build1 (NEGATE_EXPR,
>  				 TREE_TYPE (controlstep), controlstep);
>        enddiff = fold_build_pointer_plus (controlbase, controlstep);
>  
> -      type = unsigned_type_for (enddiff);
> +      type = unsigned_type_for (TREE_TYPE (enddiff));
Isn't this an indication the trunk sources are broken?  Consider pushing
this forward independent of the rest of this change if it looks like
we're going to have to iterate more than once or twice.



> @@ -462,8 +476,148 @@ compute_new_first_bound (gimple_seq *stmts, struct tree_niter_desc *niter,
>  			      build_int_cst (type, addbound));
>      }
>  
> -  newbound = fold_build2 (minmax, TREE_TYPE (border), border, newbound);
> -  return force_gimple_operand (newbound, stmts, true, NULL_TREE);
> +  tree cmp_rslt = fold_build2 (cmp_code, boolean_type_node, border, newbound);
> +  /* Only handle simple case with unit step.  */
> +  if (wi::eq_p (wi::abs (step), 1)
> +      && cmp_rslt != NULL_TREE && integer_nonzerop (cmp_rslt))
> +    {
> +      if (integer_nonzerop (cmp_rslt))
> +	{
> +	  tree niter_type, diff;
> +
> +	  niter_type = unsigned_type_for (TREE_TYPE (newbound));
> +	  /* The split condition indicates smaller iteration space than the
> +	     original loop, so the second loop must be executed.  */
> +	  if (cmp_code == LT_EXPR)
> +	    diff = fold_build2 (MINUS_EXPR, niter_type,
> +				fold_convert (niter_type, newbound),
> +				fold_convert (niter_type, border));
> +	  else
> +	    diff = fold_build2 (MINUS_EXPR, niter_type,
> +				fold_convert (niter_type, border),
> +				fold_convert (niter_type, newbound));
> +
> +	  /* Check if niter can be computed.  */
> +	  if (tree_fits_shwi_p (diff) && !tree_int_cst_sign_bit (diff))
> +	    *second_loop_niter_bound = tree_to_shwi (diff) - 1;
> +	  else
> +	    *second_loop_niter_bound = -1;
> +
> +	  return border;
> +	}
> +      else if (integer_zerop (cmp_rslt))
> +	{
> +	  /* The split condition indicates larger iteration space than the
> +	     oiginal loop, so the second loop must not be executed.  */
s/oiginal/original/


Overall I like it and it looks reasonably close to being ready.   Let's
get the answers to the few questions above and decide how to move
forward after that.

Thanks,

Jeff

  parent reply	other threads:[~2017-06-30 16:09 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-14 13:08 Bin Cheng
2017-06-14 16:05 ` Bernhard Reutner-Fischer
2017-06-30 16:09 ` Jeff Law [this message]
2017-07-04 15:13   ` Bin.Cheng

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=bc67be58-7bdc-9ef5-a8cc-3973e8944f84@redhat.com \
    --to=law@redhat.com \
    --cc=Bin.Cheng@arm.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=nd@arm.com \
    /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).