https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103986
--- Comment #9 from Richard Biener <rguenth at gcc dot gnu.org> --- There's nothing wrong with the unswitching I think. The exit test is optimized out in VRP2 where the preceeding DOM pass ended up putting some more SSA ranges in, specifically those derived from the unreachable(). Disabling DOM3 avoids the miscompile. After DOM3 we have <bb 2> [local count: 118111600]: goto <bb 4>; [100.00%] <bb 4> [local count: 228582456]: # ivtmp.22_40 = PHI <0(2), ivtmp.22_42(3)> # RANGE [-32768, 2] it$z_43 = (short int) ivtmp.22_40; # RANGE [1, 1] _32 = it$z_43 <= 2; <bb 5> [local count: 443025880]: # ivtmp.14_3 = PHI <0(4), ivtmp.14_19(9)> # RANGE [-32768, 2] it$y_2 = (short int) ivtmp.14_3; # RANGE [1, 1] _10 = it$y_2 <= 2; # RANGE [1, 1] _29 = _10 & _32; if (ivtmp.22_40 != 3) goto <bb 7>; [89.00%] else goto <bb 6>; [11.00%] note how it$z_43, derived from ivtmp.22_40 has a [-32768, 2] range and the exit test is ivtmp.22_40 != 3. Now, if ranger would come along and we'd ask it for the _43 def with the global range [-32768, 2] how that constrains _40 it would compute a range for that that doesn't hold at this point. SO what we're likely seeing is bad effects of our handling of globalizing ranges for a derived from if (a) __builtin_unreachable (); There have been issues with that in the past. GCC 10 vs 11 we have the extra g:c76b3f9e83353a4cd437ca137c1fb835c9b5c21f which likely fixed this.