mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Specifically for 6.2, we are making optimize hop to executor more conservative
around caller isolation inheriting functions. This means that we are:
1. No longer treating calls to caller isolation inheriting functions as having a
hop in their prologue. In terms of this pass, it means that when determining
dead hop to executors, we no longer think that a caller isolation inheriting
function means that an earlier hop to executor is not required.
2. Treating returns from caller isolation inheriting callees as requiring a
hop. The reason why we are doing this is that we can no longer assume that our
caller will hop after we return.
Post 6.2, there are three main changes we are going to make:
* Forward Dataflow
Caller isolation inheriting functions will no longer be treated as suspension
points meaning that we will be able to propagate hops over them and can assume
that we know the actor that we are on when we enter the function. Practically
this means that trees of calls that involve just nonisolated(nonsending) async
functions will avoid /all/ hop to executor calls since we will be able to
eliminate all of them since the dataflow will just propagate forward from the
entrance that we are already on the actor.
* Backwards Dataflow
A caller isolation inheriting call site will still cause preceding
hop_to_executor functions to be live. This is because we need to ensure that we
are on the caller isolation inheriting actor before we hit the call site. If we
are already on that actor, the hop will be eliminated by the forward pass. But
if the hop has not been eliminated, then the hop must be needed to return us to
the appropriate actor.
We will also keep the behavior that returns from a caller isolation inheriting
function are considered to keep hop to executors alive. If we were able to
propagate to a hop to executor before the return inst with the forward dataflow,
then we know that we are guaranteed to still be on the relevant actor. If the
hop to executor is still there, then we need it to ensure that our caller can
treat the caller isolation inheriting function as a non-suspension point.
rdar://155905383
(cherry picked from commit b3942424c8)
442 lines
19 KiB
Plaintext
442 lines
19 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-function-isolation-info -enable-sil-verify-all %s -optimize-hop-to-executor | %FileCheck %s
|
|
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: asserts
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
actor MyActor {
|
|
@_hasStorage private var p: Int { get set }
|
|
}
|
|
|
|
sil [ossa] @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
sil [ossa] @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
sil [ossa] @syncFunction : $@convention(thin) () -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleRedundantActor : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'simpleRedundantActor'
|
|
sil [ossa] @simpleRedundantActor : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
hop_to_executor %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @redundantActorAndControlFlow : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'redundantActorAndControlFlow'
|
|
sil [ossa] @redundantActorAndControlFlow : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
hop_to_executor %0 : $MyActor
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
hop_to_executor %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @notRedundantActor : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK: } // end sil function 'notRedundantActor'
|
|
sil [ossa] @notRedundantActor : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
hop_to_executor %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
hop_to_executor %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @mismatchingActor : $@convention(method) @async (@guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK: hop_to_executor %0
|
|
// CHECK: apply
|
|
// CHECK: hop_to_executor %1
|
|
// CHECK: apply
|
|
// CHECK: } // end sil function 'mismatchingActor'
|
|
sil [ossa] @mismatchingActor : $@convention(method) @async (@guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor):
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
hop_to_executor %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
hop_to_executor %1 : $MyActor
|
|
apply %f(%1) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleDeadHopElimination : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'simpleDeadHopElimination'
|
|
sil [ossa] @simpleDeadHopElimination : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @doubleDeadHopElimination : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'doubleDeadHopElimination'
|
|
sil [ossa] @doubleDeadHopElimination : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
hop_to_executor %0 : $MyActor
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
hop_to_executor %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @deadHopAndControlFlow : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'deadHopAndControlFlow'
|
|
sil [ossa] @deadHopAndControlFlow : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
%f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply %f() : $@convention(thin) @async () -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @partialAliveHop : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'partialAliveHop'
|
|
sil [ossa] @partialAliveHop : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @handleUnreachable1 : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'handleUnreachable1'
|
|
sil [ossa] @handleUnreachable1 : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
unreachable
|
|
bb2:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @handleUnreachable2 : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'handleUnreachable2'
|
|
sil [ossa] @handleUnreachable2 : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
hop_to_executor %0 : $MyActor
|
|
unreachable
|
|
bb2:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @handleUnreachableBlock : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: hop_to_executor
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'handleUnreachableBlock'
|
|
sil [ossa] @handleUnreachableBlock : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
br bb2
|
|
bb1:
|
|
br bb2
|
|
bb2:
|
|
hop_to_executor %0 : $MyActor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// This pattern is definitely optimizable, but it's *not* supposed to
|
|
// be optimized by simply removing the hop before the builtin.
|
|
// CHECK-LABEL: sil [ossa] @handleGetCurrentExecutor : $@convention(method) @async (@guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: hop_to_executor
|
|
// CHECK-NEXT: builtin
|
|
// CHECK-NEXT: hop_to_executor
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'handleGetCurrentExecutor'
|
|
sil [ossa] @handleGetCurrentExecutor : $@convention(method) @async (@guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%async_f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply %async_f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %0 : $MyActor
|
|
%curExec = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
|
|
hop_to_executor %1 : $MyActor
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%1) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
hop_to_executor %0 : $MyActor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @redundantMandatoryHop : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: bb0(%0 : @guaranteed $MyActor):
|
|
// CHECK-NEXT: hop_to_executor %0
|
|
// CHECK: apply
|
|
// CHECK: hop_to_executor [mandatory] %0
|
|
// CHECK: } // end sil function 'redundantMandatoryHop'
|
|
sil [ossa] @redundantMandatoryHop : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%f = function_ref @requiredToRunOnActor : $@convention(method) (@guaranteed MyActor) -> ()
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
hop_to_executor [mandatory] %0 : $MyActor
|
|
apply %f(%0) : $@convention(method) (@guaranteed MyActor) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleMandatoryHop : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: hop_to_executor [mandatory]
|
|
// CHECK: } // end sil function 'simpleMandatoryHop'
|
|
sil [ossa] @simpleMandatoryHop : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor [mandatory] %0 : $MyActor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleMandatoryHopAndSuspend : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: hop_to_executor [mandatory]
|
|
// CHECK: apply
|
|
// CHECK: } // end sil function 'simpleMandatoryHopAndSuspend'
|
|
sil [ossa] @simpleMandatoryHopAndSuspend : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor [mandatory] %0 : $MyActor
|
|
%async_f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply %async_f() : $@convention(thin) @async () -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @handleBeginBorrow : {{.*}} {
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK-LABEL: } // end sil function 'handleBeginBorrow'
|
|
sil [ossa] @handleBeginBorrow : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0 : $MyActor
|
|
%b = begin_borrow %0 : $MyActor
|
|
end_borrow %b : $MyActor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @handleEndBorrow : {{.*}} {
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK-LABEL: } // end sil function 'handleEndBorrow'
|
|
sil [ossa] @handleEndBorrow : $@convention(method) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
%b = begin_borrow %0 : $MyActor
|
|
hop_to_executor %0 : $MyActor
|
|
end_borrow %b : $MyActor
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleDCEAsync : $@convention(thin) @async (@guaranteed MyActor) -> () {
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'simpleDCEAsync'
|
|
sil [ossa] @simpleDCEAsync : $@convention(thin) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
%f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply %f() : $@convention(thin) @async () -> ()
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleCallerIsolationInheritingStopsDCE : $@convention(thin) @async (@guaranteed MyActor) -> () {
|
|
// CHECK: hop_to_executor
|
|
// CHECK: } // end sil function 'simpleCallerIsolationInheritingStopsDCE'
|
|
sil [ossa] @simpleCallerIsolationInheritingStopsDCE : $@convention(thin) @async (@guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
%f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We should eliminate none of the hop_to_executor here since
|
|
// caller_isolation_inheriting @async apply sites do not cross isolation
|
|
// boundaries.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @simpleCallerIsolationInheritingStopsDCE2 : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK: hop_to_executor
|
|
// CHECK: hop_to_executor
|
|
// CHECK: hop_to_executor
|
|
// CHECK: } // end sil function 'simpleCallerIsolationInheritingStopsDCE2'
|
|
sil [ossa] @simpleCallerIsolationInheritingStopsDCE2 : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor, %2 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
%f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %1
|
|
%f2 = function_ref @syncFunction : $@convention(thin) () -> ()
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %2
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleWithoutCallerIsolationInheritingHaveDCE : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK: bb0([[ARG1:%.*]] : @guaranteed $MyActor, [[ARG2:%.*]] : @guaranteed $MyActor, [[ARG3:%.*]] : @guaranteed $MyActor):
|
|
// CHECK-NEXT: // function_ref anotherAsyncFunction
|
|
// CHECK-NEXT: [[FUNC:%.*]] = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
// CHECK-NEXT: apply [[FUNC]]() : $@convention(thin) @async () -> ()
|
|
// CHECK-NEXT: hop_to_executor [[ARG2]]
|
|
// CHECK-NEXT: // function_ref syncFunction
|
|
// CHECK-NEXT: [[FUNC2:%.*]] = function_ref @syncFunction : $@convention(thin) () -> ()
|
|
// CHECK-NEXT: apply [[FUNC2]]() : $@convention(thin) () -> ()
|
|
// CHECK-NEXT: apply [[FUNC]]() : $@convention(thin) @async () -> ()
|
|
// CHECK-NEXT: hop_to_executor [[ARG3]]
|
|
// CHECK-NEXT: apply [[FUNC2]]() : $@convention(thin) () -> ()
|
|
// CHECK-NEXT: apply [[FUNC]]() : $@convention(thin) @async () -> ()
|
|
// CHECK-NEXT: apply [[FUNC]]() : $@convention(thin) @async () -> ()
|
|
// CHECK: } // end sil function 'simpleWithoutCallerIsolationInheritingHaveDCE'
|
|
sil [ossa] @simpleWithoutCallerIsolationInheritingHaveDCE : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor, %2 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
%f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %1
|
|
%f2 = function_ref @syncFunction : $@convention(thin) () -> ()
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
apply %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %2
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
apply %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %2
|
|
apply %f() : $@convention(thin) @async () -> ()
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// We do not allow for these to be propagated yet through caller isolation
|
|
// inheriting, so we should have all of the hop_to_executor.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @callerIsolationInheritingStopsAllowsPropagating : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK: bb0(
|
|
// CHECK: hop_to_executor
|
|
// CHECK: hop_to_executor
|
|
// CHECK: hop_to_executor
|
|
// CHECK: } // end sil function 'callerIsolationInheritingStopsAllowsPropagating'
|
|
sil [ossa] @callerIsolationInheritingStopsAllowsPropagating : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor, %2 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
%f = function_ref @anotherAsyncFunction : $@convention(thin) @async () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %0
|
|
%f2 = function_ref @syncFunction : $@convention(thin) () -> ()
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
hop_to_executor %0
|
|
apply %f2() : $@convention(thin) () -> ()
|
|
apply [callee_isolation=caller_isolation_inheriting] [caller_isolation=caller_isolation_inheriting] %f() : $@convention(thin) @async () -> ()
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Since we are caller isolation inheriting, make sure that we leave around the
|
|
// hop_to_executor due to ehre elase. We do eliminate one of the hop_to_executor
|
|
// though.
|
|
//
|
|
// CHECK: sil [isolation "caller_isolation_inheriting"] [ossa] @callerIsolationInheritingStopsReturnDeadEnd : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK: bb0(
|
|
// CHECK-NEXT: hop_to_executor
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'callerIsolationInheritingStopsReturnDeadEnd'
|
|
sil [isolation "caller_isolation_inheriting"] [ossa] @callerIsolationInheritingStopsReturnDeadEnd : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor, %2 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
hop_to_executor %0
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @noIsolationStillRemoves : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
// CHECK-NOT: hop_to_executor
|
|
// CHECK: } // end sil function 'noIsolationStillRemoves'
|
|
sil [ossa] @noIsolationStillRemoves : $@convention(thin) @async (@guaranteed MyActor, @guaranteed MyActor, @guaranteed MyActor) -> () {
|
|
bb0(%0 : @guaranteed $MyActor, %1 : @guaranteed $MyActor, %2 : @guaranteed $MyActor):
|
|
hop_to_executor %0
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|