[llvm] [Coro] [async] Disable inlining in async coroutine splitting (PR #80904)

Arnold Schwaighofer via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 7 08:03:20 PST 2024


https://github.com/aschwaighofer updated https://github.com/llvm/llvm-project/pull/80904

>From 5c9b5bac8139b8622345e4a13ef6ac9388e71d66 Mon Sep 17 00:00:00 2001
From: Arnold Schwaighofer <aschwaighofer at apple.com>
Date: Mon, 9 Oct 2023 09:03:44 -0700
Subject: [PATCH] [Coro] [async] Disable inlining in async coroutine splitting

The call to the inlining utility does not update the call graph.
Leading to assertion failures when calling the utility to update the
call graph.

Instead rely on an inline pass to run after coro splitting and use
alwaysinline annotations.

github.com/apple/swift/issues/68708
---
 llvm/lib/Transforms/Coroutines/CoroSplit.cpp  |  12 +-
 ...o-async-addr-lifetime-infinite-loop-bug.ll |   8 +-
 .../coro-async-addr-lifetime-start-bug.ll     |   6 +-
 .../Coroutines/coro-async-dyn-align.ll        |  10 +-
 .../Coroutines/coro-async-mutal-recursive.ll  | 158 ++++++++++++++++++
 .../Coroutines/coro-async-unreachable.ll      |  10 +-
 llvm/test/Transforms/Coroutines/coro-async.ll |  76 ++++-----
 .../Transforms/Coroutines/swift-async-dbg.ll  |  30 ++--
 8 files changed, 229 insertions(+), 81 deletions(-)
 create mode 100644 llvm/test/Transforms/Coroutines/coro-async-mutal-recursive.ll

diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index a552b3ac20085..aed4cd027d033 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -208,17 +208,12 @@ static bool replaceCoroEndAsync(AnyCoroEndInst *End) {
   // Insert the return instruction.
   Builder.SetInsertPoint(End);
   Builder.CreateRetVoid();
-  InlineFunctionInfo FnInfo;
 
   // Remove the rest of the block, by splitting it into an unreachable block.
   auto *BB = End->getParent();
   BB->splitBasicBlock(End);
   BB->getTerminator()->eraseFromParent();
 
-  auto InlineRes = InlineFunction(*MustTailCall, FnInfo);
-  assert(InlineRes.isSuccess() && "Expected inlining to succeed");
-  (void)InlineRes;
-
   // We have cleaned up the coro.end block above.
   return false;
 }
@@ -1842,13 +1837,8 @@ static void splitAsyncCoroutine(Function &F, coro::Shape &Shape,
     SmallVector<Value *, 8> Args(Suspend->args());
     auto FnArgs = ArrayRef<Value *>(Args).drop_front(
         CoroSuspendAsyncInst::MustTailCallFuncArg + 1);
-    auto *TailCall =
-        coro::createMustTailCall(Suspend->getDebugLoc(), Fn, FnArgs, Builder);
+    coro::createMustTailCall(Suspend->getDebugLoc(), Fn, FnArgs, Builder);
     Builder.CreateRetVoid();
-    InlineFunctionInfo FnInfo;
-    auto InlineRes = InlineFunction(*TailCall, FnInfo);
-    assert(InlineRes.isSuccess() && "Expected inlining to succeed");
-    (void)InlineRes;
 
     // Replace the lvm.coro.async.resume intrisic call.
     replaceAsyncResumeFunction(Suspend, Continuation);
diff --git a/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-infinite-loop-bug.ll b/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-infinite-loop-bug.ll
index 07b3bd8fa94ac..4960709932948 100644
--- a/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-infinite-loop-bug.ll
+++ b/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-infinite-loop-bug.ll
@@ -22,8 +22,8 @@ declare void @my_other_async_function(ptr %async.ctxt)
      i32 128    ; Initial async context size without space for frame
 }>
 
-define swiftcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {
-  tail call swiftcc void %fnPtr(ptr %async.ctxt)
+define swifttailcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) alwaysinline {
+  tail call swifttailcc void %fnPtr(ptr %async.ctxt)
   ret void
 }
 
@@ -37,12 +37,12 @@ entry:
 
 ; The address of alloca escapes but the analysis based on lifetimes fails to see
 ; that it can't localize this alloca.
-; CHECK: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {
+; CHECK: define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) {
 ; CHECK: entry:
 ; CHECK-NOT: ret
 ; CHECK-NOT:   [[ESCAPED_ADDR:%.*]] = alloca i64, align 8
 ; CHECK: ret
-define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {
+define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) {
 entry:
   %escaped_addr = alloca i64
 
diff --git a/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-start-bug.ll b/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-start-bug.ll
index 2306b72a0055f..42377285f77ca 100644
--- a/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-start-bug.ll
+++ b/llvm/test/Transforms/Coroutines/coro-async-addr-lifetime-start-bug.ll
@@ -22,8 +22,8 @@ declare void @my_other_async_function(ptr %async.ctxt)
      i32 128    ; Initial async context size without space for frame
 }>
 
-define swiftcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {
-  tail call swiftcc void %fnPtr(ptr %async.ctxt)
+define swifttailcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) alwaysinline {
+  tail call swifttailcc void %fnPtr(ptr %async.ctxt)
   ret void
 }
 
@@ -36,7 +36,7 @@ entry:
   ret ptr %resume_ctxt
 }
 
-define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {
+define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) {
 entry:
   %escaped_addr = alloca i64
 
diff --git a/llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll b/llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll
index 040c9881c1ab3..567977ea1476d 100644
--- a/llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll
+++ b/llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll
@@ -33,12 +33,12 @@ declare swiftcc void @asyncReturn(ptr)
 declare swiftcc void @asyncSuspend(ptr)
 declare {ptr} @llvm.coro.suspend.async(i32, ptr, ptr, ...)
 
-define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {
-  tail call swiftcc void %fnPtr(ptr %async.ctxt)
+define swifttailcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) alwaysinline {
+  musttail call swifttailcc void %fnPtr(ptr %async.ctxt)
   ret void
 }
 
-define ptr @__swift_async_resume_project_context(ptr %ctxt) {
+define ptr @__swift_async_resume_project_context(ptr %ctxt) alwaysinline {
 entry:
   %resume_ctxt = load ptr, ptr %ctxt, align 8
   ret ptr %resume_ctxt
@@ -46,7 +46,7 @@ entry:
 
 
 ; CHECK: %my_async_function.Frame = type { i64, [48 x i8], i64, i64, [16 x i8], ptr, i64, ptr }
-; CHECK: define swiftcc void @my_async_function
+; CHECK: define swifttailcc void @my_async_function
 ; CHECK:  [[T0:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr %async.ctx.frameptr, i32 0, i32 3
 ; CHECK:  [[T1:%.*]] = ptrtoint ptr [[T0]] to i64
 ; CHECK:  [[T2:%.*]] = add i64 [[T1]], 31
@@ -60,7 +60,7 @@ entry:
 ; CHECK:  store i64 2, ptr [[T4]]
 ; CHECK:  store i64 3, ptr [[T9]]
 
-define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) presplitcoroutine {
+define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt) presplitcoroutine {
 entry:
   %tmp = alloca i64, align 8
   %tmp2 = alloca i64, align 16
diff --git a/llvm/test/Transforms/Coroutines/coro-async-mutal-recursive.ll b/llvm/test/Transforms/Coroutines/coro-async-mutal-recursive.ll
new file mode 100644
index 0000000000000..4931fe998daa6
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-async-mutal-recursive.ll
@@ -0,0 +1,158 @@
+; RUN: opt < %s -passes='default<O2>' -S | FileCheck --check-prefixes=CHECK %s
+; RUN: opt < %s -O0 -S | FileCheck --check-prefixes=CHECK-O0 %s
+
+
+; CHECK-NOT: llvm.coro.suspend.async
+; CHECK-O0-NOT: llvm.coro.suspend.async
+
+; This test used to crash during updating the call graph in coro splitting.
+
+target datalayout = "p:64:64:64"
+
+%swift.async_func_pointer = type <{ i32, i32 }>
+
+@"$s1d3fooyySbYaFTu" = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s1d3fooyySbYaF" to i64), i64 ptrtoint (ptr @"$s1d3fooyySbYaFTu" to i64)) to i32), i32 16 }>
+@"$s1d3baryySbYaFTu" = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s1d3baryySbYaF" to i64), i64 ptrtoint (ptr @"$s1d3baryySbYaFTu" to i64)) to i32), i32 16 }>
+
+define swifttailcc void @"$s1d3fooyySbYaF"(ptr swiftasync %0, i1 %1) {
+entry:
+  %2 = alloca ptr, align 8
+  %c.debug = alloca i1, align 8
+  %3 = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @"$s1d3fooyySbYaFTu")
+  %4 = call ptr @llvm.coro.begin(token %3, ptr null)
+  store ptr %0, ptr %2, align 8
+  call void @llvm.memset.p0.i64(ptr align 8 %c.debug, i8 0, i64 1, i1 false)
+  store i1 %1, ptr %c.debug, align 8
+  call void asm sideeffect "", "r"(ptr %c.debug)
+  %5 = load i32, ptr getelementptr inbounds (%swift.async_func_pointer, ptr @"$s1d3baryySbYaFTu", i32 0, i32 1), align 8
+  %6 = zext i32 %5 to i64
+  %7 = call swiftcc ptr @swift_task_alloc(i64 %6) #4
+  call void @llvm.lifetime.start.p0(i64 -1, ptr %7)
+  %8 = load ptr, ptr %2, align 8
+  %9 = getelementptr inbounds <{ ptr, ptr }>, ptr %7, i32 0, i32 0
+  store ptr %8, ptr %9, align 8
+  %10 = call ptr @llvm.coro.async.resume()
+  %11 = getelementptr inbounds <{ ptr, ptr }>, ptr %7, i32 0, i32 1
+  store ptr %10, ptr %11, align 8
+  %12 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0s(i32 0, ptr %10, ptr @__swift_async_resume_project_context, ptr @"$s1d3fooyySbYaF.0", ptr @"$s1d3baryySbYaF", ptr %7, i1 %1)
+  %13 = extractvalue { ptr } %12, 0
+  %14 = call ptr @__swift_async_resume_project_context(ptr %13)
+  store ptr %14, ptr %2, align 8
+  call swiftcc void @swift_task_dealloc(ptr %7) #4
+  call void @llvm.lifetime.end.p0(i64 -1, ptr %7)
+  %15 = load ptr, ptr %2, align 8
+  %16 = getelementptr inbounds <{ ptr, ptr }>, ptr %15, i32 0, i32 1
+  %17 = load ptr, ptr %16, align 8
+  %18 = load ptr, ptr %2, align 8
+  %19 = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %4, i1 false, ptr @"$s1d3fooyySbYaF.0.1", ptr %17, ptr %18)
+  unreachable
+}
+
+declare token @llvm.coro.id.async(i32, i32, i32, ptr) #1
+
+declare void @llvm.trap() #2
+
+declare ptr @llvm.coro.begin(token, ptr) #1
+
+declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1 immarg) #3
+
+define hidden swifttailcc void @"$s1d3baryySbYaF"(ptr swiftasync %0, i1 %1) {
+entry:
+  %2 = alloca ptr, align 8
+  %c.debug = alloca i1, align 8
+  %3 = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @"$s1d3baryySbYaFTu")
+  %4 = call ptr @llvm.coro.begin(token %3, ptr null)
+  store ptr %0, ptr %2, align 8
+  call void @llvm.memset.p0.i64(ptr align 8 %c.debug, i8 0, i64 1, i1 false)
+  store i1 %1, ptr %c.debug, align 8
+  call void asm sideeffect "", "r"(ptr %c.debug)
+  br i1 %1, label %5, label %17
+
+5:                                                ; preds = %entry
+  %6 = xor i1 %1, true
+  %7 = load i32, ptr getelementptr inbounds (%swift.async_func_pointer, ptr @"$s1d3fooyySbYaFTu", i32 0, i32 1), align 8
+  %8 = zext i32 %7 to i64
+  %9 = call swiftcc ptr @swift_task_alloc(i64 %8) #4
+  call void @llvm.lifetime.start.p0(i64 -1, ptr %9)
+  %10 = load ptr, ptr %2, align 8
+  %11 = getelementptr inbounds <{ ptr, ptr }>, ptr %9, i32 0, i32 0
+  store ptr %10, ptr %11, align 8
+  %12 = call ptr @llvm.coro.async.resume()
+  %13 = getelementptr inbounds <{ ptr, ptr }>, ptr %9, i32 0, i32 1
+  store ptr %12, ptr %13, align 8
+  %14 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0s(i32 0, ptr %12, ptr @__swift_async_resume_project_context, ptr @"$s1d3baryySbYaF.0.2", ptr @"$s1d3fooyySbYaF", ptr %9, i1 %6)
+  %15 = extractvalue { ptr } %14, 0
+  %16 = call ptr @__swift_async_resume_project_context(ptr %15)
+  store ptr %16, ptr %2, align 8
+  call swiftcc void @swift_task_dealloc(ptr %9) #4
+  call void @llvm.lifetime.end.p0(i64 -1, ptr %9)
+  br label %18
+
+17:                                               ; preds = %entry
+  br label %18
+
+18:                                               ; preds = %5, %17
+  %19 = load ptr, ptr %2, align 8
+  %20 = getelementptr inbounds <{ ptr, ptr }>, ptr %19, i32 0, i32 1
+  %21 = load ptr, ptr %20, align 8
+  %22 = load ptr, ptr %2, align 8
+  %23 = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %4, i1 false, ptr @"$s1d3baryySbYaF.0", ptr %21, ptr %22)
+  unreachable
+}
+
+declare swiftcc ptr @swift_task_alloc(i64) #4
+
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #5
+
+declare ptr @llvm.coro.async.resume() #6
+
+define linkonce_odr hidden ptr @__swift_async_resume_project_context(ptr %0) #7 {
+entry:
+  %1 = load ptr, ptr %0, align 8
+  %2 = call ptr @llvm.swift.async.context.addr()
+  store ptr %1, ptr %2, align 8
+  ret ptr %1
+}
+
+declare ptr @llvm.swift.async.context.addr() #1
+
+define internal swifttailcc void @"$s1d3fooyySbYaF.0"(ptr %0, ptr %1, i1 %2) #8 {
+entry:
+  musttail call swifttailcc void %0(ptr swiftasync %1, i1 %2)
+  ret void
+}
+
+declare { ptr } @llvm.coro.suspend.async.sl_p0s(i32, ptr, ptr, ...) #6
+
+declare swiftcc void @swift_task_dealloc(ptr) #4
+
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #5
+
+define internal swifttailcc void @"$s1d3fooyySbYaF.0.1"(ptr %0, ptr %1) #8 {
+entry:
+  musttail call swifttailcc void %0(ptr swiftasync %1)
+  ret void
+}
+
+declare i1 @llvm.coro.end.async(ptr, i1, ...) #1
+
+define internal swifttailcc void @"$s1d3baryySbYaF.0"(ptr %0, ptr %1) #8 {
+entry:
+  musttail call swifttailcc void %0(ptr swiftasync %1)
+  ret void
+}
+
+define internal swifttailcc void @"$s1d3baryySbYaF.0.2"(ptr %0, ptr %1, i1 %2) #8 {
+entry:
+  musttail call swifttailcc void %0(ptr swiftasync %1, i1 %2)
+  ret void
+}
+
+attributes #1 = { nounwind }
+attributes #2 = { cold noreturn nounwind }
+attributes #3 = { nocallback nofree nounwind willreturn}
+attributes #4 = { nounwind }
+attributes #5 = { nocallback nofree nosync nounwind willreturn }
+attributes #6 = { nomerge nounwind }
+attributes #7 = { alwaysinline nounwind }
+attributes #8 = { alwaysinline nounwind }
diff --git a/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll b/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll
index 79ef8939b0ecc..ed4f526b8ed98 100644
--- a/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll
+++ b/llvm/test/Transforms/Coroutines/coro-async-unreachable.ll
@@ -13,8 +13,8 @@ target datalayout = "p:64:64:64"
 declare void @my_other_async_function(ptr %async.ctxt)
 
 ; Function that implements the dispatch to the callee function.
-define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
-  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
+define swifttailcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) alwaysinline {
+  musttail call swifttailcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
   ret void
 }
 
@@ -38,7 +38,7 @@ entry:
      i32 128    ; Initial async context size without space for frame
 }>
 
-define swiftcc void @unreachable(ptr %async.ctxt, ptr %task, ptr %actor)  {
+define swifttailcc void @unreachable(ptr %async.ctxt, ptr %task, ptr %actor)  {
 entry:
   %tmp = alloca { i64, i64 }, align 8
   %proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
@@ -77,11 +77,11 @@ entry:
   unreachable
 }
 
-; CHECK: define swiftcc void @unreachable
+; CHECK: define swifttailcc void @unreachable
 ; CHECK-NOT: @llvm.coro.suspend.async
 ; CHECK: return
 
-; CHECK: define internal swiftcc void @unreachable.resume.0
+; CHECK: define internal swifttailcc void @unreachable.resume.0
 ; CHECK: unreachable
 
 declare ptr @llvm.coro.prepare.async(ptr)
diff --git a/llvm/test/Transforms/Coroutines/coro-async.ll b/llvm/test/Transforms/Coroutines/coro-async.ll
index 3740c3d1d8387..8ead304fe2988 100644
--- a/llvm/test/Transforms/Coroutines/coro-async.ll
+++ b/llvm/test/Transforms/Coroutines/coro-async.ll
@@ -37,28 +37,28 @@ declare void @my_other_async_function(ptr %async.ctxt)
 }>
 
 ; Function that implements the dispatch to the callee function.
-define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
-  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
+define swifttailcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) alwaysinline {
+  musttail call swifttailcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
   ret void
 }
 
 declare void @some_user(i64)
 declare void @some_may_write(ptr)
 
-define ptr @__swift_async_resume_project_context(ptr %ctxt) {
+define ptr @__swift_async_resume_project_context(ptr %ctxt) alwaysinline {
 entry:
   %resume_ctxt = load ptr, ptr %ctxt, align 8
   ret ptr %resume_ctxt
 }
 
-define ptr @resume_context_projection(ptr %ctxt) {
+define ptr @resume_context_projection(ptr %ctxt) alwaysinline {
 entry:
   %resume_ctxt = load ptr, ptr %ctxt, align 8
   ret ptr %resume_ctxt
 }
 
 
-define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine !dbg !1 {
+define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine !dbg !1 {
 entry:
   %tmp = alloca { i64, i64 }, align 8
   %vector = alloca <4 x double>, align 16
@@ -100,7 +100,7 @@ entry:
   %val.2 = load i64, ptr %proj.2
   call void @some_user(i64 %val.2)
   store <4 x double> %vector_spill, ptr %vector, align 16
-  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
+  tail call swifttailcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
   call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
   unreachable
 }
@@ -116,8 +116,8 @@ define void @my_async_function_pa(ptr %ctxt, ptr %task, ptr %actor) {
 ; CHECK: @my_async_function_pa_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
 ; CHECK: @my_async_function2_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
 
-; CHECK-LABEL: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
-; CHECK-O0-LABEL: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
+; CHECK-LABEL: define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
+; CHECK-O0-LABEL: define swifttailcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
 ; CHECK-SAME: !dbg ![[SP1:[0-9]+]] {
 ; CHECK: coro.return:
 ; CHECK:   [[FRAMEPTR:%.*]] = getelementptr inbounds i8, ptr %async.ctxt, i64 128
@@ -139,12 +139,12 @@ define void @my_async_function_pa(ptr %ctxt, ptr %task, ptr %actor) {
 ; CHECK-O0:   [[VECTOR_SPILL:%.*]] = load <4 x double>, ptr {{.*}}
 ; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr {{.*}}, i32 0, i32 1
 ; CHECK-O0:   store <4 x double> [[VECTOR_SPILL]], ptr [[VECTOR_SPILL_ADDR]], align 16
-; CHECK:   tail call swiftcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
+; CHECK:   tail call swifttailcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
 ; CHECK:   ret void
 ; CHECK: }
 
-; CHECK-LABEL: define internal swiftcc void @my_async_functionTQ0_(ptr nocapture readonly swiftasync %0, ptr %1, ptr nocapture readnone %2)
-; CHECK-O0-LABEL: define internal swiftcc void @my_async_functionTQ0_(ptr swiftasync %0, ptr %1, ptr %2)
+; CHECK-LABEL: define internal swifttailcc void @my_async_functionTQ0_(ptr nocapture readonly swiftasync %0, ptr %1, ptr nocapture readnone %2)
+; CHECK-O0-LABEL: define internal swifttailcc void @my_async_functionTQ0_(ptr swiftasync %0, ptr %1, ptr %2)
 ; CHECK-SAME: !dbg ![[SP2:[0-9]+]] {
 ; CHECK: entryresume.0:
 ; CHECK:   [[CALLER_CONTEXT:%.*]] = load ptr, ptr %0
@@ -163,7 +163,7 @@ define void @my_async_function_pa(ptr %ctxt, ptr %task, ptr %actor) {
 ; CHECK:   tail call void @some_user(i64 [[VAL1]])
 ; CHECK:   [[VAL2:%.*]] = load i64, ptr [[ALLOCA_PRJ2]]
 ; CHECK:   tail call void @some_user(i64 [[VAL2]])
-; CHECK:   tail call swiftcc void @asyncReturn(ptr [[ASYNC_CTXT_RELOAD]], ptr %1, ptr [[ACTOR_RELOAD]])
+; CHECK:   tail call swifttailcc void @asyncReturn(ptr [[ASYNC_CTXT_RELOAD]], ptr %1, ptr [[ACTOR_RELOAD]])
 ; CHECK:   ret void
 ; CHECK: }
 
@@ -177,7 +177,7 @@ define void @my_async_function_pa(ptr %ctxt, ptr %task, ptr %actor) {
      i32 128    ; Initial async context size without space for frame
   }>
 
-define swiftcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt) presplitcoroutine "frame-pointer"="all" !dbg !6 {
+define swifttailcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt) presplitcoroutine "frame-pointer"="all" !dbg !6 {
 entry:
 
   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 2, ptr @my_async_function2_fp)
@@ -210,12 +210,12 @@ entry:
   call void @llvm.coro.async.context.dealloc(ptr %callee_context)
   %continuation_actor_arg = extractvalue {ptr, ptr, ptr} %res.2, 1
 
-  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %continuation_actor_arg)
+  tail call swifttailcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %continuation_actor_arg)
   call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
   unreachable
 }
 
-; CHECK-LABEL: define swiftcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt)
+; CHECK-LABEL: define swifttailcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt)
 ; CHECK-SAME: #[[FRAMEPOINTER:[0-9]+]]
 ; CHECK-SAME: !dbg ![[SP3:[0-9]+]]
 ; CHECK: store ptr %async.ctxt,
@@ -225,22 +225,22 @@ entry:
 ; CHECK: store ptr [[CALLEE_CTXT]],
 ; CHECK: store ptr @my_async_function2.resume.0,
 ; CHECK: store ptr %async.ctxt,
-; CHECK: tail call swiftcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
+; CHECK: tail call swifttailcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
 ; CHECK: ret void
 
-; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(ptr %0, ptr nocapture readnone %1, ptr nocapture readonly %2)
+; CHECK-LABEL: define internal swifttailcc void @my_async_function2.resume.0(ptr %0, ptr nocapture readnone %1, ptr nocapture readonly %2)
 ; CHECK-SAME: #[[FRAMEPOINTER]]
 ; CHECK-SAME: !dbg ![[SP4:[0-9]+]]
 ; CHECK: [[CALLEE_CTXT:%.*]] = load ptr, ptr %2
 ; CHECK: [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, ptr [[CALLEE_CTXT]], i64 152
 ; CHECK: store ptr @my_async_function2.resume.1,
 ; CHECK: [[CALLLE_CTXT_RELOAD:%.*]] = load ptr, ptr [[CALLEE_CTXT_SPILL_ADDR]]
-; CHECK: tail call swiftcc void @asyncSuspend(ptr [[CALLEE_CTXT_RELOAD]]
+; CHECK: tail call swifttailcc void @asyncSuspend(ptr [[CALLEE_CTXT_RELOAD]]
 ; CHECK: ret void
 
-; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.1(ptr nocapture readonly %0, ptr %1, ptr nocapture readnone %2)
+; CHECK-LABEL: define internal swifttailcc void @my_async_function2.resume.1(ptr nocapture readonly %0, ptr %1, ptr nocapture readnone %2)
 ; CHECK-SAME: #[[FRAMEPOINTER]]
-; CHECK: tail call swiftcc void @asyncReturn({{.*}}%1)
+; CHECK: tail call swifttailcc void @asyncReturn({{.*}}%1)
 ; CHECK: ret void
 
 define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor) {
@@ -252,7 +252,7 @@ define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor) {
 ; CHECK-LABEL: define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor)
 ; CHECK: store ptr @my_async_functionTQ0_
 ; CHECK: store ptr %ctxt
-; CHECK: tail call swiftcc void @asyncSuspend
+; CHECK: tail call swifttailcc void @asyncSuspend
 ; CHECK: ret void
 
 @dont_crash_on_cf_fp = constant <{ i32, i32 }>
@@ -266,7 +266,7 @@ define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor) {
 }>
 
 
-define swiftcc void @dont_crash_on_cf_dispatch(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
+define swifttailcc void @dont_crash_on_cf_dispatch(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) alwaysinline {
   %isNull = icmp eq ptr %task, null
   br i1 %isNull, label %is_null, label %is_not_null
 
@@ -274,11 +274,11 @@ is_null:
   ret void
 
 is_not_null:
-  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
+  musttail call swifttailcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
   ret void
 }
 
-define swiftcc void @dont_crash_on_cf(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine  {
+define swifttailcc void @dont_crash_on_cf(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine  {
 entry:
   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
           ptr @dont_crash_on_cf_fp)
@@ -296,7 +296,7 @@ entry:
 
   call void @llvm.coro.async.context.dealloc(ptr %callee_context)
   %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
-  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
+  tail call swifttailcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
   call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
   unreachable
 }
@@ -311,12 +311,12 @@ entry:
      i32 128    ; Initial async context size without space for frame
 }>
 
-define swiftcc void @must_tail_call_return(ptr %async.ctxt, ptr %task, ptr %actor) {
-  musttail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %task, ptr %actor)
+define swifttailcc void @must_tail_call_return(ptr %async.ctxt, ptr %task, ptr %actor) alwaysinline {
+  musttail call swifttailcc void @asyncReturn(ptr %async.ctxt, ptr %task, ptr %actor)
   ret void
 }
 
-define swiftcc void @multiple_coro_end_async(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
+define swifttailcc void @multiple_coro_end_async(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
 entry:
   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
           ptr @dont_crash_on_cf_fp)
@@ -350,8 +350,8 @@ is_not_equal:
   unreachable
 }
 
-; CHECK-LABEL: define internal swiftcc void @multiple_coro_end_async.resume.0(
-; CHECK: musttail call swiftcc void @asyncReturn(
+; CHECK-LABEL: define internal swifttailcc void @multiple_coro_end_async.resume.0(
+; CHECK: musttail call swifttailcc void @asyncReturn(
 ; CHECK: ret void
 
 @polymorphic_suspend_return_fp = constant <{ i32, i32 }>
@@ -364,7 +364,7 @@ is_not_equal:
      i32 64    ; Initial async context size without space for frame
 }>
 
-define swiftcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
+define swifttailcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
 entry:
   %tmp = alloca { i64, i64 }, align 8
   %proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
@@ -405,13 +405,13 @@ entry:
   %val.2 = load i64, ptr %proj.2
   call void @some_user(i64 %val.2)
 
-  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
+  tail call swifttailcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
   call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
   unreachable
 }
 
-; CHECK-LABEL: define swiftcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
-; CHECK-LABEL: define internal swiftcc void @polymorphic_suspend_return.resume.0(ptr {{.*}}swiftasync{{.*}} %0, ptr {{.*}}swiftself{{.*}} %1, ptr {{.*}}%2, ptr {{.*}}%3)
+; CHECK-LABEL: define swifttailcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
+; CHECK-LABEL: define internal swifttailcc void @polymorphic_suspend_return.resume.0(ptr {{.*}}swiftasync{{.*}} %0, ptr {{.*}}swiftself{{.*}} %1, ptr {{.*}}%2, ptr {{.*}}%3)
 ; CHECK: }
 
 @no_coro_suspend_fp = constant <{ i32, i32 }>
@@ -481,7 +481,7 @@ entry:
 declare void @crash()
 declare void @use(ptr)
 
-define swiftcc void @undefined_coro_async_resume(ptr %async.ctx) presplitcoroutine {
+define swifttailcc void @undefined_coro_async_resume(ptr %async.ctx) presplitcoroutine {
 entry:
   %id = call token @llvm.coro.id.async(i32 24, i32 16, i32 0, ptr @undefined_coro_async_resume_fp)
   %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
@@ -491,7 +491,7 @@ entry:
   %unused = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 false)
   unreachable
 }
-; CHECK-LABEL: define swiftcc void @undefined_coro_async_resume
+; CHECK-LABEL: define swifttailcc void @undefined_coro_async_resume
 ; CHECK-NOT: @llvm.coro.async.resume
 ; CHECK: call void @use(ptr null)
 ; CHECK: ret
@@ -505,8 +505,8 @@ declare i1 @llvm.coro.end(ptr, i1, token)
 declare {ptr, ptr, ptr} @llvm.coro.suspend.async(i32, ptr, ptr, ...)
 declare ptr @llvm.coro.async.context.alloc(ptr, ptr)
 declare void @llvm.coro.async.context.dealloc(ptr)
-declare swiftcc void @asyncReturn(ptr, ptr, ptr)
-declare swiftcc void @asyncSuspend(ptr, ptr, ptr)
+declare swifttailcc void @asyncReturn(ptr, ptr, ptr)
+declare swifttailcc void @asyncSuspend(ptr, ptr, ptr)
 declare ptr @llvm.coro.async.resume()
 declare void @llvm.coro.async.size.replace(ptr, ptr)
 declare ptr @hide(ptr)
diff --git a/llvm/test/Transforms/Coroutines/swift-async-dbg.ll b/llvm/test/Transforms/Coroutines/swift-async-dbg.ll
index 74edf7a3f3a54..a78bcdf0ddee2 100644
--- a/llvm/test/Transforms/Coroutines/swift-async-dbg.ll
+++ b/llvm/test/Transforms/Coroutines/swift-async-dbg.ll
@@ -1,13 +1,13 @@
-; RUN: opt -mtriple='arm64-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s
-; RUN: opt -mtriple='x86_64' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s
-; RUN: opt -mtriple='i386-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s --check-prefix=NOENTRY
-; RUN: opt -mtriple='armv7-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s --check-prefix=NOENTRY
+; RUN: opt -mtriple='arm64-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s
+; RUN: opt -mtriple='x86_64' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s
+; RUN: opt -mtriple='i386-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s --check-prefix=NOENTRY
+; RUN: opt -mtriple='armv7-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s --check-prefix=NOENTRY
 
 ;; Replicate those tests with non-instruction debug markers.
-; RUN: opt --try-experimental-debuginfo-iterators -mtriple='arm64-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s
-; RUN: opt --try-experimental-debuginfo-iterators -mtriple='x86_64' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s
-; RUN: opt --try-experimental-debuginfo-iterators -mtriple='i386-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s --check-prefix=NOENTRY
-; RUN: opt --try-experimental-debuginfo-iterators -mtriple='armv7-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg)' -o - | FileCheck %s --check-prefix=NOENTRY
+; RUN: opt --try-experimental-debuginfo-iterators -mtriple='arm64-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s
+; RUN: opt --try-experimental-debuginfo-iterators -mtriple='x86_64' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s
+; RUN: opt --try-experimental-debuginfo-iterators -mtriple='i386-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s --check-prefix=NOENTRY
+; RUN: opt --try-experimental-debuginfo-iterators -mtriple='armv7-' %s -S -passes='module(coro-early),cgscc(coro-split,simplifycfg),always-inline' -o - | FileCheck %s --check-prefix=NOENTRY
 
 ; NOENTRY-NOT: OP_llvm_entry_value
 
@@ -93,29 +93,29 @@ define swifttailcc void @coroutineA(ptr swiftasync %arg) !dbg !48 {
 @coroutineBTu = global <{i32, i32}> <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"coroutineB" to i64), i64 ptrtoint (ptr @"coroutineBTu" to i64)) to i32), i32 16 }>, align 8
 @coroutineATu = global <{i32, i32}> <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"coroutineA" to i64), i64 ptrtoint (ptr @"coroutineATu" to i64)) to i32), i32 16 }>, align 8
 
-define weak_odr hidden ptr @__swift_async_resume_get_context(ptr %arg) !dbg !64 {
+define weak_odr hidden ptr @__swift_async_resume_get_context(ptr %arg) alwaysinline !dbg !64 {
   ret ptr %arg, !dbg !65
 }
-define hidden swifttailcc void @coroutineA.1(ptr %arg, i64 %arg1, i64 %arg2, ptr %arg3) !dbg !66 {
+define hidden swifttailcc void @coroutineA.1(ptr %arg, i64 %arg1, i64 %arg2, ptr %arg3) alwaysinline !dbg !66 {
   musttail call swifttailcc void @swift_task_switch(ptr swiftasync %arg3, ptr %arg, i64 %arg1, i64 %arg2), !dbg !67
   ret void, !dbg !67
 }
 
-define weak_odr hidden ptr @__swift_async_resume_project_context(ptr %arg) !dbg !68 {
+define weak_odr hidden ptr @__swift_async_resume_project_context(ptr %arg) alwaysinline !dbg !68 {
   %i1 = load ptr, ptr %arg, align 8, !dbg !69
   %i2 = call ptr @llvm.swift.async.context.addr(), !dbg !69
   store ptr %i1, ptr %i2, align 8, !dbg !69
   ret ptr %i1, !dbg !69
 }
-define hidden swifttailcc void @coroutineA.0(ptr %arg, ptr %arg1) !dbg !70 {
+define hidden swifttailcc void @coroutineA.0(ptr %arg, ptr %arg1) alwaysinline !dbg !70 {
   musttail call swifttailcc void %arg(ptr swiftasync %arg1), !dbg !71
   ret void, !dbg !71
 }
-define hidden swifttailcc void @coroutineA.0.1(ptr %arg, ptr %arg1) !dbg !72 {
+define hidden swifttailcc void @coroutineA.0.1(ptr %arg, ptr %arg1) alwaysinline !dbg !72 {
   musttail call swifttailcc void %arg(ptr swiftasync %arg1), !dbg !73
   ret void, !dbg !73
 }
-define swifttailcc void @coroutineB(ptr swiftasync %arg) !dbg !37 {
+define swifttailcc void @coroutineB(ptr swiftasync %arg) alwaysinline !dbg !37 {
   %i2 = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr nonnull @coroutineBTu)
   %i3 = call ptr @llvm.coro.begin(token %i2, ptr null)
   %i6 = getelementptr inbounds <{ ptr, ptr }>, ptr %arg, i64 0, i32 1, !dbg !42
@@ -123,7 +123,7 @@ define swifttailcc void @coroutineB(ptr swiftasync %arg) !dbg !37 {
   %i10 = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %i3, i1 false, ptr nonnull @coroutineB.0, ptr %i712, ptr %arg), !dbg !42
   unreachable, !dbg !42
 }
-define hidden swifttailcc void @coroutineB.0(ptr %arg, ptr %arg1) !dbg !44 {
+define hidden swifttailcc void @coroutineB.0(ptr %arg, ptr %arg1) alwaysinline !dbg !44 {
   musttail call swifttailcc void %arg(ptr swiftasync %arg1), !dbg !47
   ret void, !dbg !47
 }



More information about the llvm-commits mailing list