@@ -72,49 +72,16 @@ func computeLinearLiveness(for definingValue: Value, _ context: Context)
72
72
return range
73
73
}
74
74
75
- typealias InnerScopeHandler = ( Value ) -> WalkResult
76
-
77
- /// Compute liveness and return a range, which the caller must deinitialize.
78
- ///
79
- /// An OSSA lifetime begins with a single "defining" value, which must be owned, or must begin a borrow scope. A
80
- /// complete OSSA lifetime has a linear lifetime, meaning that it has a lifetime-ending use on all paths. Interior
81
- /// liveness computes liveness without assuming the lifetime is complete. To do this, it must find all "use points" and
82
- /// prove that the defining value is never propagated beyond those points. This is used to initially complete OSSA
83
- /// lifetimes and fix them after transformations that's don't preserve OSSA.
84
- ///
85
- /// The caller must check that `definingValue` has no pointer escape before calling this.
86
- ///
87
- /// Invariants:
88
- ///
89
- /// - The definition dominates all use points.
90
- ///
91
- /// - Liveness does not extend beyond lifetime-ending operations
92
- /// (a.k.a. affine lifetimes).
93
- ///
94
- /// - All inner scopes are complete. (Use `innerScopeHandler` to complete them or bail-out).
95
- func computeInteriorLiveness( for definingValue: Value , _ context: FunctionPassContext ,
96
- innerScopeHandler: InnerScopeHandler ? = nil ) -> InstructionRange {
97
- let result = InteriorLivenessResult . compute ( for: definingValue, ignoreEscape: false , visitInnerUses: false , context)
98
- switch result. pointerStatus {
99
- case . nonescaping:
100
- break
101
- case let . escaping( operands) :
102
- fatalError ( """
103
- check findPointerEscape() before computing interior liveness.
104
- Pointer escape: \( operands [ 0 ] . instruction)
105
- """ )
106
- case let . unknown( operand) :
107
- fatalError ( " Unrecognized SIL address user \( operand. instruction) " )
108
- }
109
- return result. range
110
- }
111
-
112
75
/// Compute known liveness and return a range, which the caller must deinitialize.
113
76
///
114
77
/// This computes a minimal liveness, ignoring pointer escaping uses.
115
- func computeKnownLiveness( for definingValue: Value , visitInnerUses: Bool = false , _ context: FunctionPassContext ) -> InstructionRange {
78
+ ///
79
+ /// The caller must call deinitialize() on the result.
80
+ func computeKnownLiveness( for definingValue: Value , visitInnerUses: Bool = false , _ context: FunctionPassContext )
81
+ -> InstructionRange {
82
+ // Ignore pointer escapes and other failures.
116
83
return InteriorLivenessResult . compute ( for: definingValue, ignoreEscape: true ,
117
- visitInnerUses: visitInnerUses, context) . range
84
+ visitInnerUses: visitInnerUses, context) . acquireRange
118
85
}
119
86
120
87
/// If any interior pointer may escape, then record the first instance here. If 'ignoseEscape' is true, this
@@ -156,11 +123,32 @@ enum InteriorPointerStatus: CustomDebugStringConvertible {
156
123
}
157
124
}
158
125
126
+ typealias InnerScopeHandler = ( Value ) -> WalkResult
127
+
128
+ /// An OSSA lifetime begins with a single "defining" value, which must be owned, or must begin a borrow scope. A
129
+ /// complete OSSA lifetime has a linear lifetime, meaning that it has a lifetime-ending use on all paths. Interior
130
+ /// liveness computes liveness without assuming the lifetime is complete. To do this, it must find all "use points" and
131
+ /// prove that the defining value is never propagated beyond those points. This is used to initially complete OSSA
132
+ /// lifetimes and fix them after transformations that's don't preserve OSSA.
133
+ ///
134
+ /// Invariants:
135
+ ///
136
+ /// - The definition dominates all use points (hence the result is a single InstructionRange).
137
+ ///
138
+ /// - Liveness does not extend beyond lifetime-ending operations (a.k.a. affine lifetimes).
139
+ ///
140
+ /// - All inner scopes are complete. (Use `innerScopeHandler` to either complete them or to recursively compute their
141
+ /// liveness and either bail-out on or propagate inner pointer escapes outward).
159
142
struct InteriorLivenessResult : CustomDebugStringConvertible {
143
+ // 'success' may only be set to .abortWalk if pointerStatus != .nonescaping or visitInnerUses returned false.
144
+ // The client can therefore ensure success if it has already checked for pointer escapes.
160
145
let success : WalkResult
161
- let range : InstructionRange
146
+ var range : InstructionRange
162
147
let pointerStatus : InteriorPointerStatus
163
148
149
+ /// Compute liveness for a single OSSA value without assuming a complete lifetime.
150
+ ///
151
+ /// The caller must call acquireRange or deinitialize() on the result.
164
152
static func compute( for definingValue: Value , ignoreEscape: Bool = false , visitInnerUses: Bool ,
165
153
_ context: FunctionPassContext ,
166
154
innerScopeHandler: InnerScopeHandler ? = nil ) -> InteriorLivenessResult {
@@ -184,6 +172,13 @@ struct InteriorLivenessResult: CustomDebugStringConvertible {
184
172
return result
185
173
}
186
174
175
+ /// Client must call deinitialize() on the result.
176
+ var acquireRange : InstructionRange { consuming get { range } }
177
+
178
+ mutating func deinitialize( ) {
179
+ range. deinitialize ( )
180
+ }
181
+
187
182
var debugDescription : String {
188
183
" \( success) \n \( range) \n \( pointerStatus) "
189
184
}
0 commit comments