Before r254954, for x | 1 where x is VR_VARYING, we would deduce a VR_ANTI_RANGE ~[0, 0]. Since then, we deduce [-INT_MAX, INT_MAX]. Both make sense, but it is strange that we get something different for VR_VARYING and for a full range, and Richard thinks it is worth looking into (maybe zero_nonzero_bits_from_vr). -O2 -fdump-tree-optimized-all int f(int x){return x|1;}
I will have a look.
So for VARYING | 1 we go using the may_be_nonzero stuff in else if (code == BIT_IOR_EXPR) { max = wide_int_to_tree (expr_type, may_be_nonzero0 | may_be_nonzero1); wide_int wmin = must_be_nonzero0 | must_be_nonzero1; /* If the input ranges contain only positive values we can truncate the minimum of the result range to the maximum of the input range minima. */ if (int_cst_range0 && int_cst_range1 && tree_int_cst_sgn (vr0.min) >= 0 && tree_int_cst_sgn (vr1.min) >= 0) { wmin = wi::max (wmin, wi::to_wide (vr0.min), TYPE_SIGN (expr_type)); wmin = wi::max (wmin, wi::to_wide (vr1.min), TYPE_SIGN (expr_type)); } /* If either input range contains only negative values we can truncate the minimum of the result range to the respective minimum range. */ if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0) wmin = wi::max (wmin, wi::to_wide (vr0.min), TYPE_SIGN (expr_type)); if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0) wmin = wi::max (wmin, wi::to_wide (vr1.min), TYPE_SIGN (expr_type)); min = wide_int_to_tree (expr_type, wmin); but for [MIN, MAX] we go /* For op & or | attempt to optimize: [x, y] op z into [x op z, y op z] if z is a constant which (for op | its bitwise not) has n consecutive least significant bits cleared followed by m 1 consecutive bits set immediately above it and either m + n == precision, or (x >> (m + n)) == (y >> (m + n)). The least significant n bits of all the values in the range are cleared or set, the m bits above it are preserved and any bits above these are required to be the same for all values in the range. */ if (vr0p && range_int_cst_p (vr0p)) { wide_int w = wi::to_wide (vr1p->min); int m = 0, n = 0; if (code == BIT_IOR_EXPR) w = ~w; if (wi::eq_p (w, 0)) ... and both cases produce a different outcome (as we see). I don't see how we can do better. Well, we can choose to handle | CST with least significant bit set as ~[0, 0] consistently. Or we can add a predicate effectively_varying_p () and guard the 2nd case above with it. The "proper" result for [MIN,MAX] | 1 is of course a set of every odd number...
(In reply to Richard Biener from comment #2) > The "proper" result for [MIN,MAX] | 1 is of course a set of every odd > number... Sadly, while we track may-be-nonzero bits in CCP (maybe with the VRP reorg there will be a chance to merge it somehow?), we do not track must-be-nonzero bits. Note that the original testcase is completely artificial. I needed something known to be nonzero, and at the time x|1 worked so I used that, but it should not be used as if it was an important real-world code that heuristics need to be tuned for.
I added a patch to 83072 in which multi-range will now recognize there is no [0,0] in x|1. When we add bitmask tracking to ranger, it is in the work queue to track both must-be-zero and must-be-one bits, and integrate that knowledge with range queries. (so if (x == 20) would be known false after x = x | 1) Any additional input on what kind of other information could be attached here to this PR.
Take -O2 -fno-tree-fre -fno-tree-ccp -fno-tree-forwprop: int f(int x) { x = x|1; return x & 1; } We should be able to figure this out in evrp but don't currently. VRP can figure it out as it does a match and simplify for the statement.
The master branch has been updated by Andrew Macleod <amacleod@gcc.gnu.org>: https://gcc.gnu.org/g:49d5fb4feee831868d80fff4d024c271911c92ca commit r12-6559-g49d5fb4feee831868d80fff4d024c271911c92ca Author: Andrew MacLeod <amacleod@redhat.com> Date: Wed Jan 12 13:31:08 2022 -0500 Allow more precision when querying from fold_const. fold_const::expr_not_equal_to queries for a current range, but still uses the old value_range class. This is causing it to miss opportunities when ranger can provide something better. PR tree-optimization/83072 PR tree-optimization/83073 PR tree-optimization/97909 gcc/ * fold-const.c (expr_not_equal_to): Use a multi-range class. gcc/testsuite/ * gcc.dg/pr83072-2.c: New. * gcc.dg/pr83073.c: New.
Ranger VRP also does match and simplify now for both EVRP and VRP2.