Skip to content

Commit 3bad906

Browse files
authored
Merge pull request #65622 from eeckstein/improve-escape-utils
EscapeUtils: better handling of noescape closures and convert_function instructions
2 parents ddc0219 + 5992e68 commit 3bad906

File tree

4 files changed

+51
-7
lines changed

4 files changed

+51
-7
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,10 +361,6 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
361361
case is ApplyInst, is TryApplyInst, is BeginApplyInst:
362362
return walkDownCallee(argOp: operand, apply: instruction as! FullApplySite, path: path)
363363
case let pai as PartialApplyInst:
364-
// This is a non-stack closure.
365-
// For `stack` closures, `hasRelevantType` in `walkDown` will return false
366-
// stopping the walk since they don't escape.
367-
368364
// Check whether the partially applied argument can escape in the body.
369365
if walkDownCallee(argOp: operand, apply: pai, path: path.with(knownType: nil)) == .abortWalk {
370366
return .abortWalk
@@ -376,8 +372,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
376372
// 2. something can escape in a destructor when the context is destroyed
377373
return walkDownUses(ofValue: pai, path: path.with(knownType: nil))
378374
case let pta as PointerToAddressInst:
379-
assert(operand.index == 0)
380375
return walkDownUses(ofAddress: pta, path: path.with(knownType: nil))
376+
case let cv as ConvertFunctionInst:
377+
return walkDownUses(ofValue: cv, path: path.with(knownType: nil))
381378
case let bi as BuiltinInst:
382379
switch bi.id {
383380
case .DestroyArray:
@@ -561,6 +558,12 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
561558
return .continueWalk
562559
}
563560

561+
if argOp.value.type.isNoEscapeFunction {
562+
// Per definition a `partial_apply [on_stack]` cannot escape the callee.
563+
// Potential escapes of its captured values are already handled when visiting the `partial_apply`.
564+
return .continueWalk
565+
}
566+
564567
// Argument effects do not consider any potential stores to the argument (or it's content).
565568
// Therefore, if we need to track stores, the argument effects do not correctly describe what we need.
566569
// For example, argument 0 in the following function is marked as not-escaping, although there

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
4141
public var isEnum: Bool { bridged.getEnumOrBoundGenericEnum() != nil }
4242
public var isFunction: Bool { bridged.isFunction() }
4343
public var isMetatype: Bool { bridged.isMetatype() }
44+
public var isNoEscapeFunction: Bool { bridged.isNoEscapeFunction() }
4445

4546
/// Can only be used if the type is in fact a nominal type (`isNominal` is true).
4647
public var nominal: NominalTypeDecl {

include/swift/SIL/SILType.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,13 @@ class SILType {
471471
return false;
472472
}
473473

474+
bool isNoEscapeFunction() const {
475+
if (auto *fTy = getASTType()->getAs<SILFunctionType>()) {
476+
return fTy->isNoEscape();
477+
}
478+
return false;
479+
}
480+
474481
/// True if the type involves any archetypes.
475482
bool hasArchetype() const { return getASTType()->hasArchetype(); }
476483

test/SILOptimizer/escape_info.sil

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,9 @@ sil [ossa] @closure6 : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> @own
10221022
[%1: escape c*.v** => %r.c*.v**]
10231023
}
10241024

1025+
sil @take_noescape_closure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (@guaranteed Y) -> ()) -> ()
1026+
sil @take_escaping_closure : $@convention(thin) (@owned @callee_guaranteed (@guaranteed Y) -> ()) -> ()
1027+
10251028
// CHECK-LABEL: Escape information for callClosure1:
10261029
// CHECK: - : %0 = alloc_ref $Y
10271030
// CHECK: global: %1 = alloc_ref $Y
@@ -1332,8 +1335,8 @@ sil @test_debug_value : $@convention(thin) () -> () {
13321335
}
13331336

13341337
// CHECK-LABEL: Escape information for test_walk_up_partial_apply_argument:
1335-
// CHECK: global: %0 = alloc_ref $Y // users: %3, %2
1336-
// CHECK: global: %6 = alloc_ref $X // user: %7
1338+
// CHECK: global: %0 = alloc_ref $Y
1339+
// CHECK: global: %6 = alloc_ref $X
13371340
// CHECK: End function test_walk_up_partial_apply_argument
13381341
sil @test_walk_up_partial_apply_argument : $@convention(thin) () -> () {
13391342
bb0:
@@ -1350,6 +1353,36 @@ bb0:
13501353
return %13 : $()
13511354
}
13521355

1356+
// CHECK-LABEL: Escape information for test_escaping_closure:
1357+
// CHECK: global: %0 = alloc_ref $Y
1358+
// CHECK: End function test_escaping_closure
1359+
sil @test_escaping_closure : $@convention(thin) () -> () {
1360+
bb0:
1361+
%0 = alloc_ref $Y
1362+
%1 = function_ref @closure1 : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> ()
1363+
%2 = partial_apply [callee_guaranteed] %1(%0) : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> ()
1364+
%3 = function_ref @take_escaping_closure : $@convention(thin) (@owned @callee_guaranteed (@guaranteed Y) -> ()) -> ()
1365+
%5 = apply %3(%2) : $@convention(thin) (@owned @callee_guaranteed (@guaranteed Y) -> ()) -> ()
1366+
%13 = tuple ()
1367+
return %13 : $()
1368+
}
1369+
1370+
// CHECK-LABEL: Escape information for test_noescape_partial_apply_and_convert_function:
1371+
// CHECK: - : %0 = alloc_ref $Y
1372+
// CHECK: End function test_noescape_partial_apply_and_convert_function
1373+
sil @test_noescape_partial_apply_and_convert_function : $@convention(thin) () -> () {
1374+
bb0:
1375+
%0 = alloc_ref $Y
1376+
%1 = function_ref @closure1 : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> ()
1377+
%2 = partial_apply [callee_guaranteed] [on_stack] %1(%0) : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> ()
1378+
%3 = convert_function %2 : $@noescape @callee_guaranteed (@guaranteed Y) -> () to $@noescape @callee_guaranteed (@guaranteed Y) -> ()
1379+
%4 = function_ref @take_noescape_closure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (@guaranteed Y) -> ()) -> ()
1380+
%5 = apply %4(%3) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (@guaranteed Y) -> ()) -> ()
1381+
dealloc_stack %2 : $@noescape @callee_guaranteed (@guaranteed Y) -> ()
1382+
%13 = tuple ()
1383+
return %13 : $()
1384+
}
1385+
13531386
// CHECK-LABEL: Escape information for test_mismatching_existential_types:
13541387
// CHECK: - : %1 = alloc_ref $Y
13551388
// CHECK: End function test_mismatching_existential_types

0 commit comments

Comments
 (0)