Skip to content

Commit 9070974

Browse files
committed
Add BorrowingInstruction.dependentValue and .scopedValue
This consolidates the rules for borrow scopes so we can simplify interior liveness.
1 parent c364181 commit 9070974

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,50 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
204204
}
205205
}
206206

207+
var dependentValue: Value? {
208+
switch self {
209+
case .borrowedFrom(let bfi):
210+
let phi = bfi.borrowedPhi
211+
if phi.isReborrow {
212+
return nil
213+
}
214+
return phi.value
215+
case .markDependence(let mdi):
216+
if mdi.hasScopedLifetime {
217+
return nil
218+
}
219+
return mdi
220+
case .beginBorrow, .storeBorrow, .beginApply, .partialApply, .startAsyncLet:
221+
return nil
222+
}
223+
}
224+
225+
/// If this is valid, then visitScopeEndingOperands succeeds.
226+
var scopedValue: Value? {
227+
switch self {
228+
case .beginBorrow, .storeBorrow:
229+
return instruction as! SingleValueInstruction
230+
case let .borrowedFrom(bfi):
231+
let phi = bfi.borrowedPhi
232+
guard phi.isReborrow else {
233+
return nil
234+
}
235+
return phi.value
236+
case .beginApply(let bai):
237+
return bai.token
238+
case .partialApply(let pai):
239+
// We currently assume that closure lifetimes are always complete (destroyed on all paths).
240+
return pai
241+
case .markDependence(let mdi):
242+
guard mdi.hasScopedLifetime else {
243+
return nil
244+
}
245+
return mdi
246+
case .startAsyncLet(let builtin):
247+
return builtin
248+
}
249+
}
250+
207251
/// Visit the operands that end the local borrow scope.
208252
///
209253
/// Returns .abortWalk if the borrow scope cannot be determined from lifetime-ending uses. For example:
@@ -218,26 +262,23 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
218262
/// TODO: For instructions that are not a BeginBorrowValue, verify that scope ending instructions exist on all
219263
/// paths. These instructions should be complete after SILGen and never cloned to produce phis.
220264
func visitScopeEndingOperands(_ context: Context, visitor: @escaping (Operand) -> WalkResult) -> WalkResult {
265+
guard let val = scopedValue else {
266+
return .abortWalk
267+
}
221268
switch self {
222269
case .beginBorrow, .storeBorrow:
223-
return visitEndBorrows(value: instruction as! SingleValueInstruction, context, visitor)
224-
case let .borrowedFrom(bfi):
225-
guard bfi.borrowedPhi.isReborrow else {
226-
return .abortWalk
227-
}
228-
return visitEndBorrows(value: instruction as! SingleValueInstruction, context, visitor)
229-
case .beginApply(let bai):
230-
return bai.token.uses.walk { return visitor($0) }
231-
case .partialApply(let pai):
270+
return visitEndBorrows(value: val, context, visitor)
271+
case .borrowedFrom:
272+
return visitEndBorrows(value: val, context, visitor)
273+
case .beginApply:
274+
return val.uses.walk { return visitor($0) }
275+
case .partialApply:
232276
// We currently assume that closure lifetimes are always complete (destroyed on all paths).
233-
return visitOwnedDependent(value: pai, context, visitor)
234-
case .markDependence(let mdi):
235-
guard mdi.ownership == .owned, mdi.type.isEscapable(in: mdi.parentFunction) else {
236-
return .abortWalk
237-
}
238-
return visitOwnedDependent(value: mdi, context, visitor)
239-
case .startAsyncLet(let builtin):
240-
return builtin.uses.walk {
277+
return visitOwnedDependent(value: val, context, visitor)
278+
case .markDependence:
279+
return visitOwnedDependent(value: val, context, visitor)
280+
case .startAsyncLet:
281+
return val.uses.walk {
241282
if let builtinUser = $0.instruction as? BuiltinInst,
242283
builtinUser.id == .EndAsyncLetLifetime {
243284
return visitor($0)

0 commit comments

Comments
 (0)