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