[PATCH] tree-optimization/102659 - avoid undefined overflow after if-conversion

Richard Biener rguenther@suse.de
Wed Oct 13 11:08:03 GMT 2021


On Wed, 13 Oct 2021, Richard Sandiford wrote:

> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> > The following makes sure to rewrite arithmetic with undefined behavior
> > on overflow to a well-defined variant when moving them to be always
> > executed as part of doing if-conversion for loop vectorization.
> >
> > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> >
> > Any comments?
> 
> LGTM FWIW, although…
> 
> > Thanks,
> > Richard.
> >
> > 2021-10-11  Richard Biener  <rguenther@suse.de>
> >
> > 	PR tree-optimization/102659
> > 	* tree-if-conv.c (need_to_rewrite_undefined): New flag.
> > 	(if_convertible_gimple_assign_stmt_p): Mark the loop for
> > 	rewrite when stmts with undefined behavior on integer
> > 	overflow appear.
> > 	(combine_blocks): Predicate also when we need to rewrite stmts.
> > 	(predicate_statements): Rewrite affected stmts to something
> > 	with well-defined behavior on overflow.
> > 	(tree_if_conversion): Initialize need_to_rewrite_undefined.
> >
> > 	* gcc.dg/torture/pr69760.c: Adjust the testcase.
> > 	* gcc.target/i386/avx2-vect-mask-store-move1.c: Expect to move
> > 	the conversions to unsigned as well.
> > ---
> >  gcc/testsuite/gcc.dg/torture/pr69760.c        |  3 +-
> >  .../i386/avx2-vect-mask-store-move1.c         |  2 +-
> >  gcc/tree-if-conv.c                            | 28 ++++++++++++++++++-
> >  3 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/gcc/testsuite/gcc.dg/torture/pr69760.c b/gcc/testsuite/gcc.dg/torture/pr69760.c
> > index 53733c7c6a4..47e01ae59bd 100644
> > --- a/gcc/testsuite/gcc.dg/torture/pr69760.c
> > +++ b/gcc/testsuite/gcc.dg/torture/pr69760.c
> > @@ -1,11 +1,10 @@
> >  /* PR tree-optimization/69760 */
> >  /* { dg-do run { target { { *-*-linux* *-*-gnu* *-*-uclinux* } && mmap } } } */
> > -/* { dg-options "-O2" } */
> >  
> >  #include <unistd.h>
> >  #include <sys/mman.h>
> >  
> > -__attribute__((noinline, noclone)) void
> > +__attribute__((noinline, noclone)) static void
> >  test_func (double *a, int L, int m, int n, int N)
> >  {
> >    int i, k;
> > diff --git a/gcc/testsuite/gcc.target/i386/avx2-vect-mask-store-move1.c b/gcc/testsuite/gcc.target/i386/avx2-vect-mask-store-move1.c
> > index 989ba402e0e..6a47a09c835 100644
> > --- a/gcc/testsuite/gcc.target/i386/avx2-vect-mask-store-move1.c
> > +++ b/gcc/testsuite/gcc.target/i386/avx2-vect-mask-store-move1.c
> > @@ -78,4 +78,4 @@ avx2_test (void)
> >        abort ();
> >  }
> >  
> > -/* { dg-final { scan-tree-dump-times "Move stmt to created bb" 6 "vect" } } */
> > +/* { dg-final { scan-tree-dump-times "Move stmt to created bb" 10 "vect" } } */
> > diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
> > index d7b7b309309..6a67acfeaae 100644
> > --- a/gcc/tree-if-conv.c
> > +++ b/gcc/tree-if-conv.c
> > @@ -132,6 +132,11 @@ along with GCC; see the file COPYING3.  If not see
> >     predicate_statements for the kinds of predication we support.  */
> >  static bool need_to_predicate;
> >  
> > +/* True if we have to rewrite stmts that may invoke undefined behavior
> > +   when a condition C was false so it doesn't if it is always executed.
> > +   See predicate_statements for the kinds of predication we support.  */
> > +static bool need_to_rewrite_undefined;
> > +
> >  /* Indicate if there are any complicated PHIs that need to be handled in
> >     if-conversion.  Complicated PHI has more than two arguments and can't
> >     be degenerated to two arguments PHI.  See more information in comment
> > @@ -1042,6 +1047,12 @@ if_convertible_gimple_assign_stmt_p (gimple *stmt,
> >  	fprintf (dump_file, "tree could trap...\n");
> >        return false;
> >      }
> > +  else if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
> > +	   && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (lhs))
> > +	   && arith_code_with_undefined_signed_overflow
> > +				(gimple_assign_rhs_code (stmt)))
> > +    /* We have to rewrite stmts with undefined overflow.  */
> > +    need_to_rewrite_undefined = true;
> >  
> >    /* When if-converting stores force versioning, likewise if we
> >       ended up generating store data races.  */
> > @@ -2563,6 +2574,20 @@ predicate_statements (loop_p loop)
> >  
> >  	      gsi_replace (&gsi, new_stmt, true);
> >  	    }
> > +	  else if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt)))
> > +		   && TYPE_OVERFLOW_UNDEFINED
> > +			(TREE_TYPE (gimple_assign_lhs (stmt)))
> > +		   && arith_code_with_undefined_signed_overflow
> > +						(gimple_assign_rhs_code (stmt)))
> > +	    {
> > +	      gsi_remove (&gsi, true);
> > +	      gsi_insert_seq_before (&gsi, rewrite_to_defined_overflow (stmt),
> > +				     GSI_SAME_STMT);
> > +	      if (gsi_end_p (gsi))
> > +		gsi = gsi_last_bb (gimple_bb (stmt));
> > +	      else
> > +		gsi_prev (&gsi);
> 
> …perhaps there should be a GSI_* for this idiom.

Yeah, the issue is that gsi_remove might put gsi to one after the
last stmt (gsi_end_p) which gsi_insert_seq_before happily
handles (insert at the end of the block) but gsi_prev chokes on.

I wonder what GSI_CONTINUE_LINKING would do with gsi_insert[_seq]_before.
Hmm, it puts us at the first stmt inserted which might be OK in this
case but the intention was to put us as the last.  So we could
eventually add GSI_LAST_NEW_STMT or so ;)

I'll see to do that as followup if you think that makes sense.

Note we currently document

enum gsi_iterator_update
{
  GSI_NEW_STMT,         /* Only valid when single statement is added, move
                           iterator to it.  */
  GSI_SAME_STMT,        /* Leave the iterator at the same statement.  */
  GSI_CONTINUE_LINKING  /* Move iterator to whatever position is suitable
                           for linking other statements in the same
                           direction.  */
};

where the "Only valid when single statement" part is a bit odd.  It
seems to consistently point at the earliest inserted stmt (I guess
first/last is a bit confusing and maybe earlierst/latest is better?)

Richard.

> Thanks,
> Richard
> 
> > +	    }
> >  	  else if (gimple_vdef (stmt))
> >  	    {
> >  	      tree lhs = gimple_assign_lhs (stmt);
> > @@ -2647,7 +2672,7 @@ combine_blocks (class loop *loop)
> >    insert_gimplified_predicates (loop);
> >    predicate_all_scalar_phis (loop);
> >  
> > -  if (need_to_predicate)
> > +  if (need_to_predicate || need_to_rewrite_undefined)
> >      predicate_statements (loop);
> >  
> >    /* Merge basic blocks.  */
> > @@ -3148,6 +3173,7 @@ tree_if_conversion (class loop *loop, vec<gimple *> *preds)
> >    rloop = NULL;
> >    ifc_bbs = NULL;
> >    need_to_predicate = false;
> > +  need_to_rewrite_undefined = false;
> >    any_complicated_phi = false;
> >  
> >    /* Apply more aggressive if-conversion when loop or its outer loop were
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


More information about the Gcc-patches mailing list