For the record, this is what I envision the follow-up patch to be (untested).
Aldy diff --git a/gcc/vr-values.c b/gcc/vr-values.c index 9f5943a1ab6..3db72a360a6 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -1159,188 +1159,16 @@ check_for_binary_op_overflow (range_query *query, successful. */ bool -vr_values::extract_range_builtin (value_range_equiv *vr, gimple *stmt) +vr_values::extract_range_from_ubsan_builtin (value_range_equiv *vr, gimple *stmt) { 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; switch (cfn) { - 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 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) - { - /* 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 - && 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; - } - } - 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) - { - /* 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) - { - 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 true; case CFN_UBSAN_CHECK_ADD: subcode = PLUS_EXPR; break; @@ -1350,47 +1178,6 @@ vr_values::extract_range_builtin (value_range_equiv *vr, gimple *stmt) 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)))) - { - 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; - } - break; default: break; } @@ -1430,20 +1217,27 @@ 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)) + if (is_gimple_call (stmt)) { combined_fn cfn = gimple_call_combined_fn (stmt); - if (cfn == CFN_UBSAN_CHECK_ADD - || cfn == CFN_UBSAN_CHECK_SUB - || cfn == CFN_UBSAN_CHECK_MUL) - return; - - 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; + switch (cfn) + { + case CFN_UBSAN_CHECK_ADD: + case CFN_UBSAN_CHECK_SUB: + case CFN_UBSAN_CHECK_MUL: + if (extract_range_from_ubsan_builtin (vr, stmt)) + return; + break; + default: + if (range_of_builtin_call (*this, *vr, as_a<gcall *> (stmt))) + { + /* The original code nuked equivalences every time a + range was found, so do the same here. */ + vr->equiv_clear (); + return; + } + break; + } } /* Handle extraction of the two results (result of arithmetics and a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW diff --git a/gcc/vr-values.h b/gcc/vr-values.h index 59fac0c4b1e..712d029909f 100644 --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@ -148,7 +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 *); + bool extract_range_from_ubsan_builtin (value_range_equiv *, gimple *); /* This probably belongs in the lattice rather than in here. */ bool values_propagated; On Tue, Oct 27, 2020 at 4:29 PM Aldy Hernandez <al...@redhat.com> wrote: > > The UBSAN builtins degrade into PLUS/MINUS/MULT and call > extract_range_from_binary_expr, which as the PR shows, can special > case some symbolics which the ranger doesn't currently handle. > > Looking at vr_values::extract_range_builtin(), I see that every single > place where we ask for a range, we bail on non-integers (symbolics, > etc). That is, with the exception of the UBSAN builtins. > > Since this seems to be particular to UBSAN, we could still go with the > original plan of removing the duplicity in ranger vs vr-values, but > leave in the UBSAN builtin handling. This isn't ideal, as we'd like > to remove all the common code, but I'd be willing to put up with UBSAN > duplication for the time being. > > This patch disables the assert on the UBSAN builtins, while still > trapping if any other differences are found between the vr_values and > the ranger versions of builtin range handling. > > As a follow-up, once Fedora can test this approach, I'll remove all > the builtin code from extract_range_builtin, with the exception of the > UBSAN stuff (renaming it to extract_range_ubsan_builtin). > > Since the builtin code has proven fickle across architectures, I've > tested this with {-m32,-m64,-fsanitize=signed-integer-overflow} on > x86, ppc64le, and aarch64. I think this should be enough. If it > isn't, we can revert the patch, and leave the duplicate code until > the next release cycle when hopefully vr_values, evrp, and friends > will all be overhauled. > > Andrew, do you have any thoughts on this? > > Aldy > > gcc/ChangeLog: > > PR tree-optimization/97505 > * vr-values.c (vr_values::extract_range_basic): Enable > trap again for everything except UBSAN builtins. > --- > gcc/vr-values.c | 9 ++++++--- > 1 file changed, 6 insertions(+), 3 deletions(-) > > diff --git a/gcc/vr-values.c b/gcc/vr-values.c > index 7a0e70eab64..9f5943a1ab6 100644 > --- a/gcc/vr-values.c > +++ b/gcc/vr-values.c > @@ -1432,14 +1432,17 @@ vr_values::extract_range_basic (value_range_equiv > *vr, gimple *stmt) > > if (is_gimple_call (stmt) && extract_range_builtin (vr, stmt)) > { > + combined_fn cfn = gimple_call_combined_fn (stmt); > + if (cfn == CFN_UBSAN_CHECK_ADD > + || cfn == CFN_UBSAN_CHECK_SUB > + || cfn == CFN_UBSAN_CHECK_MUL) > + return; > + > 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))); > -#if 0 > - /* Disable this while PR97505 is resolved. */ > gcc_assert (tmp.equal_p (*vr, /*ignore_equivs=*/false)); > -#endif > return; > } > /* Handle extraction of the two results (result of arithmetics and > -- > 2.26.2 >