<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Missed optimization: useless write of zero to memory"
   href="https://bugs.llvm.org/show_bug.cgi?id=32522">32522</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Missed optimization: useless write of zero to memory
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>Polly
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Optimizer
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>polly-dev@googlegroups.com
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>antoshkka@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>The following code:

///////////////
#include <new>

template <class T>
struct shared_ptr_like {
    T* ptr;
    shared_ptr_like(shared_ptr_like&& v) noexcept : ptr(v.ptr) { v.ptr = 0; }
    ~shared_ptr_like() { if (ptr) { delete ptr; } }
};

typedef shared_ptr_like<int> test_type;
void relocate(test_type* new_buffer, test_type* old_buffer) {
        new (new_buffer) test_type{ static_cast<test_type&&>(*old_buffer) };
        old_buffer->~test_type();
}
///////////////

Generates suboptimal assembly:

relocate(shared_ptr_like<int>*, shared_ptr_like<int>*):    #
@relocate(shared_ptr_like<int>*, shared_ptr_like<int>*)
        mov     rax, qword ptr [rsi]
        mov     qword ptr [rdi], rax
        mov     qword ptr [rsi], 0 # Remove this
        ret


For that example GCC 7.0.1 20170330 with flags -std=c++17 -O2 generates
following assembly

relocate(shared_ptr_like<int>*, shared_ptr_like<int>*):
        mov     rax, QWORD PTR [rsi]
        mov     QWORD PTR [rdi], rax
        ret

This is allowed by C++ standard because
* [class.dtor] specifies that "Once a destructor is invoked for an object, the
object no longer exists<...>" 
* all the accesses to stored values require an object (if object does not exist
- accessing value is UB) [basic.lval] "If a program attempts to access the
stored value of an object through a glvalue <...>"


Described optimization is essential because code that moves an object to new
location and then destroys it often used in loops (for example
std::vector::reserve does that).


Checked on CLANG 4.0 (tags/RELEASE_400/final 297782) with flags -std=c++1z -O2</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>