[llvm-branch-commits] [llvm] 87b628d - [coro.async] Make sure we process async coroutines

2021-01-22 Thread Arnold Schwaighofer via llvm-branch-commits

Author: Arnold Schwaighofer
Date: 2021-01-22T07:04:01-08:00
New Revision: 87b628dadde02b295322c1530d058397c1c4dd14

URL: 
https://github.com/llvm/llvm-project/commit/87b628dadde02b295322c1530d058397c1c4dd14
DIFF: 
https://github.com/llvm/llvm-project/commit/87b628dadde02b295322c1530d058397c1c4dd14.diff

LOG: [coro.async] Make sure we process async coroutines

Because we were not looking for the llvm.coro.id.async intrinsic in the
early coro pass which triggers follow-up passes we relied on the
llvm.coro.end intrinsic being present. This might not be the case in
functions that end in unreachable code.

Differential Revision: https://reviews.llvm.org/D95144

Added: 
llvm/test/Transforms/Coroutines/coro-async-unreachable.ll

Modified: 
llvm/lib/Transforms/Coroutines/CoroEarly.cpp

Removed: 




diff  --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp 
b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
index e134ff7f45c6..1660e41ba830 100644
--- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
@@ -219,9 +219,10 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {
 static bool declaresCoroEarlyIntrinsics(const Module &M) {
   return coro::declaresIntrinsics(
   M, {"llvm.coro.id", "llvm.coro.id.retcon", "llvm.coro.id.retcon.once",
-  "llvm.coro.destroy", "llvm.coro.done", "llvm.coro.end",
-  "llvm.coro.end.async", "llvm.coro.noop", "llvm.coro.free",
-  "llvm.coro.promise", "llvm.coro.resume", "llvm.coro.suspend"});
+  "llvm.coro.id.async", "llvm.coro.destroy", "llvm.coro.done",
+  "llvm.coro.end", "llvm.coro.end.async", "llvm.coro.noop",
+  "llvm.coro.free", "llvm.coro.promise", "llvm.coro.resume",
+  "llvm.coro.suspend"});
 }
 
 PreservedAnalyses CoroEarlyPass::run(Function &F, FunctionAnalysisManager &) {

diff  --git a/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll 
b/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll
new file mode 100644
index ..0ca3a6ce162a
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll
@@ -0,0 +1,105 @@
+; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck --check-prefixes=CHECK %s
+; RUN: opt < %s -enable-coroutines -passes='default' -S | FileCheck 
--check-prefixes=CHECK %s
+
+target datalayout = "p:64:64:64"
+
+%async.task = type { i64 }
+%async.actor = type { i64 }
+%async.fp = type <{ i32, i32 }>
+
+%async.ctxt = type { i8*, void (i8*, %async.task*, %async.actor*)* }
+
+; The async callee.
+@my_other_async_function_fp = external global <{ i32, i32 }>
+declare void @my_other_async_function(i8* %async.ctxt)
+
+; Function that implements the dispatch to the callee function.
+define swiftcc void @my_async_function.my_other_async_function_fp.apply(i8* 
%fnPtr, i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
+  %callee = bitcast i8* %fnPtr to void(i8*, %async.task*, %async.actor*)*
+  tail call swiftcc void %callee(i8* %async.ctxt, %async.task* %task, 
%async.actor* %actor)
+  ret void
+}
+
+declare void @some_user(i64)
+declare void @some_may_write(i64*)
+
+define i8* @resume_context_projection(i8* %ctxt) {
+entry:
+  %resume_ctxt_addr = bitcast i8* %ctxt to i8**
+  %resume_ctxt = load i8*, i8** %resume_ctxt_addr, align 8
+  ret i8* %resume_ctxt
+}
+
+
+@unreachable_fp = constant <{ i32, i32 }>
+  <{ i32 trunc ( ; Relative pointer to async function
+   i64 sub (
+ i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @unreachable 
to i64),
+ i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, 
i32 }>* @unreachable_fp, i32 0, i32 1) to i64)
+   )
+ to i32),
+ i32 128; Initial async context size without space for frame
+}>
+
+define swiftcc void @unreachable(i8* %async.ctxt, %async.task* %task, 
%async.actor* %actor)  {
+entry:
+  %tmp = alloca { i64, i64 }, align 8
+  %proj.1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, 
i32 0
+  %proj.2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, 
i32 1
+
+  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
+  i8* bitcast (<{i32, i32}>* @unreachable_fp to i8*))
+  %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
+  store i64 0, i64* %proj.1, align 8
+  store i64 1, i64* %proj.2, align 8
+  call void @some_may_write(i64* %proj.1)
+
+   ; Begin lowering: apply %my_other_async_function(%args...)
+  ; setup callee context
+  %arg0 = bitcast %async.task* %task to i8*
+  %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
+  %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* 
%arg1)
+   %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
+  ; store the return continuation
+  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, 
%async.ctxt* %callee_context.0, i32 0, i32 1
+  %return_to_caller.addr

[llvm-branch-commits] [llvm] 333108e - Add a llvm.coro.end.async intrinsic

2020-12-22 Thread Arnold Schwaighofer via llvm-branch-commits

Author: Arnold Schwaighofer
Date: 2020-12-22T10:52:28-08:00
New Revision: 333108e8bef8966520defe8602521d0d4e2ef789

URL: 
https://github.com/llvm/llvm-project/commit/333108e8bef8966520defe8602521d0d4e2ef789
DIFF: 
https://github.com/llvm/llvm-project/commit/333108e8bef8966520defe8602521d0d4e2ef789.diff

LOG: Add a llvm.coro.end.async intrinsic

The llvm.coro.end.async intrinsic allows to specify a function that is
to be called as the last action before returning. This function will be
inlined after coroutine splitting.

This function can contain a 'musttail' call to allow for guaranteed tail
calling as the last action.

Differential Revision: https://reviews.llvm.org/D93568

Added: 


Modified: 
llvm/docs/Coroutines.rst
llvm/include/llvm/IR/Intrinsics.td
llvm/lib/Transforms/Coroutines/CoroEarly.cpp
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
llvm/lib/Transforms/Coroutines/CoroInstr.h
llvm/lib/Transforms/Coroutines/CoroInternal.h
llvm/lib/Transforms/Coroutines/CoroSplit.cpp
llvm/lib/Transforms/Coroutines/Coroutines.cpp
llvm/test/Transforms/Coroutines/coro-async.ll

Removed: 




diff  --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst
index 77fb77d9a967..268e9c79ac8f 100644
--- a/llvm/docs/Coroutines.rst
+++ b/llvm/docs/Coroutines.rst
@@ -1389,6 +1389,48 @@ The following table summarizes the handling of 
`coro.end`_ intrinsic.
 || Landingpad  | nothing   | nothing   
|
 
++-+---+---+
 
+
+'llvm.coro.end.async' Intrinsic
+^
+::
+
+  declare i1 @llvm.coro.end.async(i8* , i1 , ...)
+
+Overview:
+"
+
+The '``llvm.coro.end.async``' marks the point where execution of the resume 
part
+of the coroutine should end and control should return to the caller. As part of
+its variable tail arguments this instruction allows to specify a function and
+the function's arguments that are to be tail called as the last action before
+returning.
+
+
+Arguments:
+""
+
+The first argument should refer to the coroutine handle of the enclosing
+coroutine. A frontend is allowed to supply null as the first parameter, in this
+case `coro-early` pass will replace the null with an appropriate coroutine
+handle value.
+
+The second argument should be `true` if this coro.end is in the block that is
+part of the unwind sequence leaving the coroutine body due to an exception and
+`false` otherwise.
+
+The third argument if present should specify a function to be called.
+
+If the third argument is present, the remaining arguments are the arguments to
+the function call.
+
+.. code-block:: llvm
+
+  call i1 (i8*, i1, ...) @llvm.coro.end.async(
+   i8* %hdl, i1 0,
+   void (i8*, %async.task*, %async.actor*)* 
@must_tail_call_return,
+   i8* %ctxt, %async.task* %task, %async.actor* %actor)
+  unreachable
+
 .. _coro.suspend:
 .. _suspend points:
 

diff  --git a/llvm/include/llvm/IR/Intrinsics.td 
b/llvm/include/llvm/IR/Intrinsics.td
index f71dc147416b..aed498d80b02 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1213,6 +1213,8 @@ def int_coro_free : Intrinsic<[llvm_ptr_ty], 
[llvm_token_ty, llvm_ptr_ty],
ReadOnly>,
NoCapture>]>;
 def int_coro_end : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty], []>;
+def int_coro_end_async
+: Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty, llvm_vararg_ty], []>;
 
 def int_coro_frame : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
 def int_coro_noop : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;

diff  --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp 
b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
index 07c571a962b0..e134ff7f45c6 100644
--- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
@@ -164,10 +164,11 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {
 if (cast(&I)->isFinal())
   CB->setCannotDuplicate();
 break;
+  case Intrinsic::coro_end_async:
   case Intrinsic::coro_end:
 // Make sure that fallthrough coro.end is not duplicated as CoroSplit
 // pass expects that there is at most one fallthrough coro.end.
-if (cast(&I)->isFallthrough())
+if (cast(&I)->isFallthrough())
   CB->setCannotDuplicate();
 break;
   case Intrinsic::coro_noop:
@@ -219,8 +220,8 @@ static bool declaresCoroEarlyIntrinsics(const Module &M) {
   return coro::declaresIntrinsics(
   M, {"llvm.coro.id", "llvm.coro.id.retcon", "llvm.coro.id.retcon.once",
   "llvm.coro.destroy", "llvm.coro.done", "llvm.coro.end",
-  "llvm.coro.noop", "llvm.coro.free", "llvm.coro.promise",
-  "llvm.coro.resume",