[llvm] 836421a - [coro] [async] There needs to be a one-to-one corespondance between the async resume function value and the suspend intrinsic (#186436)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 13 14:53:20 PDT 2026
Author: Arnold Schwaighofer
Date: 2026-03-13T14:53:16-07:00
New Revision: 836421ad52585d4247ba22e0fd01265d2beef33a
URL: https://github.com/llvm/llvm-project/commit/836421ad52585d4247ba22e0fd01265d2beef33a
DIFF: https://github.com/llvm/llvm-project/commit/836421ad52585d4247ba22e0fd01265d2beef33a.diff
LOG: [coro] [async] There needs to be a one-to-one corespondance between the async resume function value and the suspend intrinsic (#186436)
We need to mark both the async.resume intrinsic function and the
supsend.async function as not duplicatable. The async.resume function
models the continuation after a suspend. It is non sense to not have a
one-to-one correspondance between the two: if the suspend intrinsic is
cloned so needs to be the matching async.resume intrinsic call.
rdar://172130181
https://github.com/swiftlang/swift/issues/87719
Added:
llvm/test/Transforms/Coroutines/coro-async-noduplicate.ll
Modified:
llvm/include/llvm/IR/Intrinsics.td
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 5b5fffaa48951..4469ff155b854 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1833,12 +1833,12 @@ def int_coro_async_context_dealloc : Intrinsic<[],
[]>;
def int_coro_async_resume : Intrinsic<[llvm_ptr_ty],
[],
- [IntrNoMerge]>;
+ [IntrNoMerge, IntrNoDuplicate]>;
def int_coro_async_size_replace : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], []>;
def int_coro_suspend_async
: Intrinsic<[llvm_any_ty],
[llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_vararg_ty],
- [IntrNoMerge]>;
+ [IntrNoMerge, IntrNoDuplicate]>;
def int_coro_prepare_async : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty],
[IntrNoMem]>;
def int_coro_begin : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
diff --git a/llvm/test/Transforms/Coroutines/coro-async-noduplicate.ll b/llvm/test/Transforms/Coroutines/coro-async-noduplicate.ll
new file mode 100644
index 0000000000000..cb9e8bbf71e06
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-async-noduplicate.ll
@@ -0,0 +1,90 @@
+; RUN: opt -S -passes=simplifycfg < %s | FileCheck %s --check-prefixes=CHECK
+
+;; This used to crash:
+; RUN: opt -S -passes='cgscc(simplifycfg,coro-split)' < %s
+; RUN: opt < %s -O2 -S
+
+target datalayout = "p:64:64:64"
+%swift.async_func_pointer = type <{ i32, i32 }>
+%swift.context = type { ptr, ptr }
+
+declare void @f()
+declare void @g()
+declare void @h()
+declare ptr @llvm.coro.async.resume()
+declare { ptr } @llvm.coro.suspend.async.sl_p0i8s(i32, ptr, ptr, ...)
+declare ptr @llvm.coro.begin(token, ptr writeonly)
+declare token @llvm.coro.id.async(i32, i32, i32, ptr)
+
+declare void @llvm.coro.end.async(ptr, i1, ...)
+
+define linkonce_odr hidden ptr @__swift_async_resume_get_context(ptr %0) {
+entry:
+ ret ptr %0
+}
+
+ at repoTU = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @repo to i64), i64 ptrtoint (ptr @repoTU to i64)) to i32), i32 16 }>, align 8
+
+;; Must not duplicate the suspend intrinsic because it needs to have a
+;; one-to-one correspondance with the async.resume intrinsic.
+
+; CHECK: define {{.*}}@repo
+; CHECK: call {{.*}}coro.async.resume
+; CHECK: call {{.*}}coro.suspend.async
+; CHECK-NOT: call {{.*}}coro.suspend.async
+
+define hidden swifttailcc void @repo(ptr swiftasync %0, i1 %cond) presplitcoroutine {
+entry:
+ %tok = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @repoTU)
+ %id = call ptr @llvm.coro.begin(token %tok, ptr null)
+ call void @f()
+
+ ;; The async.resume intrinsic models the resume function value -- the
+ ;; resumption function of the split coroutine.
+ %ptr0 = call ptr @llvm.coro.async.resume()
+
+ call void @f()
+ br i1 %cond, label %bb1, label %bb2
+
+bb1:
+ call void @f()
+ br label %threadblock
+
+bb2:
+ call void @g()
+ br label %threadblock
+
+;; Former bug: We must not duplicate the suspend intrinsic because it needs to
+;; have a one-to-one correspondance to the async.resume intrinsic (the resume
+;; function continutation value).
+
+threadblock:
+ %c = phi i1 [true, %bb1], [false, %bb2]
+ %t3 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i8s(i32 0, ptr %ptr0, ptr @__swift_async_resume_get_context, ptr @repo.1, ptr %ptr0, ptr %0)
+ call void @h()
+ br i1 %c, label %retblock, label %retblock2
+
+retblock:
+ call void (ptr, i1, ...) @llvm.coro.end.async(ptr %id, i1 false, ptr @repo.0, ptr @return, ptr %0)
+ unreachable
+
+retblock2:
+ call void (ptr, i1, ...) @llvm.coro.end.async(ptr %id, i1 false)
+ unreachable
+}
+
+define internal swifttailcc void @repo.0(ptr %0, ptr %1) {
+entry:
+ musttail call swifttailcc void %0(ptr swiftasync %1)
+ ret void
+}
+
+declare swifttailcc void @swift_task_switch(ptr, ptr)
+
+define internal swifttailcc void @repo.1(ptr %0, ptr %1) {
+entry:
+ musttail call swifttailcc void @swift_task_switch(ptr swiftasync %1, ptr %0)
+ ret void
+}
+
+declare swifttailcc void @return(ptr swiftasync)
More information about the llvm-commits
mailing list