lxfind created this revision.
lxfind added reviewers: junparser, dongAxis1944, rjmccall, ChuanqiXu.
Herald added subscribers: hoy, modimo, wenlei, hiraditya.
lxfind requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Presplit coroutines cannot be inlined. During AlwaysInliner we check if a 
function is a presplit coroutine, if so we skip inlining.
The presplit coroutine attributes are set in CoroEarly pass.
However in O0 pipeline, AlwaysInliner runs before CoroEarly, so the attribute 
isn't set yet and will still inline the coroutine.
This causes Clang to crash: https://bugs.llvm.org/show_bug.cgi?id=49920


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100282

Files:
  clang/test/CodeGenCoroutines/coro-always-inline-resume.cpp
  clang/test/CodeGenCoroutines/coro-always-inline.cpp
  llvm/lib/Passes/PassBuilder.cpp

Index: llvm/lib/Passes/PassBuilder.cpp
===================================================================
--- llvm/lib/Passes/PassBuilder.cpp
+++ llvm/lib/Passes/PassBuilder.cpp
@@ -1883,6 +1883,12 @@
   for (auto &C : PipelineEarlySimplificationEPCallbacks)
     C(MPM, Level);
 
+  // CoroEarlyPass needs to run before AlwaysInliner to make sure we add
+  // proper attributes to coroutines first, so that Inliner won't inline
+  // coroutines.
+  if (PTO.Coroutines)
+    MPM.addPass(createModuleToFunctionPassAdaptor(CoroEarlyPass()));
+
   // Build a minimal pipeline based on the semantics required by LLVM,
   // which is just that always inlining occurs. Further, disable generating
   // lifetime intrinsics to avoid enabling further optimizations during
@@ -1940,8 +1946,6 @@
   }
 
   if (PTO.Coroutines) {
-    MPM.addPass(createModuleToFunctionPassAdaptor(CoroEarlyPass()));
-
     CGSCCPassManager CGPM(DebugLogging);
     CGPM.addPass(CoroSplitPass());
     CGPM.addPass(createCGSCCToFunctionPassAdaptor(CoroElidePass()));
Index: clang/test/CodeGenCoroutines/coro-always-inline.cpp
===================================================================
--- clang/test/CodeGenCoroutines/coro-always-inline.cpp
+++ clang/test/CodeGenCoroutines/coro-always-inline.cpp
@@ -1,54 +1,64 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fcoroutines-ts \
-// RUN:   -fexperimental-new-pass-manager -O0 %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fcoroutines-ts \
-// RUN:   -fexperimental-new-pass-manager -fno-inline -O0 %s -o - | FileCheck %s
-
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fcoroutines-ts \
-// RUN:   -O0 %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fcoroutines-ts \
-// RUN:   -fno-inline -O0 %s -o - | FileCheck %s
-
-namespace std {
-namespace experimental {
-
-struct handle {};
-
-struct awaitable {
-  bool await_ready() noexcept { return true; }
-  // CHECK-NOT: await_suspend
-  inline void __attribute__((__always_inline__)) await_suspend(handle) noexcept {}
-  bool await_resume() noexcept { return true; }
-};
+// RUN: %clang -std=c++2a %s -emit-llvm -S -o - | FileCheck %s
 
-template <typename T>
-struct coroutine_handle {
-  static handle from_address(void *address) noexcept { return {}; }
-};
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+class task {
+public:
+  class promise_type {
+  public:
+    task get_return_object() noexcept;
+    coro::suspend_always initial_suspend() noexcept;
+    void return_void() noexcept;
+    void unhandled_exception() noexcept;
+
+    struct final_awaiter {
+      bool await_ready() noexcept;
+      void await_suspend(coro::coroutine_handle<promise_type> h) noexcept;
+      void await_resume() noexcept;
+    };
 
-template <typename T = void>
-struct coroutine_traits {
-  struct promise_type {
-    awaitable initial_suspend() { return {}; }
-    awaitable final_suspend() noexcept { return {}; }
-    void return_void() {}
-    T get_return_object() { return T(); }
-    void unhandled_exception() {}
+    final_awaiter final_suspend() noexcept;
+
+    coro::coroutine_handle<> continuation;
   };
+
+  task(task &&t) noexcept;
+  ~task();
+
+  class awaiter {
+  public:
+    bool await_ready() noexcept;
+    void await_suspend(coro::coroutine_handle<> continuation) noexcept;
+    void await_resume() noexcept;
+
+  private:
+    friend task;
+    explicit awaiter(coro::coroutine_handle<promise_type> h) noexcept;
+    coro::coroutine_handle<promise_type> coro_;
+  };
+
+  awaiter operator co_await() &&noexcept;
+
+private:
+  explicit task(coro::coroutine_handle<promise_type> h) noexcept;
+  coro::coroutine_handle<promise_type> coro_;
 };
-} // namespace experimental
-} // namespace std
-
-// CHECK-LABEL: @_Z3foov
-// CHECK-LABEL: entry:
-// CHECK-NEXT: %this.addr.i{{[0-9]*}} = alloca %"struct.std::experimental::awaitable"*, align 8
-// CHECK-NEXT: %this.addr.i{{[0-9]*}} = alloca %"struct.std::experimental::awaitable"*, align 8
-// CHECK: [[CAST0:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"** %this.addr.i{{[0-9]*}} to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CAST0]])
-// CHECK: [[CAST1:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"** %this.addr.i{{[0-9]*}} to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CAST1]])
-
-// CHECK: [[CAST2:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"** %this.addr.i{{[0-9]*}} to i8*
-// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[CAST2]])
-// CHECK: [[CAST3:%[0-9]+]] = bitcast %"struct.std::experimental::awaitable"** %this.addr.i{{[0-9]*}} to i8*
-// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[CAST3]])
-void foo() { co_return; }
+
+task cee();
+
+__attribute__((always_inline)) inline task bar() {
+  co_await cee();
+  co_return;
+}
+
+task foo() {
+  co_await bar();
+  co_return;
+}
+
+// check that bar is not inlined even it's marked as always_inline
+
+// CHECK-LABEL: define void @_Z3foov(
+// CHECK:         invoke void @_Z3barv(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to