https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108565
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Ever confirmed|0 |1 Status|UNCONFIRMED |NEW Last reconfirmed| |2023-01-27 CC| |hubicka at gcc dot gnu.org, | |jason at gcc dot gnu.org --- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> --- <bb 2> [local count: 1073741824]: _4 = operator new (4); MEM[(int *)_4] = 10; a ={v} {CLOBBER}; if (_4 != 0B) goto <bb 3>; [53.47%] else goto <bb 4>; [46.53%] I suspect 'operator new' is not returns_nonnull for the variant that isn't noexcept. That would be my first stab at improving things. Not sure what the standard guarantees and where we can adjust things here? We currently rely on VRP assumptions to derive _4 != 0 from the store preceeding it, but value-numbering doesn't (yet) have any of that wired in. The issue with the CSE of MEM[(int *)_28] is that _28 escapes through passing 'b' to the not inlined shared_ptr::~shared_ptr (&b) DTOR. It looks like modref is not powerful enough to see that this DTOR doesn't make *this or **this escape (it "escapes" to operator delete maybe). The late modref sees modref analyzing 'shared_ptr::~shared_ptr()/7' (ipa=0) Past summary: loads: Every base stores: Every base kills: Parm 0 param offset:0 offset:0 size:128 max_size:128 Side effects Nondeterministic Global memory read Global memory written parm 0 flags: no_direct_escape Analyzing stmt: _10 = this_6(D)->data_; Analyzing flags of ssa name: _10 Analyzing stmt: operator delete (_10, 4); [tail call] current flags of _10 no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly Analyzing stmt: if (_10 != 0B) current flags of _10 no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly flags of ssa name _10 no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly current flags of this_6(D) no_direct_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly good! But: Analyzing stmt: _1 = this_6(D)->counter_; Analyzing flags of ssa name: _1 Analyzing stmt: operator delete (_1, 4); current flags of _1 no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly Analyzing stmt: *_1 = _3; current flags of _1 no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly Analyzing stmt: _2 = *_1; Analyzing flags of ssa name: _2 Analyzing stmt: _3 = _2 + -1; Analyzing flags of ssa name: _3 Analyzing stmt: if (_3 == 0) current flags of _3 no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read Analyzing stmt: *_1 = _3; ssa name saved to memory current flags of _3 flags of ssa name _3 current flags of _2 flags of ssa name _2 current flags of _1 no_direct_escape not_returned_directly Analyzing stmt: if (_1 != 0B) current flags of _1 no_direct_escape not_returned_directly flags of ssa name _1 no_direct_escape not_returned_directly current flags of this_6(D) no_direct_clobber no_direct_escape not_returned_directly not sure what it makes dropping he no_indirect_escape - it seems the 'ssa name saved to memory', but that should affect _3 which only "escapes" to where it was loaded from? With the modref analysis fixed points-to done before PRE should improve and thus PRE VN should perform the desired transform earlier.