On Wed, 31 Jan 2018, Jakub Jelinek wrote:

> Hi!
> 
> Some spots in the vectorizer create generic COND_EXPRs that in one of the
> branches compute some +/-/* arithmetics.  When -ftrapv, the gimplifier
> ICEs on this as it may trap, we can't emit code with multiple basic blocks
> from the APIs and don't want to evaluate it if the guarding condition is
> false.
> 
> This patch resolves it by making that arithmetic untrappable (i.e. in
> unsigned types).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Wow, yes - we _do_ have absv patterns.  Looks like 
rewrite_to_defined_overflow / arith_code_with_undefined_signed_overflow 
miss handling of ABS_EXPR.  This again reminds me of adding
ABSU_EXPR which would also work nicer for fixing the trapping case.

Anyway, we probably want to postpone this "cleanup" to GCC 9.

I wonder if you actually ran into the case of ABS_EXPR being
passed to rewrite_to_non_trapping_overflow?

Ok for trunk.

Thanks,
Richard.

> 2018-01-31  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/81661
>       PR tree-optimization/84117
>       * tree-eh.h (rewrite_to_non_trapping_overflow): Declare.
>       * tree-eh.c: Include gimplify.h.
>       (find_trapping_overflow, replace_trapping_overflow,
>       rewrite_to_non_trapping_overflow): New functions.
>       * tree-vect-loop.c: Include tree-eh.h.
>       (vect_get_loop_niters): Use rewrite_to_non_trapping_overflow.
>       * tree-data-ref.c: Include tree-eh.h.
>       (get_segment_min_max): Use rewrite_to_non_trapping_overflow.
> 
>       * gcc.dg/pr81661.c: New test.
>       * gfortran.dg/pr84117.f90: New test.
> 
> --- gcc/tree-eh.h.jj  2018-01-03 10:19:54.561533862 +0100
> +++ gcc/tree-eh.h     2018-01-31 11:59:36.328182707 +0100
> @@ -37,6 +37,7 @@ extern bool operation_could_trap_helper_
>                                          bool, tree, bool *);
>  extern bool operation_could_trap_p (enum tree_code, bool, bool, tree);
>  extern bool tree_could_trap_p (tree);
> +extern tree rewrite_to_non_trapping_overflow (tree);
>  extern bool stmt_could_throw_p (gimple *);
>  extern bool tree_could_throw_p (tree);
>  extern bool stmt_can_throw_external (gimple *);
> --- gcc/tree-eh.c.jj  2018-01-03 10:19:56.103534109 +0100
> +++ gcc/tree-eh.c     2018-01-31 16:51:00.726119778 +0100
> @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "asan.h"
> +#include "gimplify.h"
>  
>  /* In some instances a tree and a gimple need to be stored in a same table,
>     i.e. in hash tables. This is a structure to do this. */
> @@ -2720,6 +2721,91 @@ tree_could_trap_p (tree expr)
>      }
>  }
>  
> +/* Return non-NULL if there is an integer operation with trapping overflow
> +   we can rewrite into non-trapping.  Called via walk_tree from
> +   rewrite_to_non_trapping_overflow.  */
> +
> +static tree
> +find_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
> +{
> +  if (EXPR_P (*tp)
> +      && !operation_no_trapping_overflow (TREE_TYPE (*tp), TREE_CODE (*tp)))
> +    return *tp;
> +  if (IS_TYPE_OR_DECL_P (*tp)
> +      || (TREE_CODE (*tp) == SAVE_EXPR && data == NULL))
> +    *walk_subtrees = 0;
> +  return NULL_TREE;
> +}
> +
> +/* Rewrite selected operations into unsigned arithmetics, so that they
> +   don't trap on overflow.  */
> +
> +static tree
> +replace_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
> +{
> +  if (find_trapping_overflow (tp, walk_subtrees, data))
> +    {
> +      tree type = TREE_TYPE (*tp);
> +      tree utype = unsigned_type_for (type);
> +      *walk_subtrees = 0;
> +      int len = TREE_OPERAND_LENGTH (*tp);
> +      for (int i = 0; i < len; ++i)
> +     walk_tree (&TREE_OPERAND (*tp, i), replace_trapping_overflow,
> +                data, (hash_set<tree> *) data);
> +
> +      if (TREE_CODE (*tp) == ABS_EXPR)
> +     {
> +       tree op = TREE_OPERAND (*tp, 0);
> +       op = save_expr (op);
> +       /* save_expr skips simple arithmetics, which is undesirable
> +          here, if it might trap due to flag_trapv.  We need to
> +          force a SAVE_EXPR in the COND_EXPR condition, to evaluate
> +          it before the comparison.  */
> +       if (EXPR_P (op)
> +           && TREE_CODE (op) != SAVE_EXPR
> +           && walk_tree (&op, find_trapping_overflow, NULL, NULL))
> +         {
> +           op = build1_loc (EXPR_LOCATION (op), SAVE_EXPR, type, op);
> +           TREE_SIDE_EFFECTS (op) = 1;
> +         }
> +       /* Change abs (op) to op < 0 ? -op : op and handle the NEGATE_EXPR
> +          like other signed integer trapping operations.  */
> +       tree cond = fold_build2 (LT_EXPR, boolean_type_node,
> +                                op, build_int_cst (type, 0));
> +       tree neg = fold_build1 (NEGATE_EXPR, utype,
> +                               fold_convert (utype, op));
> +       *tp = fold_build3 (COND_EXPR, type, cond,
> +                          fold_convert (type, neg), op);
> +     }
> +      else
> +     {
> +       TREE_TYPE (*tp) = utype;
> +       len = TREE_OPERAND_LENGTH (*tp);
> +       for (int i = 0; i < len; ++i)
> +         TREE_OPERAND (*tp, i)
> +           = fold_convert (utype, TREE_OPERAND (*tp, i));
> +       *tp = fold_convert (type, *tp);
> +     }
> +    }
> +  return NULL_TREE;
> +}
> +
> +/* If any subexpression of EXPR can trap due to -ftrapv, rewrite it
> +   using unsigned arithmetics to avoid traps in it.  */
> +
> +tree
> +rewrite_to_non_trapping_overflow (tree expr)
> +{
> +  if (!flag_trapv)
> +    return expr;
> +  hash_set<tree> pset;
> +  if (!walk_tree (&expr, find_trapping_overflow, &pset, &pset))
> +    return expr;
> +  expr = unshare_expr (expr);
> +  pset.empty ();
> +  walk_tree (&expr, replace_trapping_overflow, &pset, &pset);
> +  return expr;
> +}
>  
>  /* Helper for stmt_could_throw_p.  Return true if STMT (assumed to be a
>     an assignment or a conditional) may throw.  */
> --- gcc/tree-vect-loop.c.jj   2018-01-19 19:41:53.624549770 +0100
> +++ gcc/tree-vect-loop.c      2018-01-31 12:02:02.642190868 +0100
> @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.
>  #include "internal-fn.h"
>  #include "tree-vector-builder.h"
>  #include "vec-perm-indices.h"
> +#include "tree-eh.h"
>  
>  /* Loop Vectorization Pass.
>  
> @@ -1063,7 +1064,8 @@ vect_get_loop_niters (struct loop *loop,
>                                                         may_be_zero));
>         else
>           niter = fold_build3 (COND_EXPR, TREE_TYPE (niter), may_be_zero,
> -                              build_int_cst (TREE_TYPE (niter), 0), niter);
> +                              build_int_cst (TREE_TYPE (niter), 0),
> +                              rewrite_to_non_trapping_overflow (niter));
>  
>         may_be_zero = NULL_TREE;
>       }
> --- gcc/tree-data-ref.c.jj    2018-01-14 17:16:55.614836141 +0100
> +++ gcc/tree-data-ref.c       2018-01-31 12:01:04.836187642 +0100
> @@ -98,6 +98,7 @@ along with GCC; see the file COPYING3.
>  #include "stringpool.h"
>  #include "tree-vrp.h"
>  #include "tree-ssanames.h"
> +#include "tree-eh.h"
>  
>  static struct datadep_stats
>  {
> @@ -1790,7 +1791,8 @@ get_segment_min_max (const dr_with_seg_l
>    tree addr_base = fold_build_pointer_plus (DR_BASE_ADDRESS (d.dr),
>                                           DR_OFFSET (d.dr));
>    addr_base = fold_build_pointer_plus (addr_base, DR_INIT (d.dr));
> -  tree seg_len = fold_convert (sizetype, d.seg_len);
> +  tree seg_len
> +    = fold_convert (sizetype, rewrite_to_non_trapping_overflow (d.seg_len));
>  
>    tree min_reach = fold_build3 (COND_EXPR, sizetype, neg_step,
>                               seg_len, size_zero_node);
> --- gcc/testsuite/gcc.dg/pr81661.c.jj 2018-01-31 12:08:20.457211930 +0100
> +++ gcc/testsuite/gcc.dg/pr81661.c    2018-01-31 12:08:03.723210999 +0100
> @@ -0,0 +1,12 @@
> +/* PR tree-optimization/81661 */
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -ftrapv" } */
> +
> +int a, b, c;
> +
> +void
> +foo (void)
> +{
> +  while (a + c > b)
> +    a--;
> +}
> --- gcc/testsuite/gfortran.dg/pr84117.f90.jj  2018-01-31 12:09:11.305214765 
> +0100
> +++ gcc/testsuite/gfortran.dg/pr84117.f90     2018-01-31 12:09:31.827215918 
> +0100
> @@ -0,0 +1,7 @@
> +! PR tree-optimization/84117
> +! { dg-do compile }
> +! { dg-options "-O3 -ftrapv" }
> +  FUNCTION pw_integral_aa ( cc ) RESULT ( integral_value )
> +    COMPLEX(KIND=8), DIMENSION(:), POINTER :: cc
> +    integral_value = accurate_sum ( CONJG ( cc (:) ) * cc (:) )
> +  END FUNCTION pw_integral_aa
> 
>       Jakub
> 
> 

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

Reply via email to