https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93891
--- Comment #1 from Marc Glisse <glisse at gcc dot gnu.org> --- On the original code (I can attach it if needed, but it is large, it is resizing a std::vector with reference-counted elements) FRE3 fails to simplify MEM[(struct Handle_for *)__cur_16] ={v} {CLOBBER}; _17 = MEM[(const struct Handle_for &)__first_15].ptr_; MEM[(struct Handle_for *)__cur_16].ptr_ = _17; _18 = *_17.count; _19 = _18 + 1; *_17.count = _19; _20 = &__first_15->D.202020; _31 = MEM[(struct Handle_for *)__first_15].ptr_; while FRE4 sees MEM[(struct Handle_for *)__cur_3] ={v} {CLOBBER}; _17 = MEM[base: __first_20, offset: 0B]; MEM[base: __cur_3, offset: 0B] = _17; _18 = *_17.count; _19 = _18 + 1; *_17.count = _19; _31 = MEM[base: __first_20, offset: 0B]; and replaces _31 with _17. That's confusing, since the main difference between the 2 is removing a statement without VOP. (optimizing in FRE4 is way too late in this case, I want the simplified version before ldist, and it still requires at least DSE, some pass detecting a self-assignment, and DCE before that) Here is another simplified version of the testcase, but you need to compile it with -fno-early-inlining to see the issue: void g(); struct A { int*p; A(A const&a)noexcept:p(a.p){if(*p<=0)__builtin_unreachable();++*p;} ~A(){if(--*p==0)g();} }; #include <vector> void f(std::vector<A>&v){ v.reserve(1<<20); } At the end of gimple, we still have _92 = *_91; *_91 = _92; in the main loop, while I would want that gone before ldist.