https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119712
--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Seems it hangs when doing range_of_stmt on if (_17 >= -1) in <bb 7> [local count: 227695545]: l: _13 = _11 * 1958960196; b.9_14 = b; _15 = _13 + b.9_14; _16 = _15 + -1016458303; e = _16; _17 = _16 * 20; if (_17 >= -1) goto <bb 8>; [5.50%] else goto <bb 4>; [94.50%] $5 = <basic_block 0x7fffea31d900 (7)> The code added in r14-5109 seems to change the [irange] int [-INF, 2147483626] MASK 0xfffffffc VALUE 0x1 range into [irange] int [-INF, -1][1, 1][4, 2147483626] MASK 0xfffffffc VALUE 0x1 That is because it attempted to intersect it with [irange] int [-INF, -1][1, 1][4, +INF] derived from the mask & value. For GCC 16, guess one question is if it can't do better, like [irange] int [-INF, -3][1, 1][5, +INF] in this case, i.e. not only specify that m_value is the only possibility on the [0, 3] range but at least grow it in both directions from that value. So instead of range = int_range<5> (type, wi::zero (prec), ub); // Then remove the specific value these bits contain from the range. wide_int value = m_value & ub; range.intersect (int_range<2> (type, value, value, VR_ANTI_RANGE)); do // Then remove the specific value these bits contain from the range. wide_int value = m_value & ub; range = int_range<5> (type, value - ub + 1, value + ub - 1); range.intersect (int_range<2> (type, value, value, VR_ANTI_RANGE)); (but carefully handle signed vs. unsigned types or too large UB for the precision, the above would work for signed types if ub is small enough only I guess). Obviously for z == 1 the current code is already ok. But why this change hangs the algorithm, no idea.