@@ -181,3 +181,122 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
181
181
blockRange. deinitialize ( )
182
182
}
183
183
}
184
+
185
+ extension InstructionRange {
186
+ enum PathOverlap {
187
+ // range: ---
188
+ // | pathBegin
189
+ // | |
190
+ // | pathEnd
191
+ // ---
192
+ case containsPath
193
+
194
+ // range: ---
195
+ // | pathBegin
196
+ // --- |
197
+ // pathEnd
198
+ case containsBegin
199
+
200
+ // pathBegin
201
+ // range: --- |
202
+ // | pathEnd
203
+ // ---
204
+ case containsEnd
205
+
206
+ // pathBegin
207
+ // range: --- |
208
+ // | |
209
+ // --- |
210
+ // pathEnd
211
+ case overlappedByPath
212
+
213
+ // either: pathBegin
214
+ // |
215
+ // pathEnd
216
+ // range: ---
217
+ // |
218
+ // ---
219
+ // or: pathBegin
220
+ // |
221
+ // pathEnd
222
+ case disjoint
223
+ }
224
+
225
+ /// Return true if any exclusive path from `begin` to `end` includes an instruction in this exclusive range.
226
+ ///
227
+ /// Returns .containsBegin, if this range has the same begin and end as the path.
228
+ ///
229
+ /// Precondition: `begin` dominates `end`.
230
+ func overlaps( pathBegin: Instruction , pathEnd: Instruction , _ context: some Context ) -> PathOverlap {
231
+ assert ( pathBegin != pathEnd, " expect an exclusive path " )
232
+ if contains ( pathBegin) {
233
+ // Note: pathEnd != self.begin here since self.contains(pathBegin)
234
+ if contains ( pathEnd) { return . containsPath }
235
+ return . containsBegin
236
+ }
237
+ if contains ( pathEnd) {
238
+ if let rangeBegin = self . begin, rangeBegin == pathEnd {
239
+ return . disjoint
240
+ }
241
+ return . containsEnd
242
+ }
243
+ // Neither end-point is contained. If a backward path walk encouters this range, then it must overlap this
244
+ // range. Otherwise, it is disjoint.
245
+ var backwardBlocks = BasicBlockWorklist ( context)
246
+ defer { backwardBlocks. deinitialize ( ) }
247
+ backwardBlocks. pushIfNotVisited ( pathEnd. parentBlock)
248
+ while let block = backwardBlocks. pop ( ) {
249
+ if blockRange. inclusiveRangeContains ( block) {
250
+ // This range overlaps with this block, but there are still three possibilities:
251
+ // (1) range, pathBegin, pathEnd = disjoint (range might not begin in this block)
252
+ // (2) pathBegin, pathEnd, range = disjoint (pathBegin might not be in this block)
253
+ // (3) pathBegin, range, pathEnd = overlappedByPath (range or pathBegin might not be in this block)
254
+ //
255
+ // Walk backward from pathEnd to find either pathBegin or an instruction in this range.
256
+ // Both this range and the path may or may not begin in this block.
257
+ let endInBlock = block == pathEnd. parentBlock ? pathEnd : block. terminator
258
+ for inst in ReverseInstructionList ( first: endInBlock) {
259
+ // Check pathBegin first because the range is exclusive.
260
+ if inst == pathBegin {
261
+ break
262
+ }
263
+ // Check inclusiveRangeContains() in case the range end is the first instruction in this block.
264
+ if inclusiveRangeContains ( inst) {
265
+ return . overlappedByPath
266
+ }
267
+ }
268
+ // No instructions in this range occur between pathBegin and pathEnd.
269
+ return . disjoint
270
+ }
271
+ // No range blocks have been reached.
272
+ if block == pathBegin. parentBlock {
273
+ return . disjoint
274
+ }
275
+ backwardBlocks. pushIfNotVisited ( contentsOf: block. predecessors)
276
+ }
277
+ fatalError ( " begin: \( pathBegin) \n must dominate end: \( pathEnd) " )
278
+ }
279
+ }
280
+
281
+ let rangeOverlapsPathTest = FunctionTest ( " range_overlaps_path " ) {
282
+ function, arguments, context in
283
+ let rangeValue = arguments. takeValue ( )
284
+ print ( " Range of: \( rangeValue) " )
285
+ var range = computeLinearLiveness ( for: rangeValue, context)
286
+ defer { range. deinitialize ( ) }
287
+ let pathInst = arguments. takeInstruction ( )
288
+ print ( " Path begin: \( pathInst) " )
289
+ if let pathBegin = pathInst as? ScopedInstruction {
290
+ for end in pathBegin. endInstructions {
291
+ print ( " Overlap kind: " , range. overlaps ( pathBegin: pathInst, pathEnd: end, context) )
292
+ }
293
+ return
294
+ }
295
+ if let pathValue = pathInst as? SingleValueInstruction , pathValue. ownership == . owned {
296
+ for end in pathValue. uses. endingLifetime {
297
+ print ( " Overlap kind: " , range. overlaps ( pathBegin: pathInst, pathEnd: end. instruction, context) )
298
+ }
299
+ return
300
+ }
301
+ print ( " Test specification error: not a scoped or owned instruction: \( pathInst) " )
302
+ }
0 commit comments