Skip to content

Commit 64f2172

Browse files
authored
Merge pull request swiftlang#61238 from jckarter/function-conversion-peephole-for-capture-lists
SILGen: Apply function_conversion peephole to CaptureListExprs.
2 parents 764a4d2 + f36668e commit 64f2172

File tree

4 files changed

+74
-11
lines changed

4 files changed

+74
-11
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,11 +1754,26 @@ static bool canPeepholeLiteralClosureConversion(Type literalType,
17541754
return true;
17551755
}
17561756

1757-
// Does the conversion only add `throws`?
1758-
if (literalFnType->isEqual(convertedFnType->getWithoutThrowing())) {
1757+
// Are the types equivalent aside from effects (throws) or coeffects
1758+
// (escaping)? Then we should emit the literal as having the destination type
1759+
// (co)effects, even if it doesn't exercise them.
1760+
//
1761+
// TODO: We could also in principle let `async` through here, but that
1762+
// interferes with the implementation of `reasync`.
1763+
auto literalWithoutEffects = literalFnType->getExtInfo().intoBuilder()
1764+
.withThrows(false)
1765+
.withNoEscape(false)
1766+
.build();
1767+
1768+
auto convertedWithoutEffects = convertedFnType->getExtInfo().intoBuilder()
1769+
.withThrows(false)
1770+
.withNoEscape(false)
1771+
.build();
1772+
if (literalFnType->withExtInfo(literalWithoutEffects)
1773+
->isEqual(convertedFnType->withExtInfo(convertedWithoutEffects))) {
17591774
return true;
17601775
}
1761-
1776+
17621777
return false;
17631778
}
17641779

@@ -1804,7 +1819,7 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
18041819
// TODO: Move this up when we can emit closures directly with C calling
18051820
// convention.
18061821
auto subExpr = e->getSubExpr()->getSemanticsProvidingExpr();
1807-
if (isa<AbstractClosureExpr>(subExpr)
1822+
if ((isa<AbstractClosureExpr>(subExpr) || isa<CaptureListExpr>(subExpr))
18081823
&& canPeepholeLiteralClosureConversion(subExpr->getType(),
18091824
e->getType())) {
18101825
// If we're emitting into a context with a preferred abstraction pattern

lib/SILGen/SILGenPoly.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
//
8383
//===----------------------------------------------------------------------===//
8484

85+
#define DEBUG_TYPE "silgen-poly"
8586
#include "ExecutorBreadcrumb.h"
8687
#include "Initialization.h"
8788
#include "LValue.h"
@@ -3055,6 +3056,24 @@ static ManagedValue createThunk(SILGenFunction &SGF,
30553056
auto substSourceType = fn.getType().castTo<SILFunctionType>();
30563057
auto substExpectedType = expectedTL.getLoweredType().castTo<SILFunctionType>();
30573058

3059+
LLVM_DEBUG(llvm::dbgs() << "=== Generating reabstraction thunk from:\n";
3060+
substSourceType.dump(llvm::dbgs());
3061+
llvm::dbgs() << "\n to:\n";
3062+
substExpectedType.dump(llvm::dbgs());
3063+
llvm::dbgs() << "\n for source location:\n";
3064+
if (auto d = loc.getAsASTNode<Decl>()) {
3065+
d->dump(llvm::dbgs());
3066+
} else if (auto e = loc.getAsASTNode<Expr>()) {
3067+
e->dump(llvm::dbgs());
3068+
} else if (auto s = loc.getAsASTNode<Stmt>()) {
3069+
s->dump(llvm::dbgs());
3070+
} else if (auto p = loc.getAsASTNode<Pattern>()) {
3071+
p->dump(llvm::dbgs());
3072+
} else {
3073+
loc.dump();
3074+
}
3075+
llvm::dbgs() << "\n");
3076+
30583077
// Apply substitutions in the source and destination types, since the thunk
30593078
// doesn't change because of different function representations.
30603079
CanSILFunctionType sourceType;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
func gen<T, U>(f: (T) throws -> U) {}
4+
5+
struct Butt {
6+
var x: Int
7+
}
8+
9+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractCaptureListExprArgument
10+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}U_
11+
// CHECK: [[CLOSURE:%.*]] = partial_apply {{.*}}[[CLOSURE_FN]]
12+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape {{.*}} [[CLOSURE]]
13+
// CHECK: apply {{.*}}<Int, Int>([[CLOSURE_NE]])
14+
func reabstractCaptureListExprArgument() {
15+
gen(f: {[x = 42] y in x + y })
16+
}
17+
18+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractKeyPathFunctionArgument
19+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}U_
20+
// CHECK: [[KP_ARG:%.*]] = copy_value {{.*}} $KeyPath
21+
// CHECK: [[CLOSURE:%.*]] = partial_apply {{.*}}[[CLOSURE_FN]]([[KP_ARG]])
22+
// CHECK: [[CLOSURE_NE:%.*]] = convert_escape_to_noescape {{.*}} [[CLOSURE]]
23+
// CHECK: apply {{.*}}<Butt, Int>([[CLOSURE_NE]])
24+
func reabstractKeyPathFunctionArgument() {
25+
gen(f: \Butt.x)
26+
}
27+
28+
// CHECK-LABEL: sil {{.*}} @{{.*}}reabstractStaticMemberRef
29+
// CHECK: [[CLOSURE_FN:%.*]] = function_ref {{.*}}u_
30+
// CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[CLOSURE_FN]]
31+
// CHECK: apply {{.*}}<Int, Butt>([[CLOSURE]])
32+
func reabstractStaticMemberRef() {
33+
gen(f: Butt.init)
34+
}

test/SILOptimizer/closure_lifetime_fixup.swift

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,10 @@ public func dontCrash<In, Out>(test: Bool, body: @escaping ((In) -> Out, In) ->
9595
}
9696

9797
// CHECK-LABEL: sil @$s22closure_lifetime_fixup28to_stack_of_convert_function1pySvSg_tF
98-
// CHECK: [[FN:%.*]] = function_ref @$s22closure_lifetime_fixup28to_stack_of_convert_function1pySvSg_tFSSSvcfu_ : $@convention(thin) (UnsafeMutableRawPointer) -> @owned String
98+
// CHECK: [[FN:%.*]] = function_ref @$s22closure_lifetime_fixup28to_stack_of_convert_function1pySvSg_tFSSSvcfu_ :
9999
// CHECK: [[PA:%.*]] = thin_to_thick_function [[FN]]
100-
// CHECK: [[CVT:%.*]] = convert_function [[PA]]
101-
// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[CVT]]
102-
// CHECK: [[REABSTRACT:%.*]] = function_ref @$sSvSSs5Error_pIgyozo_SvSSsAA_pIegnrzo_TR
103-
// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[REABSTRACT]]([[CVT2]])
104-
// CHECK: [[CF2:%.*]] = convert_function [[PA2]]
105100
// CHECK: [[MAP:%.*]] = function_ref @$sSq3mapyqd__Sgqd__xKXEKlF
106-
// CHECK: try_apply [[MAP]]<UnsafeMutableRawPointer, String>({{.*}}, [[CF2]], {{.*}})
101+
// CHECK: try_apply [[MAP]]<UnsafeMutableRawPointer, String>({{.*}}, [[PA]], {{.*}})
107102
public func to_stack_of_convert_function(p: UnsafeMutableRawPointer?) {
108103
_ = p.map(String.init(describing:))
109104
}

0 commit comments

Comments
 (0)