mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Beside cleaning up the source code, the motivation for the translation into Swift is to make it easier to improve the pass for some InlineArray specific optimizations (though I'm not sure, yet if we really need those). Also, the new implementation doesn't contain the optimize-store-into-temp optimization anymore, because this is covered by redundant load elimination.
115 lines
6.7 KiB
Plaintext
115 lines
6.7 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types %s -compute-escape-effects -compute-side-effects -temp-rvalue-elimination -enable-sil-verify-all -wmo | %FileCheck %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
// 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 any SomeProtocol, @guaranteed SomeClass) -> () {
|
|
// CHECK: bb0(%0 : $*any SomeProtocol, %1 : $SomeClass):
|
|
// CHECK: alloc_ref $SomeClass
|
|
// CHECK: alloc_stack $SomeStruct
|
|
// CHECK-NOT: alloc_stack $any SomeProtocol
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: init_existential_addr %{{.*}} : $*any SomeProtocol, $SomeInstance
|
|
// CHECK: [[OPEN1:%.*]] = open_existential_addr immutable_access %0 : $*any SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001122", any SomeProtocol) Self
|
|
// CHECK: apply %{{.*}}<@opened("6419340C-0B14-11EA-9897-ACDE48001122", any SomeProtocol) Self>([[OPEN1]]) : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK-NOT: alloc_stack $any SomeProtocol
|
|
// CHECK-NOT: copy_addr
|
|
// CHECK: [[OPEN2:%.*]] = open_existential_addr immutable_access %{{.*}} : $*any SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001123", any SomeProtocol) Self
|
|
// CHECK: apply %{{.*}}<@opened("6419340C-0B14-11EA-9897-ACDE48001123", any SomeProtocol) Self>([[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 [init] %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 AliasAnalysis 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 [init] %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) Self
|
|
%witness1 = witness_method $@opened("6419340C-0B14-11EA-9897-ACDE48001122", SomeProtocol) Self, #SomeProtocol.foo : <Self where Self : SomeProtocol> (Self) -> () -> (), %openadr1 : $*@opened("6419340C-0B14-11EA-9897-ACDE48001122", SomeProtocol) Self : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
|
|
%call1 = apply %witness1<@opened("6419340C-0B14-11EA-9897-ACDE48001122", SomeProtocol) Self>(%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
|
|
// creates a content node that refers back to the dead stack
|
|
// location.
|
|
%stkAdr2 = alloc_stack $SomeProtocol
|
|
copy_addr %propAdr1 to [init] %stkAdr2 : $*SomeProtocol
|
|
%openadr2 = open_existential_addr immutable_access %stkAdr2 : $*SomeProtocol to $*@opened("6419340C-0B14-11EA-9897-ACDE48001123", SomeProtocol) Self
|
|
%witness2 = witness_method $@opened("6419340C-0B14-11EA-9897-ACDE48001123", SomeProtocol) Self, #SomeProtocol.foo : <Self where Self : SomeProtocol> (Self) -> () -> (), %openadr2 : $*@opened("6419340C-0B14-11EA-9897-ACDE48001123", SomeProtocol) Self : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> ()
|
|
%call2 = apply %witness2<@opened("6419340C-0B14-11EA-9897-ACDE48001123", SomeProtocol) Self>(%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
|
|
}
|