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 <[email protected]>
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