Files
swift-mirror/test/SILOptimizer/access_summary_analysis.sil
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00

557 lines
26 KiB
Plaintext

// RUN: %target-sil-opt %s -access-summary-dump -o /dev/null | %FileCheck %s
sil_stage raw
import Builtin
import Swift
import SwiftShims
struct StructWithStoredProperties {
@_hasStorage var f: Int
@_hasStorage var g: Int
}
struct StructWithStructWithStoredProperties {
@_hasStorage var a: StructWithStoredProperties
@_hasStorage var b: StructWithStoredProperties
}
// CHECK-LABEL: @assignsToCapture
// CHECK-NEXT: ([modify], [])
sil private [ossa] @assignsToCapture : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1: $Int):
%2 = begin_access [modify] [unknown] %0 : $*Int
assign %1 to %2 : $*Int
end_access %2 : $*Int
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @readsAndModifiesSameCapture
// CHECK-NEXT: ([modify])
sil private [ossa] @readsAndModifiesSameCapture : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = begin_access [read] [unknown] %0 : $*Int
end_access %1 : $*Int
%2 = begin_access [modify] [unknown] %0 : $*Int
end_access %2 : $*Int
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @readsAndModifiesSeparateCaptures
// CHECK-NEXT: ([read], [modify])
sil private [ossa] @readsAndModifiesSeparateCaptures : $@convention(thin) (@inout_aliasable Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int):
%2 = begin_access [read] [unknown] %0 : $*Int
end_access %2 : $*Int
%3 = begin_access [modify] [unknown] %1 : $*Int
end_access %3 : $*Int
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: @modifyInModifySubAccess
// CHECK-NEXT: ([modify])
sil private [ossa] @modifyInModifySubAccess : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = begin_access [modify] [unknown] %0 : $*Int
%2 = begin_access [modify] [unknown] %1 : $*Int
end_access %2 : $*Int
end_access %1 : $*Int
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @readInModifySubAccess
// CHECK-NEXT: ([modify])
sil private [ossa] @readInModifySubAccess : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = begin_access [modify] [unknown] %0 : $*Int
%2 = begin_access [read] [unknown] %1 : $*Int
end_access %2 : $*Int
end_access %1 : $*Int
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @accessSeparateStoredPropertiesOfSameCapture
// CHECK-NEXT: ([.f modify, .g read])
sil private [ossa] @accessSeparateStoredPropertiesOfSameCapture : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStoredProperties):
%1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
%2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
end_access %1 : $*StructWithStoredProperties
%4 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
%5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.g
end_access %4 : $*StructWithStoredProperties
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @accessSeparateElementsOfSameCapture
// CHECK-NEXT: ([.0 modify, .1 read])
sil private [ossa] @accessSeparateElementsOfSameCapture : $@convention(thin) (@inout_aliasable (Int, Int)) -> () {
bb0(%0 : $*(Int, Int)):
%1 = begin_access [modify] [unknown] %0: $*(Int, Int)
%2 = tuple_element_addr %1 : $*(Int, Int), 0
end_access %1 : $*(Int, Int)
%4 = begin_access [read] [unknown] %0: $*(Int, Int)
%5 = tuple_element_addr %4 : $*(Int, Int), 1
end_access %4 : $*(Int, Int)
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @accessSeparateNestedStoredPropertiesOfSameCapture
// CHECK-NEXT: ([.a.f modify, .b.g modify])
sil private [ossa] @accessSeparateNestedStoredPropertiesOfSameCapture : $@convention(thin) (@inout_aliasable StructWithStructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStructWithStoredProperties):
%1 = begin_access [modify] [unknown] %0: $*StructWithStructWithStoredProperties
%2 = struct_element_addr %1 : $*StructWithStructWithStoredProperties, #StructWithStructWithStoredProperties.a
%3 = struct_element_addr %2 : $*StructWithStoredProperties, #StructWithStoredProperties.f
end_access %1 : $*StructWithStructWithStoredProperties
%5 = begin_access [modify] [unknown] %0: $*StructWithStructWithStoredProperties
%6 = struct_element_addr %5 : $*StructWithStructWithStoredProperties, #StructWithStructWithStoredProperties.b
%7 = struct_element_addr %6 : $*StructWithStoredProperties, #StructWithStoredProperties.g
end_access %5 : $*StructWithStructWithStoredProperties
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: @accessSeparateStoredPropertiesOfSameCaptureOppositeOfDeclarationOrder
// CHECK-NEXT: ([.f read, .g modify])
sil private [ossa] @accessSeparateStoredPropertiesOfSameCaptureOppositeOfDeclarationOrder : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStoredProperties):
%1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
%2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.g
end_access %1 : $*StructWithStoredProperties
%4 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
%5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.f
end_access %4 : $*StructWithStoredProperties
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @accessAggregateDoesNotSubsumeAccessStoredProp
// CHECK-NEXT: ([modify, .g modify])
sil private [ossa] @accessAggregateDoesNotSubsumeAccessStoredProp : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStoredProperties):
%1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
end_access %1 : $*StructWithStoredProperties
%4 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
%5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.g
end_access %4 : $*StructWithStoredProperties
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @accessAggregateDoesNotSubsumeAccessStoredPropWithAggregateSecond
// CHECK-NEXT: ([modify, .f modify])
sil private [ossa] @accessAggregateDoesNotSubsumeAccessStoredPropWithAggregateSecond : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStoredProperties):
%1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
%2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
end_access %1 : $*StructWithStoredProperties
%4 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
end_access %4 : $*StructWithStoredProperties
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @accessSameStoredPropertyOfSameCapture
// CHECK-NEXT: ([.f modify])
sil private [ossa] @accessSameStoredPropertyOfSameCapture : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStoredProperties):
%1 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
%2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
end_access %1 : $*StructWithStoredProperties
%4 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
%5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.f
end_access %4 : $*StructWithStoredProperties
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @accessSeparateStoredPropertiesOfSameCaptureWithTSanInstrumentation
// CHECK-NEXT: ([.f modify, .g read])
sil private [ossa] @accessSeparateStoredPropertiesOfSameCaptureWithTSanInstrumentation : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
bb0(%0 : $*StructWithStoredProperties):
%1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
%2 = builtin "tsanInoutAccess"(%1 : $*StructWithStoredProperties) : $()
%3 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
%4 = builtin "tsanInoutAccess"(%3 : $*Int) : $()
end_access %1 : $*StructWithStoredProperties
%6 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
%7 = builtin "tsanInoutAccess"(%6 : $*StructWithStoredProperties) : $()
%8 = struct_element_addr %6 : $*StructWithStoredProperties, #StructWithStoredProperties.g
%9 = builtin "tsanInoutAccess"(%8 : $*Int) : $()
end_access %6 : $*StructWithStoredProperties
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: @addressToPointerOfStructElementAddr
// CHECK-NEXT: ([])
// This mirrors the code pattern for materializeForSet on a struct stored
// property
sil private [ossa] @addressToPointerOfStructElementAddr : $@convention(method) (@inout StructWithStoredProperties) -> (Builtin.RawPointer) {
bb0(%1 : $*StructWithStoredProperties):
%2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
%3 = address_to_pointer %2 : $*Int to $Builtin.RawPointer
return %3 : $(Builtin.RawPointer)
}
// CHECK-LABEL: @endUnpairedAccess
// CHECK-NEXT: ([])
sil private [ossa] @endUnpairedAccess : $@convention(method) (@inout Builtin.UnsafeValueBuffer) -> () {
bb0(%0 : $*Builtin.UnsafeValueBuffer):
end_unpaired_access [dynamic] %0 : $*Builtin.UnsafeValueBuffer
%1 = tuple ()
return %1 : $()
}
// CHECK-LABEL: @tupleElementAddr
// CHECK-NEXT: ([modify])
sil private [ossa] @tupleElementAddr : $@convention(thin) (@inout_aliasable (Int, Int)) -> () {
bb0(%0 : $*(Int, Int)):
%1 = tuple_element_addr %0 : $*(Int, Int), 1
%2 = begin_access [modify] [unknown] %1 : $*Int
end_access %2 : $*Int
%3 = tuple ()
return %3 : $()
}
sil @closureWithMissingBody : $@convention(thin) (@inout_aliasable Int, Int) -> ()
// CHECK-LABEL: @callClosureWithMissingBody
// CHECK-NEXT: ([modify], [])
sil private [ossa] @callClosureWithMissingBody : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1 : $Int):
%2 = function_ref @closureWithMissingBody : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> () // no-crash
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: @callClosureThatModifiesCapture
// CHECK-NEXT: ([modify], [])
sil private [ossa] @callClosureThatModifiesCapture : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1 : $Int):
%2 = function_ref @assignsToCapture : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: @throwingClosureThatModifiesCapture
// CHECK-NEXT: ([modify])
sil private [ossa] @throwingClosureThatModifiesCapture : $@convention(thin) (@inout_aliasable Int) -> @error Error {
bb0(%0 : $*Int):
%1 = begin_access [modify] [unknown] %0 : $*Int
end_access %1 : $*Int
%2 = tuple ()
return %2 : $()
}
// CHECK-LABEL: @callThrowingClosureThatModifiesCapture
// CHECK-NEXT: ([modify])
sil private [ossa] @callThrowingClosureThatModifiesCapture : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = function_ref @throwingClosureThatModifiesCapture : $@convention(thin) (@inout_aliasable Int) -> @error Error
try_apply %1(%0) : $@convention(thin) (@inout_aliasable Int) -> @error Error, normal bb1, error bb2
bb1(%3 : $()):
%4 = tuple ()
return %4 : $()
bb2(%5: @owned $Error):
%6 = builtin "unexpectedError"(%5 : $Error) : $()
destroy_value [dead_end] %5
unreachable
}
sil @takesNoEscapeClosure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK-LABEL: @partialApplyPassedOffToFunction
// CHECK-NEXT: ([modify], [])
sil private [ossa] @partialApplyPassedOffToFunction : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1: $Int):
%2 = function_ref @assignsToCapture : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = partial_apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%4 = function_ref @takesNoEscapeClosure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
%5 = apply %4(%3) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
%6 = tuple ()
return %6 : $()
}
sil @takesNoEscapeClosureTakingArgument : $@convention(thin) (@owned @callee_owned (Int) -> ()) -> ()
sil @takesNoEscapeClosureTakingArgumentThrowing : $@convention(thin) (@owned @callee_owned (Int) -> (@error Error)) -> ()
sil @takesGuaranteedNoEscapeClosureTakingArgumentThrowing : $@convention(thin) (@guaranteed @callee_owned (Int) -> @error Error) -> ()
// CHECK-LABEL: @hasThreeCapturesAndTakesArgument
// CHECK-NEXT: ([], [modify], [], [read])
sil private [ossa] @hasThreeCapturesAndTakesArgument : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> () {
bb0(%0 : $Int, %1: $*Int, %2: $*Int, %3: $*Int):
%4 = begin_access [modify] [unknown] %1 : $*Int
end_access %4 : $*Int
%5 = begin_access [read] [unknown] %3 : $*Int
end_access %5 : $*Int
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @partialApplyOfClosureTakingArgumentPassedOffToFunction
// CHECK-NEXT: ([modify], [], [read])
sil private [ossa] @partialApplyOfClosureTakingArgumentPassedOffToFunction : $@convention(thin) (@inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int, %2 : $*Int):
%3 = function_ref @hasThreeCapturesAndTakesArgument : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%4 = partial_apply %3(%0, %1, %2) : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%5 = function_ref @takesNoEscapeClosureTakingArgument : $@convention(thin) (@owned @callee_owned (Int) -> ()) -> ()
%6 = apply %5(%4) : $@convention(thin) (@owned @callee_owned (Int) -> ()) -> ()
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @partialApplyFollowedByConvertFunction
// CHECK-NEXT: ([modify], [], [read])
sil private [ossa] @partialApplyFollowedByConvertFunction : $@convention(thin) (@inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int, %2 : $*Int):
%3 = function_ref @hasThreeCapturesAndTakesArgument : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%4 = partial_apply %3(%0, %1, %2) : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%5 = convert_function %4 : $@callee_owned (Int) -> () to $@callee_owned (Int) -> @error Error
%6 = function_ref @takesNoEscapeClosureTakingArgumentThrowing : $@convention(thin) (@owned @callee_owned (Int) -> @error Error) -> ()
%7 = apply %6(%5) : $@convention(thin) (@owned @callee_owned (Int) -> @error Error) -> ()
%8 = tuple ()
return %8 : $()
}
sil @takesAutoClosureReturningGeneric : $@convention(thin) <T where T : Equatable> (@owned @callee_owned () -> (@out T, @error Error)) -> ()
sil @thunkForAutoClosure : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error)
// CHECK-LABEL: @readsAndThrows
// CHECK-NEXT: ([read])
sil private [ossa] @readsAndThrows : $@convention(thin) (@inout_aliasable Int) -> (Int, @error Error) {
bb0(%0 : $*Int):
%3 = begin_access [read] [unknown] %0 : $*Int
%4 = load [trivial] %3 : $*Int
end_access %3 : $*Int
return %4 : $Int
}
// CHECK-LABEL: @passPartialApplyAsArgumentToPartialApply
// CHECK-NEXT: ([read])
sil hidden [ossa] @passPartialApplyAsArgumentToPartialApply : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%2 = function_ref @takesAutoClosureReturningGeneric : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> ()
%3 = function_ref @readsAndThrows : $@convention(thin) (@inout_aliasable Int) -> (Int, @error Error)
%4 = partial_apply %3(%0) : $@convention(thin) (@inout_aliasable Int) -> (Int, @error Error)
%5 = function_ref @thunkForAutoClosure : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error)
%6 = partial_apply %5(%4) : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error)
%7 = apply %2<Int>(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> ()
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: @reads
// CHECK-NEXT: ([read])
sil private [ossa] @reads : $@convention(thin) (@inout_aliasable Int) -> Int {
bb0(%0 : $*Int):
%3 = begin_access [read] [unknown] %0 : $*Int
%4 = load [trivial] %3 : $*Int
end_access %3 : $*Int
return %4 : $Int
}
// CHECK-LABEL: @convertPartialApplyAndPassToPartialApply
// CHECK-NEXT: ([read])
sil hidden [ossa] @convertPartialApplyAndPassToPartialApply : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%2 = function_ref @takesAutoClosureReturningGeneric : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> ()
%3 = function_ref @reads : $@convention(thin) (@inout_aliasable Int) -> Int
%4 = partial_apply %3(%0) : $@convention(thin) (@inout_aliasable Int) -> Int
%5 = convert_function %4 : $@callee_owned () -> Int to $@callee_owned () -> (Int, @error Error)
%6 = function_ref @thunkForAutoClosure : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error)
%7 = partial_apply %6(%5) : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error)
%8 = apply %2<Int>(%7) : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> ()
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: @selfRecursion
// CHECK-NEXT: ([modify], [])
sil private [ossa] @selfRecursion : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1 : $Int):
%2 = function_ref @selfRecursion : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%4 = begin_access [modify] [unknown] %0 : $*Int
end_access %4 : $*Int
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: @callsMutuallyRecursive
// CHECK-NEXT: ([modify], [])
sil private [ossa] @callsMutuallyRecursive : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1 : $Int):
%2 = function_ref @mutualRecursion1 : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: @mutualRecursion1
// CHECK-NEXT: ([modify], [])
sil private [ossa] @mutualRecursion1 : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1 : $Int):
%2 = function_ref @mutualRecursion2 : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%4 = begin_access [modify] [unknown] %0 : $*Int
end_access %4 : $*Int
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: @mutualRecursion2
// CHECK-NEXT: ([modify], [])
sil private [ossa] @mutualRecursion2 : $@convention(thin) (@inout_aliasable Int, Int) -> () {
bb0(%0 : $*Int, %1 : $Int):
%2 = function_ref @mutualRecursion1 : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (@inout_aliasable Int, Int) -> ()
%4 = begin_access [read] [unknown] %0 : $*Int
end_access %4 : $*Int
%5 = tuple ()
return %5 : $()
}
// Multiple cycles. This requires two iterations of the edge propagation.
// Once to propagate the modify from A to B and one to propagate from
// B to C
//
// A [Call B then later modify param]
// / |
// \ |
// B
// / |
// \ |
// C
//
// CHECK-LABEL: @multipleCycleA
// CHECK-NEXT: ([modify])
sil private [ossa] @multipleCycleA : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = function_ref @multipleCycleB : $@convention(thin) (@inout_aliasable Int) -> ()
%2 = apply %1(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
%3 = begin_access [modify] [unknown] %0 : $*Int
end_access %3 : $*Int
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: @multipleCycleB
// CHECK-NEXT: ([modify])
sil private [ossa] @multipleCycleB : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = function_ref @multipleCycleA : $@convention(thin) (@inout_aliasable Int) -> ()
%2 = apply %1(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
%3 = function_ref @multipleCycleC : $@convention(thin) (@inout_aliasable Int) -> ()
%4 = apply %3(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: @multipleCycleC
// CHECK-NEXT: ([modify])
sil private [ossa] @multipleCycleC : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = function_ref @multipleCycleB : $@convention(thin) (@inout_aliasable Int) -> ()
%2 = apply %1(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
%4 = tuple ()
return %4 : $()
}
// Make sure that we can accept borrows of partial apply by looking through the
// borrow.
// CHECK-LABEL: @partialApplyFollowedByConvertFunctionWithBorrow
// CHECK-NEXT: ([modify], [], [read])
sil private [ossa] @partialApplyFollowedByConvertFunctionWithBorrow : $@convention(thin) (@inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int, %2 : $*Int):
%3 = function_ref @hasThreeCapturesAndTakesArgument : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%4 = partial_apply %3(%0, %1, %2) : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%5 = convert_function %4 : $@callee_owned (Int) -> () to $@callee_owned (Int) -> @error Error
%6 = begin_borrow %5 : $@callee_owned (Int) -> @error Error
%7 = function_ref @takesGuaranteedNoEscapeClosureTakingArgumentThrowing : $@convention(thin) (@guaranteed @callee_owned (Int) -> @error Error) -> ()
%8 = apply %7(%6) : $@convention(thin) (@guaranteed @callee_owned (Int) -> @error Error) -> ()
end_borrow %6 : $@callee_owned (Int) -> @error Error
destroy_value %5 : $@callee_owned (Int) -> @error Error
%9999 = tuple ()
return %9999 : $()
}
// Look through moves.
// CHECK-LABEL: @partialApplyFollowedByConvertFunctionWithMove
// CHECK-NEXT: ([modify], [], [read])
sil private [ossa] @partialApplyFollowedByConvertFunctionWithMove : $@convention(thin) (@inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int, %2 : $*Int):
%3 = function_ref @hasThreeCapturesAndTakesArgument : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%4 = partial_apply %3(%0, %1, %2) : $@convention(thin) (Int, @inout_aliasable Int, @inout_aliasable Int, @inout_aliasable Int) -> ()
%5 = convert_function %4 : $@callee_owned (Int) -> () to $@callee_owned (Int) -> @error Error
%6 = move_value %5 : $@callee_owned (Int) -> @error Error
%7 = function_ref @takesGuaranteedNoEscapeClosureTakingArgumentThrowing : $@convention(thin) (@guaranteed @callee_owned (Int) -> @error Error) -> ()
%8 = apply %7(%6) : $@convention(thin) (@guaranteed @callee_owned (Int) -> @error Error) -> ()
destroy_value %6 : $@callee_owned (Int) -> @error Error
%9999 = tuple ()
return %9999 : $()
}
sil @use : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
sil @subject : $@convention(thin) (Builtin.Int64) -> ()
// CHECK-LABEL: @partial_apply_convert
sil [ossa] @partial_apply_convert : $@convention(thin) () -> () {
entry:
%f = function_ref @subject : $@convention(thin) (Builtin.Int64) -> ()
%z = integer_literal $Builtin.Int64, 0
%e = partial_apply [callee_guaranteed] %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
%b = begin_borrow %e : $@callee_guaranteed () -> ()
%n = convert_escape_to_noescape %b : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
%n2 = mark_dependence %n : $@noescape @callee_guaranteed () -> () on %e : $@callee_guaranteed () -> ()
%f2 = function_ref @use : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
apply %f2(%n2) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
destroy_value %n2 : $@noescape @callee_guaranteed () -> ()
end_borrow %b : $@callee_guaranteed () -> ()
destroy_value %e : $@callee_guaranteed () -> ()
%t = tuple ()
return %t : $()
}
sil [ossa] @asyncIntClosure : $@convention(thin) @async (@inout_aliasable Builtin.Int64) -> (@out Builtin.Int64, @error any Error) {
bb0(%0 : $*Builtin.Int64, %1: $*Builtin.Int64):
%2 = begin_access [modify] [unknown] %0 : $*Builtin.Int64
%3 = load [trivial] %1 : $*Builtin.Int64
assign %3 to %2 : $*Builtin.Int64
end_access %2 : $*Builtin.Int64
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: @partial_apply_asynclet
sil [ossa] @partial_apply_asynclet : $@convention(thin) @async (@inout_aliasable Builtin.Int64) -> () {
bb0(%0 : $*Builtin.Int64):
%i = alloc_stack $Builtin.Int64
%p = address_to_pointer %i : $*Builtin.Int64 to $Builtin.RawPointer
%o = enum $Optional<Builtin.RawPointer>, #Optional.none!enumelt
%x = enum $Optional<Builtin.Executor>, #Optional.none!enumelt
%f = function_ref @asyncIntClosure : $@convention(thin) @async (@inout_aliasable Builtin.Int64) -> (@out Builtin.Int64, @error any Error)
%e = partial_apply [callee_guaranteed] %f(%0) : $@convention(thin) @async (@inout_aliasable Builtin.Int64) -> (@out Builtin.Int64, @error any Error)
%a = convert_function %e : $@async @callee_guaranteed () -> (@out Builtin.Int64, @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@sil_sending @out τ_0_0, @error any Error) for <Builtin.Int64>
%n = convert_escape_to_noescape [not_guaranteed] %a : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@sil_sending @out τ_0_0, @error any Error) for <Builtin.Int64> to $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@sil_sending @out τ_0_0, @error any Error) for <Builtin.Int64>
%sl = builtin "startAsyncLetWithLocalBuffer"<Builtin.Int64>(%o : $Optional<Builtin.RawPointer>, %n : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@sil_sending @out τ_0_0, @error any Error) for <Builtin.Int64>, %p : $Builtin.RawPointer) : $Builtin.RawPointer
%ap = builtin "finishAsyncLet"(%sl, %p) : $()
hop_to_executor %x : $Optional<Builtin.Executor>
%el = builtin "endAsyncLetLifetime"(%sl : $Builtin.RawPointer) : $()
destroy_value %n : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> (@sil_sending @out τ_0_0, @error any Error) for <Builtin.Int64>
destroy_value %a : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@sil_sending @out τ_0_0, @error any Error) for <Builtin.Int64>
dealloc_stack %i : $*Builtin.Int64
%t = tuple ()
return %t : $()
}