https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117793
Bug ID: 117793 Summary: missed copy propagation across memcpy Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: hubicka at gcc dot gnu.org Target Milestone: --- Compiling: #include <string> std::string test() { std::string a="this text is longer than 15 characters"; std::string b=".txt"; return a+b; } With -std=c++23 -O2 yields: __attribute__((abi_tag ("cxx11"))) struct string test () { void * D.54566; struct string b; struct string a; struct string & _11(D); char * _46; char[16] * _76; char * _99; void * _330; <bb 2> [local count: 1073741824]: MEM[(struct basic_string *)&a] ={v} {CLOBBER(bob)}; MEM[(struct _Alloc_hider *)&a] ={v} {CLOBBER(bob)}; _46 = operator new (39); a._M_dataplus._M_p = _46; a.D.34429._M_allocated_capacity = 38; __builtin_memcpy (_46, "this text is longer than 15 characters", 38); a._M_string_length = 38; MEM[(char_type &)_46 + 38] = 0; MEM[(struct basic_string *)&b] ={v} {CLOBBER(bob)}; MEM[(struct _Alloc_hider *)&b] ={v} {CLOBBER(bob)}; MEM[(struct _Alloc_hider *)&b]._M_p = &b.D.34429._M_local_buf; __builtin_memcpy (&b.D.34429._M_local_buf, ".txt", 4); b._M_string_length = 4; MEM[(char_type &)&b + 20] = 0; _76 = &MEM[(struct basic_string *)_11(D)].D.34429._M_local_buf; MEM[(struct _Alloc_hider *)_11(D)]._M_p = _76; MEM[(struct basic_string *)_11(D)]._M_string_length = 0; MEM[(char_type &)_11(D) + 16] = 0; _99 = operator new (43); <bb 3> [local count: 1021257323]: MEM[(struct basic_string *)_11(D)]._M_dataplus._M_p = _99; MEM[(struct basic_string *)_11(D)].D.34429._M_allocated_capacity = 42; __builtin_memcpy (_99, _46, 38); MEM[(struct basic_string *)_11(D)]._M_string_length = 42; MEM <unsigned int> [(void *)_99 + 38B] = 1954051118; MEM[(char_type &)_99 + 42] = 0; b ={v} {CLOBBER(eob)}; operator delete (_46, 39); a ={v} {CLOBBER(eob)}; a ={v} {CLOBBER(eos)}; b ={v} {CLOBBER(eos)}; return _11(D); <bb 4> [count: 0]: <L12>: std::__cxx11::basic_string<char>::_M_dispose (_11(D)); __builtin_eh_copy_values (11, 19); std::__cxx11::basic_string<char>::_M_dispose (&b); b ={v} {CLOBBER(eob)}; __builtin_eh_copy_values (6, 11); std::__cxx11::basic_string<char>::_M_dispose (&a); a ={v} {CLOBBER(eob)}; _330 = __builtin_eh_pointer (6); __builtin_unwind_resume (_330); } So string b is constructed only to be destroyed if EH happens in + operation. If we inlined the destructor this would be optimized out: void std::__cxx11::basic_string<char>::_M_dispose (struct basic_string * const this) { long unsigned int _1; char * _5; const char[16] * _6; long unsigned int _8; <bb 2> [local count: 1073741824]: _5 = MEM[(const struct basic_string *)this_4(D)]._M_dataplus._M_p; _6 = &MEM[(const struct basic_string *)this_4(D)].D.34429._M_local_buf; if (_5 == _6) goto <bb 4>; [18.09%] else goto <bb 3>; [81.91%] <bb 3> [local count: 879501928]: _1 = this_4(D)->D.34429._M_allocated_capacity; _8 = _1 + 1; operator delete (_5, _8); [tail call] <bb 4> [local count: 1073741824]: return; } In this case if (_5==_6) is known to be true, but we can not represent this by IPA predicates. This goes away with -fno-exceptions: __attribute__((abi_tag ("cxx11"))) struct string test () { struct string & _10(D); char * _55; char * _108; <bb 2> [local count: 1073741824]: _55 = operator new (39); __builtin_memcpy (_55, "this text is longer than 15 characters", 38); _108 = operator new (43); MEM[(struct basic_string *)_10(D)]._M_dataplus._M_p = _108; MEM[(struct basic_string *)_10(D)].D.34405._M_allocated_capacity = 42; __builtin_memcpy (_108, _55, 38); MEM[(struct basic_string *)_10(D)]._M_string_length = 42; MEM <unsigned int> [(void *)_108 + 38B] = 1954051118; MEM[(char_type &)_108 + 42] = 0; operator delete (_55, 39); return _10(D); } However we also get __builtin_memcpy (_55, "this text is longer than 15 characters", 38); ... __builtin_memcpy (_108, _55, 38); If we were able to rewrite _108 to _55 we would optimize away the new/delete pair. We probably can also expand the memcpy inline like for ".txt" MEM <unsigned int> [(void *)_108 + 38B] = 1954051118;