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;