File: escape_analysis_invalidate.sil

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (114 lines) | stat: -rw-r--r-- 6,788 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// RUN: %target-sil-opt %s -compute-escape-effects -compute-side-effects -temp-rvalue-opt -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
}