https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59739
--- Comment #8 from Richard Biener <rguenth at gcc dot gnu.org> --- The last testcase shows <bb 2> : # .MEM_9 = VDEF <.MEM_6(D)> D.8527 = S::operator<=> (a_7(D), b_8(D)); <bb 3> : # VUSE <.MEM_9> __v$_M_value_21 = D.8527._M_value; if (__v$_M_value_21 < 0) goto <bb 7>; [INV] else goto <bb 4>; [INV] <bb 4> : # .MEM_11 = VDEF <.MEM_9> D.8527 = S::operator<=> (a_7(D), b_8(D)); so in this case the result is even the same memory temporary. Consider x = foo(1); x.z = 2; use (x); x = foo(1); "saving" the result of foo(1) to be re-used the 2nd time would require a new temporary aggregate. It's basically lowering to _1 = foo (1); x = _1; x.z = 2; use (x); x = _1; with the hope that _1 and x can be coalesced later. The C++ case can possibly be handled directly in visit_reference_op_call by looking up with the next VUSE after discovering the same LHS is being used. But wiring this into VN itself is a bit difficult. Figuring the 2nd store is a redundant one might be easier in this case. This wouldn't help for the C testcase from comment#4 which uses two different LHS temporaries.