On Thu, Oct 08, 2020 at 04:55:07PM +0200, Aldy Hernandez via Gcc-patches wrote:
> > Yes, for max == 0 aka [0, 0] I wanted:
> > 1) if mini == -1, i.e. the DEFINED_VALUE_AT_ZERO == 2 VALUE is -1, return 
> > [-1, -1]
> > 2) if maxi == prec, i.e. DEFINED_VALUE_AT_ZERO == 2 VALUE is prec, return 
> > [prec, prec]
> 
> Ah, I see.  Do you mind commenting that?  Or perhaps you could spell it out
> obviously like:
> 
> if (max == 0) {
>       ...
>       if (DEFINED_VALUE_AT_ZERO)
>               // do special things
>       ...
> }
> 
> But whatever is fine.  I hope to never look at these bits ever again :).

Added several comments now (but just in gimple-range.cc, I assume
vr-values.c code is what you want to kill eventually).

2020-10-08  Jakub Jelinek  <ja...@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/vr-values.c.jj  2020-10-07 10:47:47.065983121 +0200
+++ gcc/vr-values.c     2020-10-08 15:23:56.042631592 +0200
@@ -1208,34 +1208,42 @@ vr_values::extract_range_basic (value_ra
          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_ra
              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_ra
          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_ra
              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)
--- gcc/gimple-range.cc.jj      2020-10-08 11:55:25.498313173 +0200
+++ gcc/gimple-range.cc 2020-10-08 15:36:14.926945183 +0200
@@ -636,28 +636,38 @@ gimple_ranger::range_of_builtin_call (ir
       // __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 (ir
       // 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 (ir
       // __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 (ir
          // 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;
--- gcc/testsuite/gcc.dg/tree-ssa/pr94801.c.jj  2020-10-08 15:35:01.837005736 
+0200
+++ gcc/testsuite/gcc.dg/tree-ssa/pr94801.c     2020-10-08 15:34:49.252188342 
+0200
@@ -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;
+}


        Jakub

Reply via email to