https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72785
--- Comment #6 from Jeffrey A. Law <law at redhat dot com> --- So this is a very interesting little issue that highlights a deficiency in the semantics of __builtin_constant_p. So prior to threading we have: ;; basic block 4, loop depth 0, count 0, freq 10000, maybe hot ;; prev block 3, next block 5, flags: (NEW, REACHABLE, VISITED) ;; pred: 2 [50.0%] (TRUE_VALUE,EXECUTABLE) ;; 3 [100.0%] (FALLTHRU,EXECUTABLE) # iftmp.0_2 = PHI <a.1_5(2), 1(3)> b = iftmp.0_2; _1 = __builtin_constant_p (iftmp.0_2); if (_1 != 0) goto <bb 5>; else goto <bb 7>; ;; succ: 5 [54.0%] (TRUE_VALUE,EXECUTABLE) ;; 7 [46.0%] (FALSE_VALUE,EXECUTABLE) ;; basic block 5, loop depth 0, count 0, freq 5400, maybe hot ;; prev block 4, next block 6, flags: (NEW, REACHABLE, VISITED) ;; pred: 4 [54.0%] (TRUE_VALUE,EXECUTABLE) if (iftmp.0_2 != 0) goto <bb 6>; else goto <bb 7>; ;; succ: 6 [36.6%] (TRUE_VALUE,EXECUTABLE) ;; 7 [63.4%] (FALSE_VALUE,EXECUTABLE) ;; basic block 6, loop depth 0, count 0, freq 1979, maybe hot ;; prev block 5, next block 7, flags: (NEW, REACHABLE, VISITED) ;; pred: 5 [36.6%] (TRUE_VALUE,EXECUTABLE) ____ilog2_NaN (); That's all fine and good. Threading wants to lookup the value of iftmp.0_2 in an attempt to eliminate the conditional in BB5. And it finds that the path 3->4->5 will result in iftmp.0_2 having the value 1. So it isolates that path. After isolation things look like this: ;; basic block 3, loop depth 0 ;; pred: 2 # iftmp.0_8 = PHI <1(2)> b = iftmp.0_8; _10 = __builtin_constant_p (iftmp.0_8); if (_10 != 0) goto <bb 6>; else goto <bb 7>; ;; succ: 6 ;; 7 ;; basic block 4, loop depth 0 ;; pred: 2 # iftmp.0_2 = PHI <a.1_5(2)> b = iftmp.0_2; _1 = __builtin_constant_p (iftmp.0_2); if (_1 != 0) goto <bb 5>; else goto <bb 7>; ;; succ: 5 ;; 7 ;; basic block 5, loop depth 0 ;; pred: 4 if (iftmp.0_2 != 0) goto <bb 6>; else goto <bb 7>; ;; succ: 6 ;; 7 ;; basic block 6, loop depth 0 ;; pred: 5 ;; 3 ____ilog2_NaN (); ;; succ: 7 Note how the path leading out of block 3 will never pass through the conditional in block 5. That's the primary effect of jump threading. The most "obvious" interpretation is that "b" is not constant in this case at the source level and thus __b_c_p must return zero. But how does one deal with cases where analysis such as VRP, CPROP, etc prove certain edges are not executable and thus certain paths to a b_c_p call are eliminated and the "obvious" non-constant b_c_p argument turns into a constant argument. This could happen virtually with any optimization that eliminates an edge in the CFG. Proving edge removal does not change the runtime result of a b_c_p call is almost certainly akin to the halting problem. Similarly such an interpretation would essentially mean that a block with a b_c_p call can only be duplicated if we can prove that the original and duplicate have the same runtime result as the original -- which we might be able to prove in some cases, but the context necessary to do so is likely not available in the places where we have to make that determination -- essentially we'll likely have to disallow duplication of blocks with b_c_p. I want folks to realize that the "obvious" interpretation may have very significant secondary effects and may ultimately result in cases where we must either totally cripple optimizers or declare that the "obvious" semantics simply can't be supported.