[llvm-bugs] [Bug 41877] New: [coroutines] escaping alloca from inlined function should not be included in the coroutine frame

via llvm-bugs llvm-bugs at lists.llvm.org
Tue May 14 10:44:54 PDT 2019


https://bugs.llvm.org/show_bug.cgi?id=41877

            Bug ID: 41877
           Summary: [coroutines] escaping alloca from inlined function
                    should not be included in the coroutine frame
           Product: new-bugs
           Version: trunk
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: new bugs
          Assignee: unassignedbugs at nondot.org
          Reporter: gornishanov at gmail.com
                CC: htmldeveloper at gmail.com, llvm-bugs at lists.llvm.org

https://godbolt.org/z/CCl-bg

CoroFrame analysis needs to pay attention to the lifetime.begin and .end
markers when deciding whether an escaping alloca should become part of the
coroutine frame or not.

In the example linked an pasted here for convenience:

// -std=c++2a -stdlib=libc++ -S -emit-llvm -g0 -O2
#include <experimental/coroutine>

using namespace std::experimental;

struct coro {
  struct promise_type {
    suspend_always initial_suspend() { return {};}
    suspend_always final_suspend() { return {};}
    void return_void() {}
    void unhandled_exception() {}
    coro get_return_object(){ return{}; }
  };
};

struct A {
    ~A();
};

void async(void*) noexcept;

struct Awaiter{
  bool await_ready() { return false; }    
  void await_resume() {}
  void await_suspend(coroutine_handle<> h) {
      A a;
      async(h.address());
  }
};

coro f() {
  co_await Awaiter{};
}

await_suspend will get inlined into "f".
Address of a local variable "a" escapes (to a destructor call).

The correct lowering is that A should no be included into the coroutine frame,
since its lifetime ends after the call to "async".

However, currently CoroFrame does not pay attention to the lifetime markers and
will make A to be part of the coroutine frame that may get destroyed before
async returns leading to bad outcomes.

CoroFrame needs to be improved to take advantage of lifetime marker
information. If we go there, and completely understand the lifetime of very
variable, we could also pack variables tighter in the coroutine frame.

Looking at the IR emitted right now, we can observe the problem:

1) Struct A is included in the coroutine frame

%_Z1fv.Frame = type { void (%_Z1fv.Frame*)*, void (%_Z1fv.Frame*)*,
%"struct.coro::promise_type", i2, %struct.A }

2) A is touched after we called async (and coroutine frame could be destroyed
there)

define internal fastcc void @_Z1fv.resume(%_Z1fv.Frame*) #0 personality i8* ...
                                               ; preds = %1
  %6 = bitcast %_Z1fv.Frame* %0 to i8*
  store i2 1, i2* %2, align 1
  %7 = getelementptr inbounds %_Z1fv.Frame, %_Z1fv.Frame* %0, i64 0, i32 4
  %8 = getelementptr inbounds %struct.A, %struct.A* %7, i64 0, i32 0
  tail call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %8) #2
  tail call void @_Z5asyncPv(i8* %6) #2
  tail call void @_ZN1AD1Ev(%struct.A* nonnull %7) #2 ; <==== BOOM
  tail call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %8) #2
...
}

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20190514/c950e126/attachment-0001.html>


More information about the llvm-bugs mailing list