On Thu, 11 Feb 2016, Jakub Jelinek wrote:

> Hi!
> 
> While the cgraph versioning code is able to deal with clobber stmts that
> refer to SSA_NAMEs set by basic blocks not split into the versioned
> function, and similarly with debug stmts (clobbers refererring to those
> are removed and debug stmts reset), on the main part that doesn't happen,
> because ipa-split makes the split blocks unreachable by jumping around them
> and thus if SSA_NAMEs set in the split basic blocks are referenced
> in return_bb in statements we intentionally ignored for the analysis (debug
> stmts and clobber stmts), we either end up with weird stuff (set debug stmts
> to debug temporary that is set in the basic blocks that are removed as
> dead), or for clobbers ICE.
> 
> Richard has tried to deal with this by throwing away the return_bb in
> certain cases in the main part (forcing recreation of it), but that can
> throw valuable statements that we could have kept (debug stmts or e.g. decl
> clobbers or clobbers that don't need SSA_NAMEs from the split blocks),
> and doesn't work e.g. on the 1st and 3rd testcase below anyway.
> 
> So, this patch reverts the main_part_return_p and instead does
> what is needed for those ignored stmts in return_bb:
> 1) SSA_NAME references to retval in both debug stmts and clobber stmts
>    are replaced with the lhs of the call to *.part.*
> 2) debug stmts referencing other SSA_NAMEs set in the split bbs are reset
> 3) clobber stmts referencing other SSA_NAMEs set in the split bbs are removed
> 
> The testcase hopefully cover all the interesting cases (return_bb copied
> from main part (where it is kept) to split part too, and with debug stmts
> and clobbers that refer to SSA_NAMEs set in main or split part or retval).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok.

Thanks,
Richard.

> 2016-02-11  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR ipa/68672
>       * ipa-split.c (split_function): Don't compute/use main_part_return_p.
>       Compute retval and retbnd early in all cases if split_part_return_p
>       and return_bb is not EXIT.  Remove all clobber stmts and reset
>       all debug stmts that refer to SSA_NAMEs defined in split part,
>       except if it is retval, in that case replace the old retval with the
>       lhs of the call to the split part.
> 
>       * g++.dg/ipa/pr68672-1.C: New test.
>       * g++.dg/ipa/pr68672-2.C: New test.
>       * g++.dg/ipa/pr68672-3.C: New test.
> 
> --- gcc/ipa-split.c.jj        2016-02-11 10:50:52.888220581 +0100
> +++ gcc/ipa-split.c   2016-02-11 12:46:15.975777652 +0100
> @@ -1244,28 +1244,13 @@ split_function (basic_block return_bb, s
>       args_to_pass.safe_push (arg);
>        }
>  
> -  /* See if the split function or the main part will return.  */
> -  bool main_part_return_p = false;
> +  /* See if the split function will return.  */
>    bool split_part_return_p = false;
>    FOR_EACH_EDGE (e, ei, return_bb->preds)
>      {
>        if (bitmap_bit_p (split_point->split_bbs, e->src->index))
>       split_part_return_p = true;
> -      else
> -     main_part_return_p = true;
>      }
> -  /* The main part also returns if we split on a fallthru edge
> -     and the split part returns.  */
> -  if (split_part_return_p)
> -    FOR_EACH_EDGE (e, ei, split_point->entry_bb->preds)
> -      {
> -     if (! bitmap_bit_p (split_point->split_bbs, e->src->index)
> -         && single_succ_p (e->src))
> -       {
> -         main_part_return_p = true;
> -         break;
> -       }
> -      }
>  
>    /* Add return block to what will become the split function.
>       We do not return; no return block is needed.  */
> @@ -1279,8 +1264,8 @@ split_function (basic_block return_bb, s
>       FIXME: Once we are able to change return type, we should change function
>       to return void instead of just outputting function with undefined return
>       value.  For structures this affects quality of codegen.  */
> -  else if (!split_point->split_part_set_retval
> -           && (retval = find_retval (return_bb)))
> +  else if ((retval = find_retval (return_bb))
> +        && !split_point->split_part_set_retval)
>      {
>        bool redirected = true;
>        basic_block new_return_bb = create_basic_block (NULL, 0, return_bb);
> @@ -1308,12 +1293,10 @@ split_function (basic_block return_bb, s
>      }
>    /* When we pass around the value, use existing return block.  */
>    else
> -    bitmap_set_bit (split_point->split_bbs, return_bb->index);
> -
> -  /* If the main part doesn't return pretend the return block wasn't
> -     found for all of the following.  */
> -  if (! main_part_return_p)
> -    return_bb = EXIT_BLOCK_PTR_FOR_FN (cfun);
> +    {
> +      bitmap_set_bit (split_point->split_bbs, return_bb->index);
> +      retbnd = find_retbnd (return_bb);
> +    }
>  
>    /* If RETURN_BB has virtual operand PHIs, they must be removed and the
>       virtual operand marked for renaming as we change the CFG in a way that
> @@ -1382,6 +1365,44 @@ split_function (basic_block return_bb, s
>        DECL_FUNCTION_CODE (node->decl) = (enum built_in_function) 0;
>      }
>  
> +  /* If return_bb contains any clobbers that refer to SSA_NAMEs
> +     set in the split part, remove them.  Also reset debug stmts that
> +     refer to SSA_NAMEs set in the split part.  */
> +  if (return_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
> +    {
> +      gimple_stmt_iterator gsi = gsi_start_bb (return_bb);
> +      while (!gsi_end_p (gsi))
> +     {
> +       tree op;
> +       ssa_op_iter iter;
> +       gimple *stmt = gsi_stmt (gsi);
> +       bool remove = false;
> +       if (gimple_clobber_p (stmt) || is_gimple_debug (stmt))
> +         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
> +           {
> +             basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (op));
> +             if (op != retval
> +                 && bb
> +                 && bb != return_bb
> +                 && bitmap_bit_p (split_point->split_bbs, bb->index))
> +               {
> +                 if (is_gimple_debug (stmt))
> +                   {
> +                     gimple_debug_bind_reset_value (stmt);
> +                     update_stmt (stmt);
> +                   }
> +                 else
> +                   remove = true;
> +                 break;
> +               }
> +           }
> +       if (remove)
> +         gsi_remove (&gsi, true);
> +       else
> +         gsi_next (&gsi);
> +     }
> +    }
> +
>    /* If the original function is instrumented then it's
>       part is also instrumented.  */
>    if (with_bounds)
> @@ -1499,9 +1520,7 @@ split_function (basic_block return_bb, s
>           return value into and put call just before it.  */
>        if (return_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
>       {
> -       real_retval = retval = find_retval (return_bb);
> -       retbnd = find_retbnd (return_bb);
> -
> +       real_retval = retval;
>         if (real_retval && split_point->split_part_set_retval)
>           {
>             gphi_iterator psi;
> @@ -1545,6 +1564,28 @@ split_function (basic_block return_bb, s
>                           break;
>                         }
>                     update_stmt (gsi_stmt (bsi));
> +                   /* Also adjust clobbers and debug stmts in return_bb.  */
> +                   for (bsi = gsi_start_bb (return_bb); !gsi_end_p (bsi);
> +                        gsi_next (&bsi))
> +                     {
> +                       gimple *stmt = gsi_stmt (bsi);
> +                       if (gimple_clobber_p (stmt)
> +                           || is_gimple_debug (stmt))
> +                         {
> +                           ssa_op_iter iter;
> +                           use_operand_p use_p;
> +                           bool update = false;
> +                           FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter,
> +                                                     SSA_OP_USE)
> +                             if (USE_FROM_PTR (use_p) == real_retval)
> +                               {
> +                                 SET_USE (use_p, retval);
> +                                 update = true;
> +                               }
> +                           if (update)
> +                             update_stmt (stmt);
> +                         }
> +                     }
>                   }
>  
>                 /* Replace retbnd with new one.  */
> --- gcc/testsuite/g++.dg/ipa/pr68672-1.C.jj   2016-02-11 12:31:27.344497187 
> +0100
> +++ gcc/testsuite/g++.dg/ipa/pr68672-1.C      2016-02-11 12:31:01.000000000 
> +0100
> @@ -0,0 +1,20 @@
> +// PR ipa/68672
> +// { dg-do compile }
> +// { dg-options "-O -finline-small-functions -fpartial-inlining 
> --param=partial-inlining-entry-probability=100" }
> +
> +void f2 (void *);
> +void *a;
> +struct C { virtual void m1 (); };
> +struct D { C *m2 () { if (a) __builtin_abort (); } };
> +D f1 ();
> +struct E { int e; ~E () { if (e) f2 (&e); } };
> +E *b;
> +struct I { virtual void m3 (); };
> +
> +void
> +I::m3 ()
> +{
> +  if (a)
> +    f1 ().m2 ()->m1 ();
> +  b->~E ();
> +}
> --- gcc/testsuite/g++.dg/ipa/pr68672-2.C.jj   2016-02-11 12:33:50.744438948 
> +0100
> +++ gcc/testsuite/g++.dg/ipa/pr68672-2.C      2016-02-11 12:32:50.000000000 
> +0100
> @@ -0,0 +1,54 @@
> +// PR ipa/68672
> +// { dg-do compile }
> +// { dg-options "-O3 --param=partial-inlining-entry-probability=100 -g" }
> +
> +struct S { ~S () {} };
> +S *a;
> +int *b;
> +void bar ();
> +void baz ();
> +void fn (int *);
> +
> +static int
> +foo ()
> +{
> +  S *c = a;
> +  if (c)
> +    {
> +      bar ();
> +      if (a)
> +     __builtin_abort ();
> +      baz ();
> +    }
> +  int p = *b;
> +  if (p)
> +    {
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +    }
> +  c->~S ();
> +  int q = 2 * p;
> +  int r = 3 * q;
> +  S *d = c;
> +  return p;
> +}
> +
> +void
> +use1 ()
> +{
> +  foo ();
> +}
> +
> +void
> +use2 ()
> +{
> +  foo ();
> +}
> +
> +void
> +use3 ()
> +{
> +  foo ();
> +}
> --- gcc/testsuite/g++.dg/ipa/pr68672-3.C.jj   2016-02-11 12:34:02.374272024 
> +0100
> +++ gcc/testsuite/g++.dg/ipa/pr68672-3.C      2016-02-11 12:34:22.337985482 
> +0100
> @@ -0,0 +1,57 @@
> +// PR ipa/68672
> +// { dg-do compile }
> +// { dg-options "-O3 --param=partial-inlining-entry-probability=100 -g" }
> +
> +struct S { ~S () {} };
> +S *a, *e;
> +int *b;
> +void bar ();
> +void baz ();
> +void fn (int *);
> +void fn2 (S *);
> +
> +static int
> +foo ()
> +{
> +  S *c = a;
> +  if (c)
> +    {
> +      bar ();
> +      if (a)
> +     __builtin_abort ();
> +      baz ();
> +    }
> +  int p = *b;
> +  S *f = e;
> +  if (p)
> +    {
> +      fn2 (f);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +      fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn (b); fn 
> (b); fn (b);
> +    }
> +  f->~S ();
> +  int q = 2 * p;
> +  int r = 3 * q;
> +  S *d = c;
> +  return p;
> +}
> +
> +void
> +use1 ()
> +{
> +  foo ();
> +}
> +
> +void
> +use2 ()
> +{
> +  foo ();
> +}
> +
> +void
> +use3 ()
> +{
> +  foo ();
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to