vrp: Fix up gcc.target/aarch64/pr90838.c [PR97312, PR94801]
authorJakub Jelinek <jakub@redhat.com>
Fri, 9 Oct 2020 08:19:16 +0000 (10:19 +0200)
committerJakub Jelinek <jakub@redhat.com>
Fri, 9 Oct 2020 08:19:16 +0000 (10:19 +0200)
> Perhaps another way out of this would be document and enforce that
> __builtin_c[lt]z{,l,ll} etc calls are undefined at zero, but C[TL]Z ifn
> calls are defined there based on *_DEFINED_VALUE_AT_ZERO (*) == 2

The following patch implements that, i.e. __builtin_c?z* now take full
advantage of them being UB at zero, while the ifns are well defined at zero
if *_DEFINED_VALUE_AT_ZERO (*) == 2.  That is what fixes PR94801.

Furthermore, to fix PR97312, if it is well defined at zero and the value at
zero is prec, we don't lower the maximum unless the argument is known to be
non-zero.
For gimple-range.cc I guess we could improve it if needed e.g. by returning
a [0,7][32,32] range for .CTZ of e.g. [0,137], but for now it (roughly)
matches what vr-values.c does.

2020-10-09  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/94801
PR target/97312
* vr-values.c (vr_values::extract_range_basic) <CASE_CFN_CLZ,
CASE_CFN_CTZ>: When stmt is not an internal-fn call or
C?Z_DEFINED_VALUE_AT_ZERO is not 2, assume argument is not zero
and thus use [0, prec-1] range unless it can be further improved.
For CTZ, don't update maxi from upper bound if it was previously prec.
* gimple-range.cc (gimple_ranger::range_of_builtin_call) <CASE_CFN_CLZ,
CASE_CFN_CTZ>: Likewise.

* gcc.dg/tree-ssa/pr94801.c: New test.

gcc/gimple-range.cc
gcc/testsuite/gcc.dg/tree-ssa/pr94801.c [new file with mode: 0644]
gcc/vr-values.c

index 2461bb78394c592f3a46da9fb8631479379ce994..2ca86ed0e4c7153ca274d3b4f26ea53be30f96d5 100644 (file)
@@ -636,28 +636,38 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
       // __builtin_c[lt]z* return [0, prec-1], except when the
       // argument is 0, but that is undefined behavior.
       //
-      // On many targets where the CLZ RTL or optab value is defined
-      // for 0, the value is prec, so include that in the range by
-      // default.
+      // For __builtin_c[lt]z* consider argument of 0 always undefined
+      // behavior, for internal fns depending on C?Z_DEFINED_VALUE_AT_ZERO.
       arg = gimple_call_arg (call, 0);
       prec = TYPE_PRECISION (TREE_TYPE (arg));
       mini = 0;
-      maxi = prec;
+      maxi = prec - 1;
       mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-      if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
-         && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov)
-         // Only handle the single common value.
-         && zerov != prec)
-       // Magic value to give up, unless we can prove arg is non-zero.
-       mini = -2;
+      if (gimple_call_internal_p (call))
+       {
+         if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
+             && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+           {
+             // Only handle the single common value.
+             if (zerov == prec)
+               maxi = prec;
+             else
+               // Magic value to give up, unless we can prove arg is non-zero.
+               mini = -2;
+           }
+       }
 
       gcc_assert (range_of_expr (r, arg, call));
       // From clz of minimum we can compute result maximum.
       if (r.constant_p ())
        {
-         maxi = prec - 1 - wi::floor_log2 (r.lower_bound ());
-         if (maxi != prec)
-           mini = 0;
+         int newmaxi = prec - 1 - wi::floor_log2 (r.lower_bound ());
+         // Argument is unsigned, so do nothing if it is [0, ...] range.
+         if (newmaxi != prec)
+           {
+             mini = 0;
+             maxi = newmaxi;
+           }
        }
       else if (!range_includes_zero_p (&r))
        {
@@ -669,9 +679,17 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
       // From clz of maximum we can compute result minimum.
       if (r.constant_p ())
        {
-         mini = prec - 1 - wi::floor_log2 (r.upper_bound ());
-         if (mini == prec)
-           break;
+         int newmini = prec - 1 - wi::floor_log2 (r.upper_bound ());
+         if (newmini == prec)
+           {
+             // Argument range is [0, 0].  If CLZ_DEFINED_VALUE_AT_ZERO
+             // is 2 with VALUE of prec, return [prec, prec], otherwise
+             // ignore the range.
+             if (maxi == prec)
+               mini = prec;
+           }
+         else
+           mini = newmini;
        }
       if (mini == -2)
        break;
@@ -682,25 +700,27 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
       // __builtin_ctz* return [0, prec-1], except for when the
       // argument is 0, but that is undefined behavior.
       //
-      // If there is a ctz optab for this mode and
-      // CTZ_DEFINED_VALUE_AT_ZERO, include that in the range,
-      // otherwise just assume 0 won't be seen.
+      // For __builtin_ctz* consider argument of 0 always undefined
+      // behavior, for internal fns depending on CTZ_DEFINED_VALUE_AT_ZERO.
       arg = gimple_call_arg (call, 0);
       prec = TYPE_PRECISION (TREE_TYPE (arg));
       mini = 0;
       maxi = prec - 1;
       mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-      if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
-         && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov))
+      if (gimple_call_internal_p (call))
        {
-         // Handle only the two common values.
-         if (zerov == -1)
-           mini = -1;
-         else if (zerov == prec)
-           maxi = prec;
-         else
-           // Magic value to give up, unless we can prove arg is non-zero.
-           mini = -2;
+         if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
+             && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+           {
+             // Handle only the two common values.
+             if (zerov == -1)
+               mini = -1;
+             else if (zerov == prec)
+               maxi = prec;
+             else
+               // Magic value to give up, unless we can prove arg is non-zero.
+               mini = -2;
+           }
        }
       gcc_assert (range_of_expr (r, arg, call));
       if (!r.undefined_p ())
@@ -714,8 +734,20 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
          // the maximum.
          wide_int max = r.upper_bound ();
          if (max == 0)
-           break;
-         maxi = wi::floor_log2 (max);
+           {
+             // Argument is [0, 0].  If CTZ_DEFINED_VALUE_AT_ZERO
+             // is 2 with value -1 or prec, return [-1, -1] or [prec, prec].
+             // Otherwise ignore the range.
+             if (mini == -1)
+               maxi = -1;
+             else if (maxi == prec)
+               mini = prec;
+           }
+         // If value at zero is prec and 0 is in the range, we can't lower
+         // the upper bound.  We could create two separate ranges though,
+         // [0,floor_log2(max)][prec,prec] though.
+         else if (maxi != prec)
+           maxi = wi::floor_log2 (max);
        }
       if (mini == -2)
        break;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr94801.c b/gcc/testsuite/gcc.dg/tree-ssa/pr94801.c
new file mode 100644 (file)
index 0000000..5382e5e
--- /dev/null
@@ -0,0 +1,16 @@
+/* PR tree-optimization/94801 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */
+
+int
+foo (int a)
+{
+  return __builtin_clz (a) >> 5;
+}
+
+int
+bar (int a)
+{
+  return __builtin_ctz (a) >> 5;
+}
index 88aa672466ce8a456d30ae8f1b3e9e69c621da14..da0b249278b8ec19a0f034c3437fe7a503fadc0e 100644 (file)
@@ -1208,34 +1208,42 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
          mini = 0;
          maxi = 1;
          goto bitop_builtin;
-         /* __builtin_c[lt]z* return [0, prec-1], except for
+         /* __builtin_clz* return [0, prec-1], except for
             when the argument is 0, but that is undefined behavior.
-            On many targets where the CLZ RTL or optab value is defined
-            for 0 the value is prec, so include that in the range
-            by default.  */
+            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;
+         maxi = prec - 1;
          mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-         if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
-             && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov)
-             /* Handle only the single common value.  */
-             && zerov != prec)
-           /* Magic value to give up, unless vr0 proves
-              arg is non-zero.  */
-           mini = -2;
+         if (gimple_call_internal_p (stmt))
+           {
+             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;
+               }
+           }
          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)
+                 && TREE_CODE (vr0->min ()) == INTEGER_CST
+                 && integer_nonzerop (vr0->min ()))
                {
                  maxi = prec - 1 - tree_floor_log2 (vr0->min ());
-                 if (maxi != prec)
+                 if (mini == -2)
                    mini = 0;
                }
              else if (vr0->kind () == VR_ANTI_RANGE
@@ -1251,9 +1259,14 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
              if (vr0->kind () == VR_RANGE
                  && TREE_CODE (vr0->max ()) == INTEGER_CST)
                {
-                 mini = prec - 1 - tree_floor_log2 (vr0->max ());
-                 if (mini == prec)
-                   break;
+                 int newmini = prec - 1 - tree_floor_log2 (vr0->max ());
+                 if (newmini == prec)
+                   {
+                     if (maxi == prec)
+                       mini = prec;
+                   }
+                 else
+                   mini = newmini;
                }
            }
          if (mini == -2)
@@ -1261,27 +1274,30 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
          goto bitop_builtin;
          /* __builtin_ctz* return [0, prec-1], except for
             when the argument is 0, but that is undefined behavior.
-            If there is a ctz optab for this mode and
-            CTZ_DEFINED_VALUE_AT_ZERO, include that in the range,
-            otherwise just assume 0 won't be seen.  */
+            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 (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
-             && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov))
+         if (gimple_call_internal_p (stmt))
            {
-             /* 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 (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
+                 && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+               {
+                 /* 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)
            {
@@ -1300,10 +1316,16 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
              if (vr0->kind () == VR_RANGE
                  && TREE_CODE (vr0->max ()) == INTEGER_CST)
                {
-                 maxi = tree_floor_log2 (vr0->max ());
-                 /* For vr0 [0, 0] give up.  */
-                 if (maxi == -1)
-                   break;
+                 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 == -2)