https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86132
Bug ID: 86132 Summary: Failure to elide condition known to be non-null Product: gcc Version: 8.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: nathan at gcc dot gnu.org Target Milestone: --- Created attachment 44268 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44268&action=edit test case x86_64 linux target using trunk: trunk/obj/x86_64/gcc/cc1plus jay.ii -O3 Both single_slow() and single() implement a cache of an object that is expensive to construct. We know if we call either once, subsequent calls will return the same value -- can the compiler tell? (Ignore the problem of operator new throwing, that's not important, alternatives that cannot thtor show the same problem). Yes and no. a() is optimized down to a single inlined call of single(). b() is not so fortunate and contains two inlined calls of single(). single_slow() is annotated to return non-null. but its internals could well be opaque. single() is inlineable, and expected to be so. Thus the value propagator should be able to determine that the assignment to single::object of the result of single_slow(), assigns a non-null value. It manages to do this in the a() case, but not the b() case. My guess is it thinks that the call to want_foo(Foo &) could affect the value of single::object. But that's not possible. It's function-local, its address does not escape, and it has a single assignment only reachable when it is NULL. _Z1av: cmpq $0, _ZZ6singlevE6object(%rip) je .L15 ;; the only test ret .L15: subq $8, %rsp call _Z11single_slowv ; the one call movq %rax, _ZZ6singlevE6object(%rip) addq $8, %rsp ret _Z1bv: subq $8, %rsp movq _ZZ6singlevE6object(%rip), %rdi testq %rdi, %rdi ;; test one. je .L20 .L17: call _Z8want_fooR3Foo movq _ZZ6singlevE6object(%rip), %rdi testq %rdi, %rdi ;; test two je .L21 addq $8, %rsp jmp _Z8want_fooR3Foo .L20: call _Z11single_slowv movq %rax, %rdi movq %rax, _ZZ6singlevE6object(%rip) jmp .L17 .L21: call _Z11single_slowv movq %rax, _ZZ6singlevE6object(%rip) movq %rax, %rdi addq $8, %rsp jmp _Z8want_fooR3Foo