Skip to content

Commit b8df083

Browse files
committed
hacking
1 parent e4c201f commit b8df083

File tree

1 file changed

+109
-81
lines changed

1 file changed

+109
-81
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift

Lines changed: 109 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ import SIL
1717
/// If this instruction produces a borrowed value, then
1818
/// BeginBorrowValue(resultOf: self) != nil.
1919
///
20-
/// This does not include instructions like Apply and TryApply that
20+
/// This does not include instructions like `apply` and `try_apply` that
2121
/// instantaneously borrow a value from the caller.
2222
///
23+
/// This does not include `load_borrow` because it borrows a memory
24+
/// location, not the value of its operand.
25+
///
2326
/// Note: This must handle all instructions with a .borrow operand ownership.
2427
///
2528
/// TODO: replace BorrowIntroducingInstruction
@@ -57,11 +60,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
5760
}
5861
}
5962

60-
typealias ScopeEndingOperands =
61-
LazyMapSequence<LazyFilterSequence<LazyMapSequence<UseList, Operand?>>,
62-
Operand>
63-
64-
/// The operands that end the local borrow scope.
63+
/// Visit the operands that end the local borrow scope.
6564
///
6665
/// Note: When this instruction's result is BeginBorrowValue the
6766
/// scopeEndingOperand may include reborrows. To find all uses that
@@ -76,28 +75,42 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
7675
/// that scope ending instructions exist on all paths. These
7776
/// instructions should be complete after SILGen and never cloned to
7877
/// produce phis.
79-
var scopeEndingOperands: ScopeEndingOperands {
80-
if let value = instruction as? SingleValueInstruction,
81-
BeginBorrowValue(value) != nil {
82-
return value.uses.lazy.compactMap { $0.endsLifetime ? $0 : nil }
83-
}
84-
switch instruction {
85-
case let sbi as StoreBorrowInst:
86-
return sbi.uses.lazy.compactMap {
87-
$0.instruction is EndBorrowInst ? $0 : nil
78+
func visitScopeEndingOperands(_ context: Context,
79+
visitor: @escaping (Operand) -> WalkResult)
80+
-> WalkResult {
81+
switch self {
82+
case .beginBorrow, .storeBorrow:
83+
let svi = instruction as! SingleValueInstruction
84+
return svi.uses.walk {
85+
if $0.instruction is EndBorrowInst { return visitor($0) }
86+
return .continueWalk
8887
}
89-
case let bai as BeginApplyInst:
90-
return bai.token.uses.lazy.compactMap { $0 }
91-
case let builtin as BuiltinInst:
92-
return builtin.uses.lazy.compactMap {
88+
case .beginApply(let bai):
89+
return bai.token.uses.walk { return visitor($0) }
90+
case .partialApply(let pai):
91+
return visitForwardedUses(introducer: pai, context) {
92+
switch $0 {
93+
case let .operand(operand):
94+
if operand.endsLifetime {
95+
return visitor(operand)
96+
}
97+
return .continueWalk
98+
case let .deadValue(_, operand):
99+
if let operand = operand {
100+
assert(!operand.endsLifetime,
101+
"a dead forwarding instruction cannot end a lifetime")
102+
}
103+
return .continueWalk
104+
}
105+
}
106+
case .startAsyncLet(let builtin):
107+
return builtin.uses.walk {
93108
if let builtinUser = $0.instruction as? BuiltinInst,
94109
builtinUser.id == .EndAsyncLetLifetime {
95-
return $0
110+
return visitor($0)
96111
}
97-
return nil
112+
return .continueWalk
98113
}
99-
default:
100-
fatalError("unknown BorrowingInstruction")
101114
}
102115
}
103116

@@ -176,17 +189,25 @@ enum BeginBorrowValue {
176189
}
177190

178191
var hasLocalScope: Bool {
179-
return !(value is FunctionArgument)
192+
switch self {
193+
case .beginBorrow, .loadBorrow, .beginApply, .reborrow:
194+
return true
195+
case .functionArgument:
196+
return false
197+
}
180198
}
181199

182-
// non-nil if hasLocalScope is true
200+
// Return the value borrowed by begin_borrow or address borrowed by
201+
// load_borrow.
202+
//
203+
// Return nil for begin_apply and reborrow, which need special handling.
183204
var baseOperand: Operand? {
184-
switch value {
185-
case let beginBorrow as BeginBorrowInst:
186-
return beginBorrow.operand
187-
case let loadBorrow as LoadBorrowInst:
205+
switch self {
206+
case let .beginBorrow(beginBorrow):
207+
return beginBorrow.operand
208+
case let .loadBorrow(loadBorrow):
188209
return loadBorrow.operand
189-
default:
210+
case .beginApply, .functionArgument, .reborrow:
190211
return nil
191212
}
192213
}
@@ -203,9 +224,9 @@ enum BeginBorrowValue {
203224
}
204225
}
205226

206-
/// Find the enclosing borrow introducers for `value`. This gives you
207-
/// a set of OSSA lifetimes that directly include `value`. If `value`
208-
/// is owned, or introduces a borrow scope, then `value` is the single
227+
/// Find the borrow introducers for `value`. This gives you a set of
228+
/// OSSA lifetimes that directly include `value`. If `value` is owned,
229+
/// or introduces a borrow scope, then `value` is the single
209230
/// introducer for itself.
210231
///
211232
/// Example: // introducers:
@@ -217,14 +238,15 @@ enum BeginBorrowValue {
217238
/// %first = struct_extract %pair // %borrow0, %1
218239
/// %field = ref_element_addr %first // (none)
219240
/// %load = load_borrow %field : $*C // %load
220-
func gather(borrowIntroducers: inout Stack<Value>, for value: Value,
221-
_ context: Context) {
241+
func gatherBorrowIntroducers(for value: Value,
242+
in borrowIntroducers: inout Stack<Value>,
243+
_ context: Context) {
222244

223245
// Cache introducers across multiple instances of BorrowIntroducers.
224246
var cache = BorrowIntroducers.Cache(context)
225247
defer { cache.deinitialize() }
226-
BorrowIntroducers.gather(introducers: &borrowIntroducers,
227-
forValue: value, &cache, context)
248+
BorrowIntroducers.gather(for: value, in: &borrowIntroducers,
249+
&cache, context)
228250
}
229251

230252
private struct BorrowIntroducers {
@@ -254,10 +276,10 @@ private struct BorrowIntroducers {
254276
// introducer set to avoid adding duplicates.
255277
var visitedIntroducers: Set<HashableValue> = Set()
256278

257-
static func gather(introducers: inout Stack<Value>, forValue value: Value,
258-
_ cache: inout Cache, _ context: Context) {
279+
static func gather(for value: Value, in introducers: inout Stack<Value>,
280+
_ cache: inout Cache, _ context: Context) {
259281
var borrowIntroducers = BorrowIntroducers(context: context)
260-
borrowIntroducers.gather(introducers: &introducers, forValue: value, &cache)
282+
borrowIntroducers.gather(for: value, in: &introducers, &cache)
261283
}
262284

263285
private mutating func push(_ introducer: Value,
@@ -280,8 +302,9 @@ private struct BorrowIntroducers {
280302
// - `value` introduces a borrow scope (begin_borrow, load_borrow, reborrow)
281303
//
282304
// Otherwise recurse up the use-def chain to find all introducers.
283-
private mutating func gather(introducers: inout Stack<Value>,
284-
forValue value: Value, _ cache: inout Cache) {
305+
private mutating func gather(for value: Value,
306+
in introducers: inout Stack<Value>,
307+
_ cache: inout Cache) {
285308
// Check if this value's introducers have already been added to
286309
// 'introducers' to avoid duplicates and avoid exponential
287310
// recursion on aggregates.
@@ -291,7 +314,7 @@ private struct BorrowIntroducers {
291314
}
292315
introducers.withMarker(
293316
pushElements: { introducers in
294-
gatherUncached(introducers: &introducers, forValue: value, &cache)
317+
gatherUncached(for: value, in: &introducers, &cache)
295318
},
296319
withNewElements: { newIntroducers in
297320
{ cachedIntroducers in
@@ -300,8 +323,9 @@ private struct BorrowIntroducers {
300323
})
301324
}
302325

303-
private mutating func gatherUncached(introducers: inout Stack<Value>,
304-
forValue value: Value, _ cache: inout Cache) {
326+
private mutating func gatherUncached(for value: Value,
327+
in introducers: inout Stack<Value>,
328+
_ cache: inout Cache) {
305329
switch value.ownership {
306330
case .none, .unowned:
307331
return
@@ -321,7 +345,7 @@ private struct BorrowIntroducers {
321345
}
322346
// Handle guaranteed forwarding phis
323347
if let phi = Phi(value) {
324-
gather(introducers: &introducers, forPhi: phi, &cache)
348+
gather(forPhi: phi, in: &introducers, &cache)
325349
return
326350
}
327351
// Recurse through guaranteed forwarding non-phi instructions.
@@ -330,7 +354,7 @@ private struct BorrowIntroducers {
330354
}
331355
for operand in forwardingInst.forwardedOperands {
332356
if operand.value.ownership == .guaranteed {
333-
gather(introducers: &introducers, forValue: operand.value, &cache);
357+
gather(for: operand.value, in: &introducers, &cache);
334358
}
335359
}
336360
}
@@ -351,7 +375,7 @@ private struct BorrowIntroducers {
351375
// two(%reborrow_2 : @guaranteed, %forward_2 : @guaranteed)
352376
// end_borrow %reborrow_2
353377
//
354-
// Calling `recursivelyFindForwardingPhiIntroducers(%forward_2)`
378+
// Calling `gatherPhiIntroducers(for: %forward_2)`
355379
// recursively computes these introducers:
356380
//
357381
// %field is the only value incoming to %forward_2.
@@ -364,8 +388,9 @@ private struct BorrowIntroducers {
364388
//
365389
// %reborrow_2 is returned.
366390
//
367-
private mutating func gather(introducers: inout Stack<Value>, forPhi phi: Phi,
368-
_ cache: inout Cache) {
391+
private mutating func gather(forPhi phi: Phi,
392+
in introducers: inout Stack<Value>,
393+
_ cache: inout Cache) {
369394
// Phi cycles are skipped. They cannot contribute any new introducer.
370395
if !cache.pendingPhis.insert(phi.value) {
371396
return
@@ -380,8 +405,8 @@ private struct BorrowIntroducers {
380405
defer {
381406
incomingIntroducers.deinitialize()
382407
}
383-
BorrowIntroducers.gather(introducers: &incomingIntroducers,
384-
forValue: value, &cache, context)
408+
BorrowIntroducers.gather(for: value, in: &incomingIntroducers,
409+
&cache, context)
385410
// Map the incoming introducers to an outer-adjacent phi if one exists.
386411
push(contentsOf: mapToPhi(predecessor: pred,
387412
incomingValues: incomingIntroducers),
@@ -450,25 +475,26 @@ private func mapToPhi<PredecessorSequence: Sequence<Value>> (
450475
/// bb1(%outerReborrow : @guaranteed, // %0
451476
/// %innerReborrow : @guaranteed) // %outerReborrow
452477
///
453-
func gather(enclosingValues: inout Stack<Value>,
454-
for value: Value, _ context: some Context) {
478+
func gatherEnclosingValues(for value: Value,
479+
in enclosingValues: inout Stack<Value>,
480+
_ context: some Context) {
455481

456482
var gatherValues = EnclosingValues(context)
457483
defer { gatherValues.deinitialize() }
458484
var cache = BorrowIntroducers.Cache(context)
459485
defer { cache.deinitialize() }
460-
gatherValues.gather(enclosingValues: &enclosingValues, forValue: value,
461-
&cache)
486+
gatherValues.gather(for: value, in: &enclosingValues, &cache)
462487
}
463488

464489
/// Find inner adjacent phis in the same block as `enclosingPhi`.
465490
/// These keep the enclosing (outer adjacent) phi alive.
466-
func gather(innerAdjacentPhis: inout Stack<Phi>, for enclosingPhi: Phi,
467-
_ context: Context) {
491+
func gatherInnerAdjacentPhis(for enclosingPhi: Phi,
492+
in innerAdjacentPhis: inout Stack<Phi>,
493+
_ context: Context) {
468494
for candidatePhi in enclosingPhi.successor.arguments {
469495
var enclosingValues = Stack<Value>(context)
470496
defer { enclosingValues.deinitialize() }
471-
gather(enclosingValues: &enclosingValues, for: candidatePhi, context)
497+
gatherEnclosingValues(for: candidatePhi, in: &enclosingValues, context)
472498
if enclosingValues.contains(where: { $0 == enclosingPhi.value}) {
473499
innerAdjacentPhis.push(Phi(candidatePhi)!)
474500
}
@@ -489,28 +515,28 @@ private struct EnclosingValues {
489515
visitedReborrows.deinitialize()
490516
}
491517

492-
mutating func gather(enclosingValues: inout Stack<Value>,
493-
forValue value: Value, _ cache: inout BorrowIntroducers.Cache) {
518+
mutating func gather(for value: Value,
519+
in enclosingValues: inout Stack<Value>,
520+
_ cache: inout BorrowIntroducers.Cache) {
494521
if value is Undef || value.ownership != .guaranteed {
495522
return
496523
}
497-
if BeginBorrowValue(value) != nil {
498-
switch value {
499-
case let beginBorrow as BeginBorrowInst:
524+
if let beginBorrow = BeginBorrowValue(value) {
525+
switch beginBorrow {
526+
case let .beginBorrow(bbi):
500527
// Gather the outer enclosing borrow scope.
501-
BorrowIntroducers.gather(introducers: &enclosingValues,
502-
forValue: beginBorrow.operand.value, &cache, context)
503-
case is LoadBorrowInst, is FunctionArgument:
528+
BorrowIntroducers.gather(for: bbi.operand.value, in: &enclosingValues,
529+
&cache, context)
530+
case .loadBorrow, .beginApply, .functionArgument:
504531
// There is no enclosing value on this path.
505532
break
506-
default:
507-
gather(enclosingValues: &enclosingValues, forReborrow: Phi(value)!,
508-
&cache)
533+
case let .reborrow(reborrow):
534+
gather(forReborrow: reborrow, in: &enclosingValues, &cache)
509535
}
510536
} else {
511537
// Handle forwarded guaranteed values.
512-
BorrowIntroducers.gather(introducers: &enclosingValues, forValue: value,
513-
&cache, context)
538+
BorrowIntroducers.gather(for: value, in: &enclosingValues,
539+
&cache, context)
514540
}
515541
}
516542

@@ -545,8 +571,9 @@ private struct EnclosingValues {
545571
// end_borrow %reborrow_3
546572
// destroy_value %phi_3
547573
//
548-
// gather(%reborrow_3) finds %phi_3 by computing enclosing defs in this order
549-
// (inner -> outer):
574+
// gather(forReborrow: %reborrow_3) finds %phi_3 by computing
575+
// enclosing defs in this order
576+
// (inner -> outer):
550577
//
551578
// %reborrow_1 -> %value
552579
// %reborrow_2 -> %phi_2
@@ -561,10 +588,11 @@ private struct EnclosingValues {
561588
// br one(%outerBorrowA, %borrow)
562589
// one(%outerReborrow : @guaranteed, %reborrow : @guaranteed)
563590
//
564-
// gather(%reborrow) finds (%outerReborrow, %outerBorrowB).
591+
// gather(forReborrow: %reborrow) finds (%outerReborrow, %outerBorrowB).
565592
//
566-
private mutating func gather(enclosingValues: inout Stack<Value>,
567-
forReborrow reborrow: Phi, _ cache: inout BorrowIntroducers.Cache) {
593+
private mutating func gather(forReborrow reborrow: Phi,
594+
in enclosingValues: inout Stack<Value>,
595+
_ cache: inout BorrowIntroducers.Cache) {
568596

569597
guard visitedReborrows.insert(reborrow.value) else { return }
570598

@@ -580,8 +608,8 @@ private struct EnclosingValues {
580608
defer {
581609
incomingEnclosingValues.deinitialize()
582610
}
583-
gather(enclosingValues: &incomingEnclosingValues, forValue: incomingValue,
584-
&cache)
611+
gatherEnclosingValues(for: incomingValue, in: &incomingEnclosingValues,
612+
&cache)
585613
mapToPhi(predecessor: pred,
586614
incomingValues: incomingEnclosingValues).forEach {
587615
if pushedEnclosingValues.insert($0) {
@@ -601,7 +629,7 @@ let borrowIntroducersTest = FunctionTest("borrow_introducers") {
601629
defer {
602630
introducers.deinitialize()
603631
}
604-
gather(borrowIntroducers: &introducers, for: value, context)
632+
gatherBorrowIntroducers(for: value, in: &introducers, context)
605633
introducers.forEach { print($0) }
606634
}
607635

@@ -614,6 +642,6 @@ let enclosingValuesTest = FunctionTest("enclosing_values") {
614642
defer {
615643
enclosing.deinitialize()
616644
}
617-
gather(enclosingValues: &enclosing, for: value, context)
645+
gatherEnclosingValues(for: value, in: &enclosing, context)
618646
enclosing.forEach { print($0) }
619647
}

0 commit comments

Comments
 (0)