On Tue, May 26, 2015 at 6:48 PM, Aditya Kumar <hiradi...@msn.com> wrote:
> w.r.t. the PR48052, here is the patch which finds out if scev would wrap or 
> not.
> The patch symbolically evaluates if valid_niter >= loop->nb_iterations is 
> true.
> In that case the scev would not wrap.
> Currently, we only look for two special 'patterns', which are sufficient to
> analyze the test cases.
>
> valid_niter = ~s (= UNIT_MAX - s)
>
> We have to prove that valid_niter >= loop->nb_iterations
>
> Pattern1
> loop->nb_iterations: s>= e ? s - e : 0
> In this case we prove that valid_niter >= loop->nb_iterations in both the 
> cases
> i.e., when s >= e and when not.
>
> Pattern2
> loop->nb_iterations: (e - s) -1
> In this case we prove valid_niter >= loop->nb_iterations, by simple analysis 
> that
> UINT_MAXi >= e is true in all cases.
>
> We symbolically evaluate conditionals, and subtraction when additional
> constraints are provided.
>
> Adding this evaluation mechanism helps vectorize some loops on 64bit machines
> because on 64bit, a typecast appears which causes scev to bail out.
>
> This patch passes bootstrap and no additional failures on regression test.

The simplifications look generic and thus belong in fold-const.c fold_comparison
(there may be already code that tries to handle those cases but fails for some
unknown reason - you may want to go through existing simplifications to check
that - some comparison folding is also done directly in fold_binary_loc).

Thanks,
Richard.

> gcc/ChangeLog:
>
> 2015-05-21 Aditya Kumar  <aditya...@samsung.com>
> 2015-05-21 Sebastian Pop  <s....@samsung.com>
> 2015-05-21 Abderrazek Zaafrani <a.zaafr...@samsung.com>
>
>         * gcc.dg/vect/pr48052.c: New test.
>         * tree-ssa-loop-niter.c (fold_binary_cond_p): Fold a conditional 
> operation
>         when additional constraints are available.
>         (fold_binary_minus_p): Fold a subtraction operations of the form (A - 
> B -1)
>         when additional constraints are available.
>         (scev_probably_wraps_p): Use the above two functions to find whether
>         valid_niter>= loop->nb_iterations.
> ---
>  gcc/testsuite/gcc.dg/vect/pr48052.c |  26 +++++++
>  gcc/tree-ssa-loop-niter.c           | 138 
> ++++++++++++++++++++++++++++++++++++
>  2 files changed, 164 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/vect/pr48052.c
>
> diff --git a/gcc/testsuite/gcc.dg/vect/pr48052.c 
> b/gcc/testsuite/gcc.dg/vect/pr48052.c
> new file mode 100644
> index 0000000..534fb54
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/pr48052.c
> @@ -0,0 +1,26 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-O3" } */
> +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" } } */
> +/* { dg-final { cleanup-tree-dump "vect" } } */
> +
> +int foo(int* A, int* B,  unsigned start, unsigned BS)
> +{
> +  int s;
> +  for (unsigned k = start;  k < start + BS; k++)
> +    {
> +      s += A[k] * B[k];
> +    }
> +
> +  return s;
> +}
> +
> +int bar(int* A, int* B, unsigned BS)
> +{
> +  int s;
> +  for (unsigned k = 0;  k < BS; k++)
> +    {
> +      s += A[k] * B[k];
> +    }
> +
> +  return s;
> +}
> diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> index 042f8df..a14f7e5 100644
> --- a/gcc/tree-ssa-loop-niter.c
> +++ b/gcc/tree-ssa-loop-niter.c
> @@ -3773,6 +3773,133 @@ nowrap_type_p (tree type)
>    return false;
>  }
>
> +/* Return true when op0>= op1.
> +   For example:
> +   Where, op0 = ~start_3(D);
> +   op1 = start_3(D) <= stop_6(D) ? stop_6(D) - start_3(D) : 0;
> +   In this case op0 = UINT_MAX - start_3(D);
> +   So, op0>= op1 in all cases because UINT_MAX>= stop_6(D),
> +   when TREE_TYPE(stop_6(D)) == unsigned int;  */
> +bool
> +fold_binary_cond_p (enum tree_code code, tree type, tree op0, tree op1)
> +{
> +  gcc_assert (type == boolean_type_node);
> +
> +  if (TREE_TYPE (op0) != TREE_TYPE (op1))
> +    return false;
> +
> +  /* TODO: Handle other operations.  */
> +  if (code != GE_EXPR)
> +    return false;
> +
> +  /* The type of op0 and op1 should be unsigned.  */
> +  if (!TYPE_UNSIGNED (TREE_TYPE (op0)))
> +    return false;
> +
> +  if ((TREE_CODE (op0) != BIT_NOT_EXPR) || (TREE_CODE (op1) != COND_EXPR))
> +    return false;
> +
> +  /* We have to show that in both the cases,
> +     (when cond is true and when cond is false) op (op0, op1) is true.  */
> +   tree neg_op0 = TREE_OPERAND (op0, 0);
> +   tree cond_op1 = TREE_OPERAND (op1, 0);
> +   tree true_op1 = TREE_OPERAND (op1, 1);
> +   tree false_op1 = TREE_OPERAND (op1, 2);
> +
> +   gcc_assert (neg_op0 && cond_op1 && true_op1 && false_op1);
> +
> +  /* When cond is false.  Evaluate op (op0, false_op1).  */
> +  tree running_exp = fold_binary (code, boolean_type_node, op0, false_op1);
> +
> +  if (running_exp == NULL || integer_zerop (running_exp))
> +    /* TODO: Handle more cases here.  */
> +    return false;
> +
> +  /* When cond is true.  Evaluate op (op0, true_op1).  */
> +  running_exp = fold_binary (code, boolean_type_node, op0, true_op1);
> +
> +  if (running_exp != NULL && integer_nonzerop (running_exp))
> +    return true;
> +
> +  tree smaller, bigger;
> +  if (TREE_CODE (cond_op1) == LE_EXPR)
> +    {
> +      smaller = TREE_OPERAND (cond_op1, 0);
> +      bigger = TREE_OPERAND (cond_op1, 1);
> +    }
> +  else
> +    return false;
> +
> +  if (TREE_CODE (true_op1) == MINUS_EXPR)
> +    {
> +      tree minuend = TREE_OPERAND (true_op1, 0);
> +      tree subtrahend = TREE_OPERAND (true_op1, 1);
> +
> +      if (subtrahend == neg_op0 && subtrahend == smaller && minuend == 
> bigger)
> +       {
> +         tree extreme = upper_bound_in_type (TREE_TYPE (neg_op0),
> +                                             TREE_TYPE (neg_op0));
> +         running_exp = fold_binary (code, boolean_type_node, extreme, 
> minuend);
> +         return running_exp != NULL && integer_nonzerop (running_exp);
> +       }
> +      else
> +       return false;
> +    }
> +  else
> +    return false;
> +}
> +
> +/* Return true when op0>= op1 and
> +   op0 is ~start3(D) or, UINT_MAX - start3(D)
> +   op1 is (_21 - start_3(D)) - 1; */
> +bool
> +fold_binary_minus_p (enum tree_code code, tree type, tree op0, tree op1)
> +{
> +  gcc_assert (type == boolean_type_node);
> +
> +  if (TREE_TYPE (op0) != TREE_TYPE (op1))
> +    return false;
> +
> +  /* TODO: Handle other operations.  */
> +  if (code != GE_EXPR)
> +    return false;
> +
> +  /* The type of op0 and op1 should be unsigned.  */
> +  if (!TYPE_UNSIGNED (TREE_TYPE (op0)))
> +    return false;
> +
> +  if ((TREE_CODE (op0) != BIT_NOT_EXPR) || (TREE_CODE (op1) != MINUS_EXPR))
> +    return false;
> +
> +  /* We have to show that op (op0, op1) is true.  */
> +  tree neg_op0 = TREE_OPERAND (op0, 0);
> +  tree minuend_op1 = TREE_OPERAND (op1, 0);
> +  tree subtrahend_op1 = TREE_OPERAND (op1, 1);
> +
> +  gcc_assert (neg_op0 && subtrahend_op1 && minuend_op1);
> +
> +  /* TODO: Also check that the integer_cst is positive.  */
> +  if (TREE_CODE (minuend_op1) != MINUS_EXPR ||
> +      TREE_CODE (subtrahend_op1) != INTEGER_CST)
> +    return false;
> +
> +  tree minuend_minuend_op1 = TREE_OPERAND (minuend_op1, 0);
> +  tree subtrahend_minuend_op1 = TREE_OPERAND (minuend_op1, 1);
> +
> +  /* TODO: Extend this to evaluate the subtrahends.
> +     i.e., when there are complicated operations in the subtrahend.  */
> +  if (subtrahend_minuend_op1 != neg_op0)
> +    return false;
> +
> +  tree extreme = upper_bound_in_type (TREE_TYPE (neg_op0), TREE_TYPE 
> (neg_op0));
> +  tree compare_minuend = fold_binary (GE_EXPR, boolean_type_node,
> +                                     extreme, minuend_minuend_op1);
> +
> +  if (compare_minuend != NULL && integer_nonzerop (compare_minuend))
> +    return true;
> +  return false;
> +}
> +
>  /* Return false only when the induction variable BASE + STEP * I is
>     known to not overflow: i.e. when the number of iterations is small
>     enough with respect to the step and initial condition in order to
> @@ -3867,6 +3994,17 @@ scev_probably_wraps_p (tree base, tree step,
>        fold_undefer_and_ignore_overflow_warnings ();
>        return false;
>      }
> +
> +  if (loop->nb_iterations && at_stmt
> +      && (fold_binary_cond_p (GE_EXPR, boolean_type_node,
> +                             valid_niter, loop->nb_iterations)
> +         || fold_binary_minus_p (GE_EXPR, boolean_type_node,
> +                                 valid_niter, loop->nb_iterations)))
> +    {
> +      fold_undefer_and_ignore_overflow_warnings ();
> +      return false;
> +    }
> +
>    if (at_stmt)
>      for (bound = loop->bounds; bound; bound = bound->next)
>        {
> --
> 2.1.0.243.g30d45f7
>

Reply via email to