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;

Reply via email to