https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107569
--- Comment #40 from Jakub Jelinek <jakub at gcc dot gnu.org> --- The current state of #c0 testcase is that bar is actually optimized into return 1; Folding statement: .ASSUME (_Z3bard._assume.0, x_1(D)); _Z3bard._assume.0 assume inferred range of x_1(D) (param x) = [frange] double [-1.79769313486231570814527423731704356798070567525844996599e+308 (-0x0.fffffffffffff8p+1024), 1.7976931 3486231570814527423731704356798070567525844996599e+308 (0x0.fffffffffffff8p+1024)] during vrp1 and Folding statement: _4 = _3 u> 1.79769313486231570814527423731704356798070567525844996599e+308; Queued stmt for removal. Folds to: 0 It is correct to optimize the comparison even with -ftrapping-math - comparisons only emit exceptions on NaNs, the quiet ones like u> even just on sNaNs, and the range proves that the non-constant operand is never a NAN and the other isn't either (it is constant). On the other side, foo isn't optimized. # RANGE [frange] double [0.0 (0x0.0p+0), +Inf] +NAN _6 = ABS_EXPR <x_3(D)>; _4 = _6 u> 1.79769313486231570814527423731704356798070567525844996599e+308; _8 = ~_4; if (_6 u> 1.79769313486231570814527423731704356798070567525844996599e+308) goto <bb 3>; [INV] else goto <bb 4>; [INV] <bb 3> : __builtin_unreachable (); <bb 4> : # RANGE [frange] double [0.0 (0x0.0p+0), +Inf] +NAN _9 = ABS_EXPR <x_3(D)>; _10 = _9 u> 1.79769313486231570814527423731704356798070567525844996599e+308; _11 = ~_10; return _11; is turned by fre1 into: _6 = ABS_EXPR <x_3(D)>; _4 = _6 u> 1.79769313486231570814527423731704356798070567525844996599e+308; _8 = ~_4; if (_6 u> 1.79769313486231570814527423731704356798070567525844996599e+308) goto <bb 3>; [INV] else goto <bb 4>; [INV] <bb 3> : __builtin_unreachable (); <bb 4> : return _8; and while e.g. evrp figures correctly out that 2->3 (T) _6 : [frange] double [+Inf, +Inf] +NAN 2->4 (F) x_3(D) : [frange] double [-1.79769313486231570814527423731704356798070567525844996599e+308 (-0x0.fffffffffffff8p+1024), 1.797693134862315708145274237317043567980705675 25844996599e+308 (0x0.fffffffffffff8p+1024)] 2->4 (F) _4 : [irange] bool [0, 0] NONZERO 0x0 2->4 (F) _6 : [frange] double [0.0 (0x0.0p+0), 1.79769313486231570814527423731704356798070567525844996599e+308 (0x0.fffffffffffff8p+1024)] it doesn't do the extra step of figuring out that when _4 on the 2->4 edge must be 0, then _8 on that edge must be 1. And, the finite range say for _6 or x_3(D) isn't stored into global state (if there would be say some possibly not returning call between _6 definition and uses or for x_3(D) between start of function and the uses, we obviously couldn't store it as a global range; in this case we could if we proved that isn't possible, i.e. that if the function is reached then return _8; is reached too). And then during vrp1 the same problem and __builtin_unreachable () is removed with nothing noted anywhere. Andrew, any thoughts?