blob: e9033fe4d46e961864ef3a942e511429cf06903c [file] [log] [blame]
// RUN: %target-sil-opt %s -temp-rvalue-opt -enable-sil-verify-all -escapes-internal-verify -wmo | %FileCheck %s
//
// TempRValue iteratively uses EscapeAnalysis and deletes
// instructions. Make sure that the connection graph remains valid
// <rdar://57290845>.
//
// This test requires -wmo so EscapeAnalysis can find all
// implementations of SomeProtocol.foo. Otherwise the existential
// address appears to escape. As an alternative, we could be more
// aggressive about considering address-type argument not to escape,
// but that would require some limiting address_to_pointer to never
// occur on an exclusive address argument.
import Swift
sil_stage canonical
protocol SomeProtocol {
func foo()
}
struct SomeInstance : SomeProtocol {
func foo()
}
class SomeClass {
var someProperty: SomeProtocol
}
struct SomeStruct {
var someRef: SomeClass
}
// CHECK-LABEL: sil @testTempRvalueEscapeAnalysisUpdate : $@convention(thin) (@in_guaranteed SomeProtocol, @guaranteed SomeClass) -> () {
// CHECK: bb0(%0 : $*SomeProtocol, %1 : $SomeClass):
// CHECK: alloc_ref $SomeClass
// CHECK: alloc_stack $SomeStruct
// CHECK-NOT: alloc_stack $SomeProtocol
// CHECK-NOT: copy_addr
// CHECK: init_existential_addr %{{.*}} : $*SomeProtocol, $SomeInstance
// CHECK: [[OPEN1:%.*]] = open_existential_addr immutable_access %0 : $*SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001122") SomeProtocol
// CHECK: apply %{{.*}}<@opened("6419340C-0B14-11EA-9897-ACDE48001122") SomeProtocol>([[OPEN1]]) : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
// CHECK-NOT: destroy_addr
// CHECK-NOT: alloc_stack $SomeProtocol
// CHECK-NOT: copy_addr
// CHECK: [[OPEN2:%.*]] = open_existential_addr immutable_access %{{.*}} : $*SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001123") SomeProtocol
// CHECK: apply %{{.*}}<@opened("6419340C-0B14-11EA-9897-ACDE48001123") SomeProtocol>([[OPEN2]]) : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
// CHECK-NOT: destroy_addr
// CHECK-LABEL: } // end sil function 'testTempRvalueEscapeAnalysisUpdate'
sil @testTempRvalueEscapeAnalysisUpdate : $@convention(thin) (@in_guaranteed SomeProtocol, @guaranteed SomeClass) -> () {
bb0(%0 : $*SomeProtocol, %1 : $SomeClass):
// First create a uniquely identified protocol value. This way
// EscapeAnalysis canPointToSameMemory will kick in later. It can't
// be an exclusive argument, or AliasAnalysis will filter it before
// querying EscapeAnalysis.
%localRef = alloc_ref $SomeClass
%localPropAdr = ref_element_addr %localRef : $SomeClass, #SomeClass.someProperty
copy_addr %0 to [initialization] %localPropAdr : $*SomeProtocol
%stk0 = alloc_stack $SomeStruct
%stk0Ref = struct_element_addr %stk0 : $*SomeStruct, #SomeStruct.someRef
store %localRef to %stk0Ref : $*SomeClass
%indirectRef = load %stk0Ref : $*SomeClass
%indirectLocalPropAdr = ref_element_addr %indirectRef : $SomeClass, #SomeClass.someProperty
%propAdr1 = ref_element_addr %1 : $SomeClass, #SomeClass.someProperty
// TempRValue tries to kick in on this copy, but there is an
// interfering write that can't be handled by AliasAnlysis without
// consulting EscapingAnalysis. MemoryBehavior drops down to
// EscapeAnalysis for only a few special instructions, like
// init_existential_addr.
%stkAdr1 = alloc_stack $SomeProtocol
copy_addr %0 to [initialization] %stkAdr1 : $*SomeProtocol
%instanceAdr = init_existential_addr %indirectLocalPropAdr : $*SomeProtocol, $SomeInstance
%openadr1 = open_existential_addr immutable_access %stkAdr1 : $*SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001122") SomeProtocol
%witness1 = witness_method $@opened("6419340C-0B14-11EA-9897-ACDE48001122") SomeProtocol, #SomeProtocol.foo : <Self where Self : SomeProtocol> (Self) -> () -> (), %openadr1 : $*@opened("6419340C-0B14-11EA-9897-ACDE48001122") SomeProtocol : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
%call1 = apply %witness1<@opened("6419340C-0B14-11EA-9897-ACDE48001122") SomeProtocol>(%openadr1) : $@convention(witness_method: SomeProtocol) _0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
destroy_addr %stkAdr1 : $*SomeProtocol
// TempRValue optimization kicks in here. The open_existential_addr
// ceates a content node that refers back to the dead stack
// location.
%stkAdr2 = alloc_stack $SomeProtocol
copy_addr %propAdr1 to [initialization] %stkAdr2 : $*SomeProtocol
%openadr2 = open_existential_addr immutable_access %stkAdr2 : $*SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001123") SomeProtocol
%witness2 = witness_method $@opened("6419340C-0B14-11EA-9897-ACDE48001123") SomeProtocol, #SomeProtocol.foo : <Self where Self : SomeProtocol> (Self) -> () -> (), %openadr2 : $*@opened("6419340C-0B14-11EA-9897-ACDE48001123") SomeProtocol : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
%call2 = apply %witness2<@opened("6419340C-0B14-11EA-9897-ACDE48001123") SomeProtocol>(%openadr2) : $@convention(witness_method: SomeProtocol) _0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
destroy_addr %stkAdr2 : $*SomeProtocol
dealloc_stack %stkAdr2 : $*SomeProtocol
dealloc_stack %stkAdr1 : $*SomeProtocol
dealloc_stack %stk0 : $*SomeStruct
%v = tuple ()
return %v : $()
}
sil hidden @$s26escape_analysis_invalidate12SomeInstanceV3fooyyF : $@convention(method) (SomeInstance) -> () {
bb0(%0 : $SomeInstance):
debug_value %0 : $SomeInstance, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
}
sil private [transparent] [thunk] @$s26escape_analysis_invalidate12SomeInstanceVAA0A8ProtocolA2aDP3fooyyFTW : $@convention(witness_method: SomeProtocol) (@in_guaranteed SomeInstance) -> () {
bb0(%0 : $*SomeInstance):
%1 = load %0 : $*SomeInstance
// function_ref SomeInstance.foo()
%2 = function_ref @$s26escape_analysis_invalidate12SomeInstanceV3fooyyF : $@convention(method) (SomeInstance) -> ()
%3 = apply %2(%1) : $@convention(method) (SomeInstance) -> ()
%4 = tuple ()
return %4 : $()
}
sil_witness_table hidden SomeInstance: SomeProtocol module t {
method #SomeProtocol.foo: <Self where Self : SomeProtocol> (Self) -> () -> () : @$s26escape_analysis_invalidate12SomeInstanceVAA0A8ProtocolA2aDP3fooyyFTW // protocol witness for SomeProtocol.foo() in conformance SomeInstance
}