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

--- Comment #23 from Jan Hubicka <hubicka at gcc dot gnu.org> ---
one in comment #0 optimizes with me provided that destructors are inline

jh@shroud:/tmp> cat tt.C
#include <vector>
#include <numeric>
#include <array>

//static int calc(const std::array<int,3> p_ints, const int& p_init)
static int calc(const std::vector<int> p_ints, const int& p_init)
{
  return std::accumulate(p_ints.begin(), p_ints.end(), p_init);
}

int main2()
{
  const int result = calc({10,20,30},100);
  return result;
}
jh@shroud:/tmp> ~/trunk-install-new5/bin/g++ -O2 tt.C -S -fdump-tree-all
jh@shroud:/tmp> cat tt.C*optimized

;; Function main2 (_Z5main2v, funcdef_no=1316, decl_uid=26734, cgraph_uid=154,
symbol_order=174)

int main2 ()
{
  <bb 2> [local count: 118111600]:
  return 160;
}

One in comment #17 does optimize too
jh@shroud:/tmp> cat >qq.C
int f(void)
{
        int tt = 100;
        int t[3] = {10,20,30};
        int *t1 = new int[3];
        __builtin_memcpy(t1, t, sizeof(t));
        for(int *i = t1; i != &t1[3]; i++)
          tt += *i;
        delete[] t1;
        return tt;
}

jh@shroud:/tmp> ~/trunk-install-new5/bin/g++ -O2 qq.C -S -fdump-tree-all
jh@shroud:/tmp> cat qq.C*optimized

;; Function f (_Z1fv, funcdef_no=0, decl_uid=2828, cgraph_uid=1,
symbol_order=0)

int f ()
{
  <bb 2> [local count: 268435458]:
  return 160;

}


However if I do not rename main to main2 I get in #0 testcase:
int main ()
{
  void * D.27965;
  int * __result;
  static const int C.0[3] = {10, 20, 30};
  struct vector D.26783;
  int * _36;
  void * _45;

  <bb 2> [local count: 118111600]:
  MEM[(struct _Vector_impl_data *)&D.26783] ={v} {CLOBBER(bob)};
  MEM <vector(2) long unsigned int> [(int * *)&D.26783] = { 0, 0 };
  MEM[(struct _Vector_impl_data *)&D.26783]._M_end_of_storage = 0B;
  _36 = operator new (12);

  <bb 3> [local count: 118111600]:
  __builtin_memcpy (_36, &C.0, 12);
  __result_29 = _36 + 12;
  D.26783.D.26624._M_impl.D.25935._M_finish = __result_29;
  D.26783.D.26624._M_impl.D.25935._M_start = _36;
  D.26783.D.26624._M_impl.D.25935._M_end_of_storage = __result_29;
  std::_Vector_base<int, std::allocator<int> >::~_Vector_base
(&D.26783.D.26624);
  D.26783 ={v} {CLOBBER(eob)};
  D.26783 ={v} {CLOBBER(eos)};
  return 160;

  <bb 4> [count: 0]:
<L6>:
  std::_Vector_base<int, std::allocator<int> >::~_Vector_base
(&D.26783.D.26624);
  _45 = __builtin_eh_pointer (11);
  __builtin_unwind_resume (_45);

}

I think this is kind of important limitation because uninlined destructors in
EH are very frequent.

Reason why we do not optimize is that the destructor computes size of array
being destroyed:

void std::_Vector_base<int, std::allocator<int> >::~_Vector_base (struct
_Vector_base * const this)
{
  int * _1;
  int * _2;
  long int _3;
  long unsigned int _11;

  <bb 2> [local count: 1073741824]:
  _2 = this_7(D)->_M_impl.D.25935._M_start;
  if (_2 != 0B)
    goto <bb 3>; [53.47%]
  else
    goto <bb 4>; [46.53%]

  <bb 3> [local count: 574129752]:
  _1 = this_7(D)->_M_impl.D.25935._M_end_of_storage;
  _3 = _1 - _2;
  _11 = (long unsigned int) _3;
  operator delete (_2, _11); [tail call]

  <bb 4> [local count: 1073741824]:
  *this_7(D) ={v} {CLOBBER(eob)};
  return;

}
and that is considered as too big when optimizing for size.  delete has a
variant without size known. I wonder if for vectors it is not better to use
this variant, given that computing size involves some pointer arithmetics.

I think I will need to extend ipa-modref to recognize wrappers of removable
allocations and deallocations.

Here we can figure out that the destructors only reads from block being deleted
and then calls particular variant of delete.

Reply via email to