Refactor range handling of builtins in vr_values and ranger.
authorAldy Hernandez <aldyh@redhat.com>
Fri, 9 Oct 2020 09:26:33 +0000 (11:26 +0200)
committerAldy Hernandez <aldyh@redhat.com>
Tue, 20 Oct 2020 16:21:23 +0000 (18:21 +0200)
This sets things up so we can share range handling of builtins between
vr_values and ranger.  It is meant to refactor the code so that we can
verify that both implementations yield the same results.

First, we abstract out gimple_ranger::range_of_builtin_call into an externally
visible counterpart that can be called from vr_values.  It will take a
range_query since both ranger and vr_values inherit from this base class.

Then we abstract out all the builtin handling in vr_values into a separate
method that is easier to compare against.

Finally, we call the ranger version from vr_values and compare it with the
vr_values version.  Since this proves both versions return the same,
we can remove vr_values::extract_range_builtin in a follow-up patch.

The vr_values::range_of_expr change brings the vr_values version up to par
with the ranger version.  It should've handled non-SSA's.  This was
a small oversight that went unnoticed because the vr_value version isn't
stressed nearly as much as the ranger version.  The change is needed because
the ranger code handling builtins calls, may call it for integer arguments
in range_of_builtin_ubsan_call.

There should be no change in functionality.

gcc/ChangeLog:

* gimple-range.cc (gimple_ranger::range_of_builtin_ubsan_call):
Make externally visble...
(range_of_builtin_ubsan_call): ...here.  Add range_query argument.
(gimple_ranger::range_of_builtin_call): Make externally visible...
(range_of_builtin_call): ...here.  Add range_query argument.
* gimple-range.h (range_of_builtin_call): Move out from class and
make externally visible.
* vr-values.c (vr_values::extract_range_basic): Abstract out
builtin handling to...
(vr_values::range_of_expr): Handle non SSAs.
(vr_values::extract_range_builtin): ...here.
* vr-values.h (class vr_values): Add extract_range_builtin.
(range_of_expr): Rename NAME to EXPR.

gcc/gimple-range.cc
gcc/gimple-range.h
gcc/vr-values.c
gcc/vr-values.h

index ed9609b..b790d62 100644 (file)
@@ -552,10 +552,13 @@ gimple_ranger::range_of_call (irange &r, gcall *call)
   return true;
 }
 
+// Return the range of a __builtin_ubsan* in CALL and set it in R.
+// CODE is the type of ubsan call (PLUS_EXPR, MINUS_EXPR or
+// MULT_EXPR).
 
-void
-gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
-                                           tree_code code)
+static void
+range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
+                            tree_code code)
 {
   gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
                       || code == MULT_EXPR);
@@ -565,8 +568,8 @@ gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
   int_range_max ir0, ir1;
   tree arg0 = gimple_call_arg (call, 0);
   tree arg1 = gimple_call_arg (call, 1);
-  gcc_assert (range_of_expr (ir0, arg0, call));
-  gcc_assert (range_of_expr (ir1, arg1, call));
+  gcc_assert (query.range_of_expr (ir0, arg0, call));
+  gcc_assert (query.range_of_expr (ir1, arg1, call));
 
   bool saved_flag_wrapv = flag_wrapv;
   // Pretend the arithmetic is wrapping.  If there is any overflow,
@@ -582,9 +585,11 @@ gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
     r.set_varying (type);
 }
 
+// For a builtin in CALL, return a range in R if known and return
+// TRUE.  Otherwise return FALSE.
 
 bool
-gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
+range_of_builtin_call (range_query &query, irange &r, gcall *call)
 {
   combined_fn func = gimple_call_combined_fn (call);
   if (func == CFN_LAST)
@@ -605,7 +610,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
          return true;
        }
       arg = gimple_call_arg (call, 0);
-      if (range_of_expr (r, arg, call) && r.singleton_p ())
+      if (query.range_of_expr (r, arg, call) && r.singleton_p ())
        {
          r.set (build_one_cst (type), build_one_cst (type));
          return true;
@@ -619,7 +624,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
       prec = TYPE_PRECISION (TREE_TYPE (arg));
       mini = 0;
       maxi = prec;
-      gcc_assert (range_of_expr (r, arg, call));
+      gcc_assert (query.range_of_expr (r, arg, call));
       // If arg is non-zero, then ffs or popcount are non-zero.
       if (!range_includes_zero_p (&r))
        mini = 1;
@@ -663,7 +668,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
            }
        }
 
-      gcc_assert (range_of_expr (r, arg, call));
+      gcc_assert (query.range_of_expr (r, arg, call));
       // From clz of minimum we can compute result maximum.
       if (r.constant_p ())
        {
@@ -728,7 +733,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
                mini = -2;
            }
        }
-      gcc_assert (range_of_expr (r, arg, call));
+      gcc_assert (query.range_of_expr (r, arg, call));
       if (!r.undefined_p ())
        {
          if (r.lower_bound () != 0)
@@ -766,13 +771,13 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
       r.set (build_int_cst (type, 0), build_int_cst (type, prec - 1));
       return true;
     case CFN_UBSAN_CHECK_ADD:
-      range_of_builtin_ubsan_call (r, call, PLUS_EXPR);
+      range_of_builtin_ubsan_call (query, r, call, PLUS_EXPR);
       return true;
     case CFN_UBSAN_CHECK_SUB:
-      range_of_builtin_ubsan_call (r, call, MINUS_EXPR);
+      range_of_builtin_ubsan_call (query, r, call, MINUS_EXPR);
       return true;
     case CFN_UBSAN_CHECK_MUL:
-      range_of_builtin_ubsan_call (r, call, MULT_EXPR);
+      range_of_builtin_ubsan_call (query, r, call, MULT_EXPR);
       return true;
 
     case CFN_GOACC_DIM_SIZE:
@@ -822,6 +827,11 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
 }
 
 
+bool
+gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
+{
+  return ::range_of_builtin_call (*this, r, call);
+}
 
 // Calculate a range for COND_EXPR statement S and return it in R.
 // If a range cannot be calculated, return false.
index a6e8793..0aa6d46 100644 (file)
@@ -64,7 +64,6 @@ private:
   bool range_of_phi (irange &r, gphi *phi);
   bool range_of_non_trivial_assignment (irange &r, gimple *s);
   bool range_of_builtin_call (irange &r, gcall *call);
-  void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code);
   bool range_with_loop_info (irange &r, tree name);
   void range_of_ssa_name_with_loop_info (irange &, tree, class loop *,
                                         gphi *);
@@ -179,4 +178,7 @@ private:
 // Flag to enable debugging the various internal Caches.
 #define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG))
 
+// Temporary external interface to share with vr_values.
+bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
+
 #endif // GCC_GIMPLE_RANGE_STMT_H
index e917704..11beef8 100644 (file)
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "vr-values.h"
 #include "cfghooks.h"
 #include "range-op.h"
+#include "gimple-range.h"
 
 /* Set value range VR to a non-negative range of type TYPE.  */
 
@@ -174,9 +175,12 @@ vr_values::get_value_range (const_tree var,
 }
 
 bool
-vr_values::range_of_expr (irange &r, tree name, gimple *stmt)
+vr_values::range_of_expr (irange &r, tree expr, gimple *stmt)
 {
-  if (const value_range *vr = get_value_range (name, stmt))
+  if (!gimple_range_ssa_p (expr))
+    return get_tree_range (r, expr);
+
+  if (const value_range *vr = get_value_range (expr, stmt))
     {
       if (vr->undefined_p () || vr->varying_p () || vr->constant_p ())
        r = *vr;
@@ -1151,271 +1155,289 @@ check_for_binary_op_overflow (range_query *query,
   return true;
 }
 
-/* Try to derive a nonnegative or nonzero range out of STMT relying
-   primarily on generic routines in fold in conjunction with range data.
-   Store the result in *VR */
+/* Derive a range from a builtin.  Set range in VR and return TRUE if
+   successful.  */
 
-void
-vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
+bool
+vr_values::extract_range_builtin (value_range_equiv *vr, gimple *stmt)
 {
-  bool sop;
+  gcc_assert (is_gimple_call (stmt));
   tree type = gimple_expr_type (stmt);
+  tree arg;
+  int mini, maxi, zerov = 0, prec;
+  enum tree_code subcode = ERROR_MARK;
+  combined_fn cfn = gimple_call_combined_fn (stmt);
+  scalar_int_mode mode;
 
-  if (is_gimple_call (stmt))
+  switch (cfn)
     {
-      tree arg;
-      int mini, maxi, zerov = 0, prec;
-      enum tree_code subcode = ERROR_MARK;
-      combined_fn cfn = gimple_call_combined_fn (stmt);
-      scalar_int_mode mode;
-
-      switch (cfn)
+    case CFN_BUILT_IN_CONSTANT_P:
+      /* Resolve calls to __builtin_constant_p after inlining.  */
+      if (cfun->after_inlining)
        {
-       case CFN_BUILT_IN_CONSTANT_P:
-         /* Resolve calls to __builtin_constant_p after inlining.  */
-         if (cfun->after_inlining)
-           {
-             vr->set_zero (type);
-             vr->equiv_clear ();
-             return;
-           }
-         break;
-         /* Both __builtin_ffs* and __builtin_popcount return
-            [0, prec].  */
-       CASE_CFN_FFS:
-       CASE_CFN_POPCOUNT:
-         arg = gimple_call_arg (stmt, 0);
-         prec = TYPE_PRECISION (TREE_TYPE (arg));
-         mini = 0;
-         maxi = prec;
-         if (TREE_CODE (arg) == SSA_NAME)
+         vr->set_zero (type);
+         vr->equiv_clear ();
+         return true;
+       }
+      break;
+      /* Both __builtin_ffs* and __builtin_popcount return
+        [0, prec].  */
+    CASE_CFN_FFS:
+    CASE_CFN_POPCOUNT:
+      arg = gimple_call_arg (stmt, 0);
+      prec = TYPE_PRECISION (TREE_TYPE (arg));
+      mini = 0;
+      maxi = prec;
+      if (TREE_CODE (arg) == SSA_NAME)
+       {
+         const value_range_equiv *vr0 = get_value_range (arg);
+         /* If arg is non-zero, then ffs or popcount are non-zero.  */
+         if (range_includes_zero_p (vr0) == 0)
+           mini = 1;
+         /* If some high bits are known to be zero,
+            we can decrease the maximum.  */
+         if (vr0->kind () == VR_RANGE
+             && TREE_CODE (vr0->max ()) == INTEGER_CST
+             && !operand_less_p (vr0->min (),
+                                 build_zero_cst (TREE_TYPE (vr0->min ()))))
+           maxi = tree_floor_log2 (vr0->max ()) + 1;
+       }
+      goto bitop_builtin;
+      /* __builtin_parity* returns [0, 1].  */
+    CASE_CFN_PARITY:
+      mini = 0;
+      maxi = 1;
+      goto bitop_builtin;
+      /* __builtin_clz* return [0, prec-1], except for
+        when the argument is 0, but that is undefined behavior.
+        Always handle __builtin_clz* which can be only written
+        by user as UB on 0 and so [0, prec-1] range, and the internal-fn
+        calls depending on how CLZ_DEFINED_VALUE_AT_ZERO is defined.  */
+    CASE_CFN_CLZ:
+      arg = gimple_call_arg (stmt, 0);
+      prec = TYPE_PRECISION (TREE_TYPE (arg));
+      mini = 0;
+      maxi = prec - 1;
+      mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
+      if (gimple_call_internal_p (stmt))
+       {
+         if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
+             && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
            {
-             const value_range_equiv *vr0 = get_value_range (arg);
-             /* If arg is non-zero, then ffs or popcount are non-zero.  */
-             if (range_includes_zero_p (vr0) == 0)
-               mini = 1;
-             /* If some high bits are known to be zero,
-                we can decrease the maximum.  */
-             if (vr0->kind () == VR_RANGE
-                 && TREE_CODE (vr0->max ()) == INTEGER_CST
-                 && !operand_less_p (vr0->min (),
-                                     build_zero_cst (TREE_TYPE (vr0->min ()))))
-               maxi = tree_floor_log2 (vr0->max ()) + 1;
+             /* Handle only the single common value.  */
+             if (zerov == prec)
+               maxi = prec;
+             /* Magic value to give up, unless vr0 proves
+                arg is non-zero.  */
+             else
+               mini = -2;
            }
-         goto bitop_builtin;
-         /* __builtin_parity* returns [0, 1].  */
-       CASE_CFN_PARITY:
-         mini = 0;
-         maxi = 1;
-         goto bitop_builtin;
-         /* __builtin_clz* return [0, prec-1], except for
-            when the argument is 0, but that is undefined behavior.
-            Always handle __builtin_clz* which can be only written
-            by user as UB on 0 and so [0, prec-1] range, and the internal-fn
-            calls depending on how CLZ_DEFINED_VALUE_AT_ZERO is defined.  */
-       CASE_CFN_CLZ:
-         arg = gimple_call_arg (stmt, 0);
-         prec = TYPE_PRECISION (TREE_TYPE (arg));
-         mini = 0;
-         maxi = prec - 1;
-         mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-         if (gimple_call_internal_p (stmt))
+       }
+      if (TREE_CODE (arg) == SSA_NAME)
+       {
+         const value_range_equiv *vr0 = get_value_range (arg);
+         /* From clz of VR_RANGE minimum we can compute
+            result maximum.  */
+         if (vr0->kind () == VR_RANGE
+             && TREE_CODE (vr0->min ()) == INTEGER_CST
+             && integer_nonzerop (vr0->min ()))
            {
-             if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
-                 && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
-               {
-                 /* Handle only the single common value.  */
-                 if (zerov == prec)
-                   maxi = prec;
-                 /* Magic value to give up, unless vr0 proves
-                    arg is non-zero.  */
-                 else
-                   mini = -2;
-               }
+             maxi = prec - 1 - tree_floor_log2 (vr0->min ());
+             if (mini == -2)
+               mini = 0;
            }
-         if (TREE_CODE (arg) == SSA_NAME)
+         else if (vr0->kind () == VR_ANTI_RANGE
+                  && integer_zerop (vr0->min ()))
            {
-             const value_range_equiv *vr0 = get_value_range (arg);
-             /* From clz of VR_RANGE minimum we can compute
-                result maximum.  */
-             if (vr0->kind () == VR_RANGE
-                 && TREE_CODE (vr0->min ()) == INTEGER_CST
-                 && integer_nonzerop (vr0->min ()))
-               {
-                 maxi = prec - 1 - tree_floor_log2 (vr0->min ());
-                 if (mini == -2)
-                   mini = 0;
-               }
-             else if (vr0->kind () == VR_ANTI_RANGE
-                      && integer_zerop (vr0->min ()))
-               {
-                 maxi = prec - 1;
-                 mini = 0;
-               }
-             if (mini == -2)
-               break;
-             /* From clz of VR_RANGE maximum we can compute
-                result minimum.  */
-             if (vr0->kind () == VR_RANGE
-                 && TREE_CODE (vr0->max ()) == INTEGER_CST)
-               {
-                 int newmini = prec - 1 - tree_floor_log2 (vr0->max ());
-                 if (newmini == prec)
-                   {
-                     if (maxi == prec)
-                       mini = prec;
-                   }
-                 else
-                   mini = newmini;
-               }
+             maxi = prec - 1;
+             mini = 0;
            }
          if (mini == -2)
            break;
-         goto bitop_builtin;
-         /* __builtin_ctz* return [0, prec-1], except for
-            when the argument is 0, but that is undefined behavior.
-            Always handle __builtin_ctz* which can be only written
-            by user as UB on 0 and so [0, prec-1] range, and the internal-fn
-            calls depending on how CTZ_DEFINED_VALUE_AT_ZERO is defined.  */
-       CASE_CFN_CTZ:
-         arg = gimple_call_arg (stmt, 0);
-         prec = TYPE_PRECISION (TREE_TYPE (arg));
-         mini = 0;
-         maxi = prec - 1;
-         mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-         if (gimple_call_internal_p (stmt))
+         /* From clz of VR_RANGE maximum we can compute
+            result minimum.  */
+         if (vr0->kind () == VR_RANGE
+             && TREE_CODE (vr0->max ()) == INTEGER_CST)
            {
-             if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
-                 && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+             int newmini = prec - 1 - tree_floor_log2 (vr0->max ());
+             if (newmini == prec)
                {
-                 /* Handle only the two common values.  */
-                 if (zerov == -1)
-                   mini = -1;
-                 else if (zerov == prec)
-                   maxi = prec;
-                 else
-                   /* Magic value to give up, unless vr0 proves
-                      arg is non-zero.  */
-                   mini = -2;
+                 if (maxi == prec)
+                   mini = prec;
                }
+             else
+               mini = newmini;
            }
-         if (TREE_CODE (arg) == SSA_NAME)
+       }
+      if (mini == -2)
+       break;
+      goto bitop_builtin;
+      /* __builtin_ctz* return [0, prec-1], except for
+        when the argument is 0, but that is undefined behavior.
+        Always handle __builtin_ctz* which can be only written
+        by user as UB on 0 and so [0, prec-1] range, and the internal-fn
+        calls depending on how CTZ_DEFINED_VALUE_AT_ZERO is defined.  */
+    CASE_CFN_CTZ:
+      arg = gimple_call_arg (stmt, 0);
+      prec = TYPE_PRECISION (TREE_TYPE (arg));
+      mini = 0;
+      maxi = prec - 1;
+      mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
+      if (gimple_call_internal_p (stmt))
+       {
+         if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
+             && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
            {
-             const value_range_equiv *vr0 = get_value_range (arg);
-             /* If arg is non-zero, then use [0, prec - 1].  */
-             if ((vr0->kind () == VR_RANGE
-                  && integer_nonzerop (vr0->min ()))
-                 || (vr0->kind () == VR_ANTI_RANGE
-                     && integer_zerop (vr0->min ())))
-               {
-                 mini = 0;
-                 maxi = prec - 1;
-               }
-             /* If some high bits are known to be zero,
-                we can decrease the result maximum.  */
-             if (vr0->kind () == VR_RANGE
-                 && TREE_CODE (vr0->max ()) == INTEGER_CST)
+             /* Handle only the two common values.  */
+             if (zerov == -1)
+               mini = -1;
+             else if (zerov == prec)
+               maxi = prec;
+             else
+               /* Magic value to give up, unless vr0 proves
+                  arg is non-zero.  */
+               mini = -2;
+           }
+       }
+      if (TREE_CODE (arg) == SSA_NAME)
+       {
+         const value_range_equiv *vr0 = get_value_range (arg);
+         /* If arg is non-zero, then use [0, prec - 1].  */
+         if ((vr0->kind () == VR_RANGE
+              && integer_nonzerop (vr0->min ()))
+             || (vr0->kind () == VR_ANTI_RANGE
+                 && integer_zerop (vr0->min ())))
+           {
+             mini = 0;
+             maxi = prec - 1;
+           }
+         /* If some high bits are known to be zero,
+            we can decrease the result maximum.  */
+         if (vr0->kind () == VR_RANGE
+             && TREE_CODE (vr0->max ()) == INTEGER_CST)
+           {
+             int newmaxi = tree_floor_log2 (vr0->max ());
+             if (newmaxi == -1)
                {
-                 int newmaxi = tree_floor_log2 (vr0->max ());
-                 if (newmaxi == -1)
-                   {
-                     if (mini == -1)
-                       maxi = -1;
-                     else if (maxi == prec)
-                       mini = prec;
-                   }
-                 else if (maxi != prec)
-                   maxi = newmaxi;
+                 if (mini == -1)
+                   maxi = -1;
+                 else if (maxi == prec)
+                   mini = prec;
                }
+             else if (maxi != prec)
+               maxi = newmaxi;
            }
-         if (mini == -2)
-           break;
-         goto bitop_builtin;
-         /* __builtin_clrsb* returns [0, prec-1].  */
-       CASE_CFN_CLRSB:
-         arg = gimple_call_arg (stmt, 0);
-         prec = TYPE_PRECISION (TREE_TYPE (arg));
-         mini = 0;
-         maxi = prec - 1;
-         goto bitop_builtin;
-       bitop_builtin:
-         vr->set (build_int_cst (type, mini), build_int_cst (type, maxi));
-         return;
-       case CFN_UBSAN_CHECK_ADD:
-         subcode = PLUS_EXPR;
-         break;
-       case CFN_UBSAN_CHECK_SUB:
-         subcode = MINUS_EXPR;
-         break;
-       case CFN_UBSAN_CHECK_MUL:
-         subcode = MULT_EXPR;
-         break;
-       case CFN_GOACC_DIM_SIZE:
-       case CFN_GOACC_DIM_POS:
-         /* Optimizing these two internal functions helps the loop
-            optimizer eliminate outer comparisons.  Size is [1,N]
-            and pos is [0,N-1].  */
+       }
+      if (mini == -2)
+       break;
+      goto bitop_builtin;
+      /* __builtin_clrsb* returns [0, prec-1].  */
+    CASE_CFN_CLRSB:
+      arg = gimple_call_arg (stmt, 0);
+      prec = TYPE_PRECISION (TREE_TYPE (arg));
+      mini = 0;
+      maxi = prec - 1;
+      goto bitop_builtin;
+    bitop_builtin:
+      vr->set (build_int_cst (type, mini), build_int_cst (type, maxi));
+      return true;
+    case CFN_UBSAN_CHECK_ADD:
+      subcode = PLUS_EXPR;
+      break;
+    case CFN_UBSAN_CHECK_SUB:
+      subcode = MINUS_EXPR;
+      break;
+    case CFN_UBSAN_CHECK_MUL:
+      subcode = MULT_EXPR;
+      break;
+    case CFN_GOACC_DIM_SIZE:
+    case CFN_GOACC_DIM_POS:
+      /* Optimizing these two internal functions helps the loop
+        optimizer eliminate outer comparisons.  Size is [1,N]
+        and pos is [0,N-1].  */
+      {
+       bool is_pos = cfn == CFN_GOACC_DIM_POS;
+       int axis = oacc_get_ifn_dim_arg (stmt);
+       int size = oacc_get_fn_dim_size (current_function_decl, axis);
+
+       if (!size)
+         /* If it's dynamic, the backend might know a hardware
+            limitation.  */
+         size = targetm.goacc.dim_limit (axis);
+
+       tree type = TREE_TYPE (gimple_call_lhs (stmt));
+       vr->set(build_int_cst (type, is_pos ? 0 : 1),
+               size
+               ? build_int_cst (type, size - is_pos) : vrp_val_max (type));
+      }
+      return true;
+    case CFN_BUILT_IN_STRLEN:
+      if (tree lhs = gimple_call_lhs (stmt))
+       if (ptrdiff_type_node
+           && (TYPE_PRECISION (ptrdiff_type_node)
+               == TYPE_PRECISION (TREE_TYPE (lhs))))
          {
-           bool is_pos = cfn == CFN_GOACC_DIM_POS;
-           int axis = oacc_get_ifn_dim_arg (stmt);
-           int size = oacc_get_fn_dim_size (current_function_decl, axis);
-
-           if (!size)
-             /* If it's dynamic, the backend might know a hardware
-                limitation.  */
-             size = targetm.goacc.dim_limit (axis);
-
-           tree type = TREE_TYPE (gimple_call_lhs (stmt));
-           vr->set(build_int_cst (type, is_pos ? 0 : 1),
-                   size
-                   ? build_int_cst (type, size - is_pos) : vrp_val_max (type));
+           tree type = TREE_TYPE (lhs);
+           tree max = vrp_val_max (ptrdiff_type_node);
+           wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
+           tree range_min = build_zero_cst (type);
+           /* To account for the terminating NUL, the maximum length
+              is one less than the maximum array size, which in turn
+              is one  less than PTRDIFF_MAX (or SIZE_MAX where it's
+              smaller than the former type).
+              FIXME: Use max_object_size() - 1 here.  */
+           tree range_max = wide_int_to_tree (type, wmax - 2);
+           vr->set (range_min, range_max);
+           return true;
          }
-         return;
-       case CFN_BUILT_IN_STRLEN:
-         if (tree lhs = gimple_call_lhs (stmt))
-           if (ptrdiff_type_node
-               && (TYPE_PRECISION (ptrdiff_type_node)
-                   == TYPE_PRECISION (TREE_TYPE (lhs))))
-             {
-               tree type = TREE_TYPE (lhs);
-               tree max = vrp_val_max (ptrdiff_type_node);
-               wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
-               tree range_min = build_zero_cst (type);
-               /* To account for the terminating NUL, the maximum length
-                  is one less than the maximum array size, which in turn
-                  is one  less than PTRDIFF_MAX (or SIZE_MAX where it's
-                  smaller than the former type).
-                  FIXME: Use max_object_size() - 1 here.  */
-               tree range_max = wide_int_to_tree (type, wmax - 2);
-               vr->set (range_min, range_max);
-               return;
-             }
-         break;
-       default:
-         break;
-       }
-      if (subcode != ERROR_MARK)
-       {
-         bool saved_flag_wrapv = flag_wrapv;
-         /* Pretend the arithmetics is wrapping.  If there is
-            any overflow, we'll complain, but will actually do
-            wrapping operation.  */
-         flag_wrapv = 1;
-         extract_range_from_binary_expr (vr, subcode, type,
-                                         gimple_call_arg (stmt, 0),
-                                         gimple_call_arg (stmt, 1));
-         flag_wrapv = saved_flag_wrapv;
-
-         /* If for both arguments vrp_valueize returned non-NULL,
-            this should have been already folded and if not, it
-            wasn't folded because of overflow.  Avoid removing the
-            UBSAN_CHECK_* calls in that case.  */
-         if (vr->kind () == VR_RANGE
-             && (vr->min () == vr->max ()
-                 || operand_equal_p (vr->min (), vr->max (), 0)))
-           vr->set_varying (vr->type ());
-         return;
-       }
+      break;
+    default:
+      break;
+    }
+  if (subcode != ERROR_MARK)
+    {
+      bool saved_flag_wrapv = flag_wrapv;
+      /* Pretend the arithmetics is wrapping.  If there is
+        any overflow, we'll complain, but will actually do
+        wrapping operation.  */
+      flag_wrapv = 1;
+      extract_range_from_binary_expr (vr, subcode, type,
+                                     gimple_call_arg (stmt, 0),
+                                     gimple_call_arg (stmt, 1));
+      flag_wrapv = saved_flag_wrapv;
+
+      /* If for both arguments vrp_valueize returned non-NULL,
+        this should have been already folded and if not, it
+        wasn't folded because of overflow.  Avoid removing the
+        UBSAN_CHECK_* calls in that case.  */
+      if (vr->kind () == VR_RANGE
+         && (vr->min () == vr->max ()
+             || operand_equal_p (vr->min (), vr->max (), 0)))
+       vr->set_varying (vr->type ());
+
+      return !vr->varying_p ();
+    }
+  return false;
+}
+
+/* Try to derive a nonnegative or nonzero range out of STMT relying
+   primarily on generic routines in fold in conjunction with range data.
+   Store the result in *VR */
+
+void
+vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
+{
+  bool sop;
+  tree type = gimple_expr_type (stmt);
+
+  if (is_gimple_call (stmt) && extract_range_builtin (vr, stmt))
+    {
+      value_range_equiv tmp;
+      /* Assert that any ranges vr_values::extract_range_builtin gets
+        are also handled by the ranger counterpart.  */
+      gcc_assert (range_of_builtin_call (*this, tmp, as_a<gcall *> (stmt)));
+      gcc_assert (tmp.equal_p (*vr, /*ignore_equivs=*/false));
+      return;
     }
   /* Handle extraction of the two results (result of arithmetics and
      a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW
index a30f05c..b0ff68d 100644 (file)
@@ -101,7 +101,7 @@ class vr_values : public range_query
   vr_values (void);
   ~vr_values (void);
 
-  virtual bool range_of_expr (irange &r, tree name, gimple *stmt) OVERRIDE;
+  virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) OVERRIDE;
   virtual tree value_of_expr (tree, gimple * = NULL) OVERRIDE;
   virtual tree value_on_edge (edge, tree) OVERRIDE;
   virtual tree value_of_stmt (gimple *, tree = NULL_TREE) OVERRIDE;
@@ -148,6 +148,7 @@ class vr_values : public range_query
   void extract_range_from_comparison (value_range_equiv *, gimple *);
   void vrp_visit_assignment_or_call (gimple*, tree *, value_range_equiv *);
   void vrp_visit_switch_stmt (gswitch *, edge *);
+  bool extract_range_builtin (value_range_equiv *, gimple *);
 
   /* This probably belongs in the lattice rather than in here.  */
   bool values_propagated;