Skip to content

Commit 62b04ca

Browse files
committed
LocalVariableUtils add non-escaping closure capture support
Don't always consider an inout_aliasable argument to have escaped. AccessEnforcementSelection has already done that analysis and left begin_access [dynamic] artifacts if the argument has escaped in any meaningful way. Use that information to Essential for supporting autoclosures that call mutating methods on span-like things. Such as UTF8Span.UnicodeScalarIterator.skipForward(): e.g. while numSkipped < n && skipForward() != 0 { ... }
1 parent 8200a87 commit 62b04ca

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
///
2222
/// 3. Stored properties in heap objects or global variables. These are always formally accessed.
2323
///
24+
/// Pass dependencies:
25+
///
26+
/// AccessEnforcementSelection must run first to correctly determine which non-esacping closure captures may have
27+
/// escaped prior to the closure invocation. Any access to an inout_aliasable argument that may have escaped in the
28+
/// caller will be marked [dynamic].
29+
///
2430
//===----------------------------------------------------------------------===//
2531

2632
import SIL
@@ -287,6 +293,9 @@ struct LocalVariableAccessMap: Collection, CustomStringConvertible {
287293

288294
var isBoxed: Bool { allocation is AllocBoxInst }
289295

296+
// If 'mayAlias' is true (@inout_aliasable), then this variable may have escaped before entering the current
297+
// function. 'walkAccesses' determines whether this allocation is considered to have escaped on entry by checked for
298+
// the existienced of begin_access [dynamic].
290299
var mayAlias: Bool {
291300
if let arg = allocation as? FunctionArgument, arg.convention == .indirectInoutAliasable {
292301
return true
@@ -324,18 +333,26 @@ struct LocalVariableAccessMap: Collection, CustomStringConvertible {
324333
if walker.walkDown(allocation: allocation) == .abortWalk {
325334
return .abortWalk
326335
}
336+
var escapedOnEntry = false
327337
for localAccess in walker.accessStack {
328338
let info = LocalVariableAccessInfo(localAccess: localAccess)
329-
if mayAlias {
330-
// Local allocations can only escape prior to assignment if they are boxed or inout_aliasable.
331-
info.hasEscaped = true
332-
} else if !isBoxed {
339+
// inout_aliasable "allocation" has escaped on entry if any begin_access [dynamic] is present.
340+
if mayAlias, info.access.kind == .beginAccess,
341+
(localAccess.instruction as! BeginAccessInst).enforcement == .dynamic {
342+
escapedOnEntry = true
343+
}
344+
if !isBoxed {
333345
// Boxed allocation requires reachability to determine whether the box escaped prior to assignment.
334346
info.hasEscaped = info.isEscape
335347
}
336348
accessMap[localAccess.instruction!] = info
337349
accessList.append(info)
338350
}
351+
if escapedOnEntry {
352+
for accessInfo in accessList {
353+
accessInfo.hasEscaped = true
354+
}
355+
}
339356
return .continueWalk
340357
}
341358

0 commit comments

Comments
 (0)