// RUN: %target-swift-frontend -enable-experimental-concurrency -enable-objc-interop -primary-file %s -emit-ir -sil-verify-all -disable-llvm-optzns -disable-swift-specific-llvm-optzns | %IRGenFileCheck %s // RUN: %target-swift-frontend -enable-experimental-concurrency -enable-objc-interop -primary-file %s -emit-ir -sil-verify-all // REQUIRES: concurrency import Builtin import Swift import _Concurrency sil @not_async_test : $@convention(thin) () -> () { bb0: %0 = tuple () return %0 : $() } // CHECK-LABEL: define{{.*}} @async_continuation( // CHECK: [[ctxt_addr:%.*]] = alloca %swift.context* // CHECK: [[cont_context:%.*]] = alloca %swift.continuation_context // CHECK: [[result_storage:%.*]] = alloca i32 // CHECK: call token @llvm.coro.id.async // CHECK: call i8* @llvm.coro.begin( // Initialize the async continuation context: // Initialize Parent. // CHECK: [[base_context:%.*]] = getelementptr inbounds %swift.continuation_context, %swift.continuation_context* [[cont_context]], i32 0, i32 0 // CHECK: [[context_addr:%.*]] = getelementptr inbounds %swift.context, %swift.context* [[base_context]], i32 0, i32 0 // CHECK: [[ctxt:%.*]] = load %swift.context*, %swift.context** [[ctxt_addr]] // CHECK-arm64e: [[ctxt_addr_int:%[0-9]+]] = ptrtoint %swift.context** [[context_addr]] to i64 // CHECK-arm64e: [[ptrauth_blend:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[ctxt_addr_int]], i64 48546) // CHECK-arm64e: [[ctxt_int:%[0-9]+]] = ptrtoint %swift.context* [[ctxt]] to i64 // CHECK-arm64e: [[signed_int:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[ctxt_int]], i32 2, i64 [[ptrauth_blend]]) // CHECK-arm64e: [[signed_ctxt:%[0-9]+]] = inttoptr i64 [[signed_int]] to %swift.context* // CHECK-arm64e: store %swift.context* [[signed_ctxt]], %swift.context** [[context_addr]] // CHECK-x86_64: store %swift.context* [[ctxt]], %swift.context** [[context_addr]] // Initialize NormalResult. // CHECK: [[result_addr:%.*]] = getelementptr inbounds %swift.continuation_context, %swift.continuation_context* [[cont_context]], i32 0, i32 3 // CHECK: [[result_storage_as_opaque:%.*]] = bitcast i32* [[result_storage]] to %swift.opaque* // CHECK: store %swift.opaque* [[result_storage_as_opaque]], %swift.opaque** [[result_addr]] // Initialize ResumeParent. // CHECK: [[resume_intrinsic:%.*]] = call i8* @llvm.coro.async.resume() // CHECK: [[continuation_fn_addr:%.*]] = getelementptr inbounds %swift.context, %swift.context* [[base_context]], i32 0, i32 1 // CHECK: [[continuation_fn:%.*]] = bitcast i8* [[resume_intrinsic]] to void (%swift.context*)* // CHECK-arm64e: [[continuation_fn_addr_int:%[0-9]+]] = ptrtoint void (%swift.context*)** [[continuation_fn_addr]] to i64 // CHECK-arm64e: [[ptrauth_blend:%[0-9]+]] = call i64 @llvm.ptrauth.blend.i64(i64 [[continuation_fn_addr_int]], i64 55047) // CHECK-arm64e: [[continuation_fn_int:%[0-9]+]] = ptrtoint void (%swift.context*)* [[continuation_fn]] to i64 // CHECK-arm64e: [[signed_int:%[0-9]+]] = call i64 @llvm.ptrauth.sign.i64(i64 [[continuation_fn_int]], i32 0, i64 [[ptrauth_blend]]) // CHECK-arm64e: [[signed_continuation_fn:%[0-9]+]] = inttoptr i64 [[signed_int]] to void (%swift.context*)* // CHECK-arm64e: store void (%swift.context*)* [[signed_continuation_fn]], void (%swift.context*)** [[continuation_fn_addr]] // CHECK-x86_64: store void (%swift.context*)* [[continuation_fn]], void (%swift.context*)** [[continuation_fn_addr]] // Call the runtime to retrieve and initialize the continuation. // CHECK: call swiftcc %swift.task* @swift_continuation_init(%swift.continuation_context* [[cont_context]], [[INT]] 0) // Do some stuff. // CHECK: call swiftcc void @not_async_test() // Arrive at the await_async_continuation point. // CHECK: [[synchronization_addr_before_await:%.*]] = getelementptr inbounds %swift.continuation_context, %swift.continuation_context* [[cont_context]], i32 0, i32 1 // CHECK: [[first_at_sync_pt:%.*]] = cmpxchg [[INT]]* [[synchronization_addr_before_await]], {{(i64|i32)}} 0, {{(i64|i32)}} 1 release acquire // CHECK: [[first_at_sync_pt_bool:%.*]] = extractvalue { {{(i64|i32)}}, i1 } [[first_at_sync_pt]], 1 // CHECK: br i1 [[first_at_sync_pt_bool]], label %await.async.abort, label %await.async.resume // Abort if we are the first to arrive at the await/or continuation point -- // we must wait on the other to arrive. // CHECK: await.async.abort: // CHECK: br label %coro.end // CHECK: coro.end: // CHECK: call i1 (i8*, i1, ...) @llvm.coro.end.async( // CHECK: unreachable // CHECK: await.async.resume: // CHECK: call { i8* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async{{.*}}({{.*}} @__swift_async_resume_project_context // CHECK: [[result_addr_addr:%.*]] = getelementptr inbounds %swift.continuation_context, %swift.continuation_context* [[cont_context]], i32 0, i32 3 // CHECK: [[result_addr:%.*]] = load %swift.opaque*, %swift.opaque** [[result_addr_addr]] // CHECK: [[typed_result_addr:%.*]] = bitcast %swift.opaque* [[result_addr]] to i32* // CHECK: [[result_value:%.*]] = load i32, i32* [[typed_result_addr]] // CHECK: br label %[[result_bb:[0-9]+]] // CHECK: [[result_bb]]: // CHECK: phi i32 [ [[result_value]], %await.async.resume ] sil @async_continuation : $@async () -> () { entry: %c = get_async_continuation Builtin.Int32 %f = function_ref @not_async_test : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () await_async_continuation %c : $Builtin.RawUnsafeContinuation, resume bb1 bb1(%r : $Builtin.Int32): %t = tuple() return %t : $() } sil @async_continuation_throws : $@async () -> () { entry: %c = get_async_continuation [throws] Builtin.Int32 %f = function_ref @not_async_test : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () await_async_continuation %c : $Builtin.RawUnsafeContinuation, resume bb1, error bb2 bb1(%r : $Builtin.Int32): br bb3 bb2(%e : $Error): br bb3 bb3: %t = tuple() return %t : $() } sil @async_continuation_addr : $@async () -> () { entry: %a = alloc_stack $Builtin.Int32 %c = get_async_continuation_addr Builtin.Int32, %a : $*Builtin.Int32 %f = function_ref @not_async_test : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () await_async_continuation %c : $Builtin.RawUnsafeContinuation, resume bb1 bb1: dealloc_stack %a : $*Builtin.Int32 %t = tuple() return %t : $() } sil @async_continuation_throws_addr : $@async () -> () { entry: %a = alloc_stack $Builtin.Int32 %c = get_async_continuation_addr [throws] Builtin.Int32, %a : $*Builtin.Int32 %f = function_ref @not_async_test : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () await_async_continuation %c : $Builtin.RawUnsafeContinuation, resume bb1, error bb2 bb1: dealloc_stack %a : $*Builtin.Int32 br bb3 bb2(%e : $Error): dealloc_stack %a : $*Builtin.Int32 br bb3 bb3: %t = tuple() return %t : $() }