<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 - miscompile of coroutines using symmetric control transfer"
   href="https://bugs.llvm.org/show_bug.cgi?id=45130">45130</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>miscompile of coroutines using symmetric control transfer
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </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>normal
          </td>
        </tr>

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

        <tr>
          <th>Component</th>
          <td>Common Code Generator Code
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>richard-llvm@metafoo.co.uk
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>gornishanov@gmail.com, llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Testcase:


#include <iostream>

#include <experimental/coroutine>
namespace std { using namespace experimental; }

struct coro {
  struct promise_type;
  using coro_handle = std::coroutine_handle<promise_type>;

  struct promise_type {
    coro_handle handle;
    auto initial_suspend() {
      struct awaitable {
        promise_type &promise;
        bool await_ready() { return false; }
        void await_suspend(coro_handle h) { promise.handle = h; }
        void await_resume() {}
      };
      return awaitable{*this};
    }
    auto final_suspend() {
      struct awaitable {
        bool await_ready() { return false; }
        void await_suspend(coro_handle h) { h.destroy(); }
        void await_resume() { __builtin_unreachable(); }
      };
      return awaitable{};
    }
    coro get_return_object() { return {this}; }
    void unhandled_exception() { throw; }
    void return_void() {}
  };
  promise_type *promise;

  bool await_ready() { return false; }
  coro_handle await_suspend(coro_handle) { return promise->handle; }
  coro await_resume() { return *this; }

  struct self_t {
    coro_handle handle;
    bool await_ready() { return false; }
    bool await_suspend(coro_handle h) { handle = h; return false; }
    coro await_resume() { return {&handle.promise()}; }
  };
  static inline self_t self;

  void run() { promise->handle(); }
  void destroy() { promise->handle.destroy(); }
};

coro g(coro c) {
  std::cout << "g1" << std::endl;
  co_await c;
  std::cout << "g2" << std::endl;
  co_await c;
  std::cout << "g3 returning" << std::endl;
  c.destroy();
}

coro f() {
  std::cout << "f1" << std::endl;
  coro c = g(co_await coro::self);
  std::cout << "f2" << std::endl;
  co_await c;
  std::cout << "f3" << std::endl;
  co_await c;
  std::cout << "f4" << std::endl;
  co_await c;
  std::cout << "f5 returning" << std::endl;
  c.destroy();
}

int main() {
  f().run();
}


At -O0, this prints out:

f1
f2
g1
f3
g2
f4
g3 returning

... which I believe to be correct. At -O2, this instead prints:

f1
f2
g1
f3
g2
f4
g2
f1
f2
g1
f3
g2
f4
g2
f1
f2
g1
f3
g2
f4
g2
f1
f2
g1
f3
g2
f4
g2
[... endless cycle ...]

Something seems to be messing up the state number handling in both coroutines.
For example, here's the resume function for g:


define internal fastcc void @_Z1g4coro.resume(%_Z1g4coro.Frame* noalias nonnull
%0) #2 {
  %2 = getelementptr inbounds %_Z1g4coro.Frame, %_Z1g4coro.Frame* %0, i64 0,
i32 3
  %3 = load i2, i2* %2, align 1
  %4 = icmp eq i2 %3, 0
  br i1 %4, label %14, label %5

5:                                                ; preds = %1
  tail call void @_Z2g2v()
  store i2 -2, i2* %2, align 1
  %6 = getelementptr inbounds %_Z1g4coro.Frame, %_Z1g4coro.Frame* %0, i64 0,
i32 4
  %7 = load %"struct.coro::promise_type"*, %"struct.coro::promise_type"** %6,
align 8
  %8 = getelementptr inbounds %"struct.coro::promise_type",
%"struct.coro::promise_type"* %7, i64 0, i32 0, i32 0, i32 0
  %9 = load i8*, i8** %8, align 8
  %10 = bitcast i8* %9 to { i8*, i8* }*
  %11 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %10, i32 0, i32 0
  %12 = load i8*, i8** %11
  %13 = bitcast i8* %12 to void (i8*)*
  musttail call fastcc void %13(i8* %9) #4
  ret void

14:                                               ; preds = %1
  tail call void @_Z2g1v()
  store i2 1, i2* %2, align 1
  %15 = getelementptr inbounds %_Z1g4coro.Frame, %_Z1g4coro.Frame* %0, i64 0,
i32 4
  %16 = load %"struct.coro::promise_type"*, %"struct.coro::promise_type"** %15,
align 8
  %17 = getelementptr inbounds %"struct.coro::promise_type",
%"struct.coro::promise_type"* %16, i64 0, i32 0, i32 0, i32 0
  %18 = load i8*, i8** %17, align 8
  %19 = bitcast i8* %18 to { i8*, i8* }*
  %20 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %19, i32 0, i32 0
  %21 = load i8*, i8** %20
  %22 = bitcast i8* %21 to void (i8*)*
  tail call fastcc void %22(i8* %18) #4
  ret void
}


Note that we store -2 and 1 to the state (%2), but we only branch on *%2 != 0,
and the code for the *%2 == -2 case (that calls g3) is gone.

If I add an extra couple of unreachable await points to 'g', the problem goes
away. Perhaps LLVM miscompiles 'switch i2'?</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>