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

--- Comment #19 from Jan Hubicka <hubicka at gcc dot gnu.org> ---
Note that the testcase from PR115037 also shows that we are not able to
optimize out dead stores to the vector, which is another quite noticeable
problem.

void
test()
{
        std::vector<int> test;
        test.push_back (1);
}

We alocate the block, store 1 and immediately delete it.
void test ()
{
  int * test$D25839$_M_impl$D25146$_M_start;
  struct vector test;
  int * _61;

  <bb 2> [local count: 1073741824]:
  _61 = operator new (4);

  <bb 3> [local count: 1063439392]:
  *_61 = 1;
  operator delete (_61, 4);
  test ={v} {CLOBBER};
  test ={v} {CLOBBER(eol)};
  return;

  <bb 4> [count: 0]:
<L1>:
  test ={v} {CLOBBER};
  resx 2

}

So my understanding is that we decided to not optimize away the dead stores
since the particular operator delete does not pass test:

  /* If the call is to a replaceable operator delete and results
     from a delete expression as opposed to a direct call to
     such operator, then we can treat it as free.  */
  if (fndecl
      && DECL_IS_OPERATOR_DELETE_P (fndecl)
      && DECL_IS_REPLACEABLE_OPERATOR (fndecl)
      && gimple_call_from_new_or_delete (stmt))
    return ". o ";

This is because we believe that operator delete may be implemented in an insane
way that inspects the values stored in the block being freed.

I can sort of see that one can write standard conforming code that allocates
some data that is POD and inspects it in destructor.
However for std::vector this argument is not really applicable. Standard does
specify that new/delete is used to allocate/deallocate the memory but does not
say how the memory is organized or what happens before deallocation.
(i.e. it is probably valid for std::vector to memset the block just before
deallocating it).

Similar argument can IMO be used for eliding unused memory allocations. It is
kind of up to std::vector implementation on how many allocations/deallocations
it does, right?

So we need a way to annotate the new/delete calls in the standard library as
safe for such optimizations (i.e. implement clang's
__bulitin_operator_new/delete?)

How clang manages to optimize this out without additional hinting?

Reply via email to