https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86276

--- Comment #2 from Jan Hubicka <hubicka at gcc dot gnu.org> ---
With -O3 we now do quite well.

_Z4goodv:
.LFB1248:
        .cfi_startproc
        ret
        .cfi_endproc
.LFE1248:
        .size   _Z4goodv, .-_Z4goodv
        .p2align 4
        .globl  _Z3badv
        .type   _Z3badv, @function
_Z3badv:
.LFB1260:
        .cfi_startproc
        pushq   %rbx
        .cfi_def_cfa_offset 16
        .cfi_offset 3, -16
        movq    %rdi, %rbx
        movl    $22, %edi
        call    _Znwm
        movb    $2, (%rax)
        leaq    22(%rax), %rdx
        movq    %rax, (%rbx)
        addq    $1, %rax
        movq    %rax, 8(%rbx)
        movq    %rbx, %rax
        movq    %rdx, 16(%rbx)
        popq    %rbx
        .cfi_def_cfa_offset 8
        ret

good is optimized to empty function since we now have __builtin_operator_new.
Bad is pretty straighforward construction of the vector:

struct vector bad ()
{
  unsigned char * __result;
  unsigned char * _26;
  unsigned char * _28;

  <bb 2> [local count: 1073741824]:
  _26 = operator new (22);
  something_3(D)->D.25721._M_impl.D.25032._M_start = _26;
  _28 = _26 + 22;
  something_3(D)->D.25721._M_impl.D.25032._M_end_of_storage = _28;
  MEM[(char * {ref-all})_26] = 2;
  __result_59 = _26 + 1;
  something_3(D)->D.25721._M_impl.D.25032._M_finish = __result_59;
  return something_3(D);

}
With -O2 however we end up offlining:

;; Function bad (_Z3badv, funcdef_no=1260, decl_uid=25847, cgraph_uid=171,
symbol_order=187)

struct vector bad ()
{
  void * D.27512;
  const unsigned char D.25850[1];
  unsigned char * _33;
  unsigned char * _38;
  unsigned char * _40;
  unsigned char * _41;
  long int _42;
  long unsigned int _43;
  void * _44;
  long unsigned int _47;
  vector(2) long unsigned int _56;

  <bb 2> [local count: 1073741824]:
  MEM[(struct _Vector_impl_data *)something_3(D)]._M_start = 0B;
  MEM[(struct _Vector_impl_data *)something_3(D)]._M_end_of_storage = 0B;
  _38 = operator new (22);

  <bb 3> [local count: 1073741824]:
  _47 = (long unsigned int) _38;
  _56 = {_47, _47};
  MEM <vector(2) long unsigned int> [(unsigned char * *)something_3(D)] = _56;
  _33 = _38 + 22;
  something_3(D)->D.25721._M_impl.D.25032._M_end_of_storage = _33;
  D.25850[0] = 2;
  std::vector<unsigned char>::_M_assign_aux.isra (something_3(D), &D.25850,
&MEM <const unsigned char[1]> [(void *)&D.25850 + 1B]);

  <bb 4> [local count: 1073741824]:
  D.25850 ={v} {CLOBBER(eos)};
  return something_3(D);

  <bb 5> [count: 0]:
<L2>:
  D.25850 ={v} {CLOBBER(eos)};
  _41 = MEM[(struct _Vector_base *)something_3(D)]._M_impl.D.25032._M_start;
  if (_41 != 0B)
    goto <bb 6>; [53.47%]
  else
    goto <bb 7>; [46.53%]

  <bb 6> [count: 0]:
  _40 = MEM[(struct _Vector_base
*)something_3(D)]._M_impl.D.25032._M_end_of_storage;
  _42 = _40 - _41;
  _43 = (long unsigned int) _42;
  operator delete (_41, _43);

  <bb 7> [count: 0]:
  _44 = __builtin_eh_pointer (1);
  __builtin_unwind_resume (_44);

}

So it first constructs empty vector and then offlines assignment froom C array.
Since it may throw an exception there is EH calling delete which is always
noop.
I think we need to start with ability to IPA propagate that the vector is empty
and thus _M_start==_M_end_of_storage

Curiously codegen for good is even longer:
void good () 
{ 
  void * D.27490; 
  unsigned char * something$_M_end_of_storage;
  unsigned char * something$_M_start;
  struct vector something;
  const unsigned char D.25837[1];
  void * _10;
  unsigned char * _36;
  unsigned char * _41;
  long int _45;
  long unsigned int _46;
  long int _49;
  long unsigned int _50;
  vector(2) long unsigned int _53;
  long unsigned int _59;

  <bb 2> [local count: 1073741824]:
  MEM[(struct _Vector_impl_data *)&something] ={v} {CLOBBER(bob)};
  _41 = operator new (22);
  goto <bb 4>; [100.00%]

  <bb 3> [count: 0]:
<L4>:
  D.25837 ={v} {CLOBBER(eos)};
  goto <bb 10>; [100.00%]

  <bb 4> [local count: 1073741824]:
  _59 = (long unsigned int) _41;
  _53 = {_59, _59};
  _36 = _41 + 22;
  D.25837[0] = 2;
  MEM <vector(2) long unsigned int> [(void *)&something] = _53;
  MEM <unsigned char *> [(struct vector *)&something + 16B] = _36;
  std::vector<unsigned char>::_M_assign_aux.isra (&something, &D.25837, &MEM
<const unsigned char[1]> [(void *)&D.25837 + 1B]);

  <bb 5> [local count: 1073741824]:
  something$_M_start_20 = MEM <unsigned char *> [(struct vector *)&something];
  something$_M_end_of_storage_21 = MEM <unsigned char *> [(struct vector
*)&something + 16B];
  D.25837 ={v} {CLOBBER(eos)};
  if (something$_M_start_20 != 0B)
    goto <bb 6>; [53.47%]
  else
    goto <bb 7>; [46.53%]

  <bb 6> [local count: 574129752]:
  _45 = something$_M_end_of_storage_21 - something$_M_start_20;
  _46 = (long unsigned int) _45;
  operator delete (something$_M_start_20, _46); [tail call]

  <bb 7> [local count: 1073741824]:
  something ={v} {CLOBBER(eob)};
  something ={v} {CLOBBER(eos)};
  return;

  <bb 8> [count: 0]:
<L3>:
  something$_M_start_22 = MEM <unsigned char *> [(struct vector *)&something];
  something$_M_end_of_storage_23 = MEM <unsigned char *> [(struct vector
*)&something + 16B];
  D.25837 ={v} {CLOBBER(eos)};
  if (something$_M_start_22 != 0B)
    goto <bb 9>; [53.47%]
  else
    goto <bb 10>; [46.53%]

  <bb 9> [count: 0]:
  _49 = something$_M_end_of_storage_23 - something$_M_start_22;
  _50 = (long unsigned int) _49;
  operator delete (something$_M_start_22, _50);

  <bb 10> [count: 0]:
  something ={v} {CLOBBER(eob)};
  _10 = __builtin_eh_pointer (2);
  __builtin_unwind_resume (_10);

}

Reply via email to