https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64454
--- Comment #9 from Marc Glisse <glisse at gcc dot gnu.org> --- VRP could still do better: typedef unsigned short T; T f(T x, T y){ // Avoid narrowing in the front-end int ix=x; int iy=y; T z=ix%iy; int iz=z; return z%iy; } ix and iy both have range [0, 65535], but we don't optimize _9 = _5 & 65535; because Visiting statement: _5 = ix_2 % iy_4; Found new range for _5: VARYING Whereas (since the type is unsigned, the signed case is slightly more complicated but should still be doable) the range for _5 should be the intersection of [0, 65535] (at most max(ix_2)) and [0, 65534] (at most max(iy_4)-1). Even in the constant case, if x has range [0, 3], VRP currently says that x%7 has range [0, 6].