https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103255
--- Comment #6 from Andrew Macleod <amacleod at redhat dot com> --- (In reply to Jakub Jelinek from comment #5) > I think the bug is in: > else if (flag_delete_null_pointer_checks > && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) > { > /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't > allow going from non-NULL pointer to NULL. */ > if(!range_includes_zero_p (&r)) > return true; > } > > If !off_cst (not this case), I think before return true here we need > r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); > - we are going from the base pointer which is known not to be NULL to that + > some unknown offset, all we can say is that the result is not NULL, but we > don't really know the exact details. > For the off_cst case (probably only when it is actually constant, i.e. > off_cst && off.to_constant (&offi), we could use something based on r, but > will need to add the offi / BITS_PER_UNIT addend to the range, probably > verify the result doesn't include zero and if it would, use that > range_nonzero too. > > For the addition, not sure if that would be range_op_handler (PLUS_EXPR, > type)->fold_range or range_op_handler (POINTER_PLUS_EXPR, type)->fold_range > or what. > > Because, with the code as is, we end up with the original r for the base > hdr_3: struct header * [4194336B, 4194336B] > and instead of returning range unsigned int * [4194340B, 4194340B] we return > incorrect unsigned int * [4194336B, 4194336B] > > Or does this code rely on pointer ranges to be always just range_zero, > range_nonzero or varying and nothing else? If so, it should normalize > INTEGER_CSTs used in addresses etc. into range_zero or range_nonzero and > nothing else... That code is an import from vr-values, and in gcc 10 it did just what we do: if ((off_cst && known_eq (off, 0)) || (flag_delete_null_pointer_checks && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)))) { const value_range_equiv *vr = get_value_range (TREE_OPERAND (base, 0)); if (!range_includes_zero_p (vr)) return true; } Perhaps it later sanitizes it to non-zero... Ah, indeed: else if (vrp_stmt_computes_nonzero (stmt)) { vr->set_nonzero (type); vr->equiv_clear (); } nothing is suppose to depend on the zero/nonzero directly. Pointer tracking is a little schizophrenic. Sometimes it just tracks zero/nonzero, other times it uses integral calculations to come up with ranges.. especially if its gone back or forth to an integral value via casting. If we know its a constant, and we know the offset is a constant, then there would be no harm in doing the math and coming up with the right value... just as you suggest, with a check to make sure if zero has reappeared that we remove it. Or we could restore previous behaviour if we simply changed it to non-zero as well before returning true. Either would be correct/fine.