Skip to content

Commit 55cda87

Browse files
authored
Merge pull request #58651 from jckarter/closure-literal-function-conversion-throws
SILGen: Emit a closure literal in a function conversion as the converted type.
2 parents 0650b8b + 482cc8a commit 55cda87

8 files changed

+80
-12
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,26 @@ static ManagedValue convertFunctionRepresentation(SILGenFunction &SGF,
17141714
llvm_unreachable("bad representation");
17151715
}
17161716

1717+
// Ideally our prolog/epilog emission would be able to handle all possible
1718+
// reabstractions and conversions. Until then, this returns true if a closure
1719+
// literal of type `literalType` can be directly emitted by SILGen as
1720+
// `convertedType`.
1721+
static bool canPeepholeLiteralClosureConversion(Type literalType,
1722+
Type convertedType) {
1723+
auto literalFnType = literalType->getAs<FunctionType>();
1724+
auto convertedFnType = convertedType->getAs<FunctionType>();
1725+
1726+
if (!literalFnType || !convertedFnType)
1727+
return false;
1728+
1729+
// Does the conversion only add `throws`?
1730+
if (literalFnType->isEqual(convertedFnType->getWithoutThrowing())) {
1731+
return true;
1732+
}
1733+
1734+
return false;
1735+
}
1736+
17171737
RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
17181738
SGFContext C)
17191739
{
@@ -1748,6 +1768,38 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
17481768
return RValue(SGF, e, result);
17491769
}
17501770

1771+
// If the function being converted is a closure literal, then the only use
1772+
// of the closure should be as the destination type of the conversion. Rather
1773+
// than emit the closure as is and convert it, see if we can emit the closure
1774+
// directly as the desired type.
1775+
//
1776+
// TODO: Move this up when we can emit closures directly with C calling
1777+
// convention.
1778+
auto subExpr = e->getSubExpr()->getSemanticsProvidingExpr();
1779+
if (isa<AbstractClosureExpr>(subExpr)
1780+
&& canPeepholeLiteralClosureConversion(subExpr->getType(),
1781+
e->getType())) {
1782+
// If we're emitting into a context with a preferred abstraction pattern
1783+
// already, carry that along.
1784+
auto origType = C.getAbstractionPattern();
1785+
// If not, use the conversion type as the desired abstraction pattern.
1786+
if (!origType) {
1787+
origType = AbstractionPattern(e->getType()->getCanonicalType());
1788+
}
1789+
1790+
auto substType = subExpr->getType()->getCanonicalType();
1791+
1792+
auto conversion = Conversion::getSubstToOrig(*origType, substType,
1793+
SGF.getLoweredType(*origType, substType));
1794+
ConvertingInitialization convertingInit(conversion, SGFContext());
1795+
auto closure = SGF.emitRValue(subExpr,
1796+
SGFContext(&convertingInit))
1797+
.getAsSingleValue(SGF, e);
1798+
closure = SGF.emitSubstToOrigValue(e, closure, *origType, substType);
1799+
1800+
return RValue(SGF, e, closure);
1801+
}
1802+
17511803
// Handle a reference to a "thin" native Swift function that only changes
17521804
// representation and refers to an inherently thin function reference.
17531805
if (destRepTy->getRepresentation() == FunctionTypeRepresentation::Thin) {

test/AutoDiff/SILOptimizer/activity_analysis.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -552,13 +552,12 @@ func testTryApply(_ x: Float) -> Float {
552552
// CHECK: bb0:
553553
// CHECK: [ACTIVE] %0 = argument of bb0 : $Float
554554
// CHECK: [NONE] // function_ref closure #1 in testTryApply(_:)
555-
// CHECK: [NONE] %3 = thin_to_thick_function %2 : $@convention(thin) () -> () to $@noescape @callee_guaranteed () -> ()
556-
// CHECK: [NONE] %4 = convert_function %3 : $@noescape @callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> @error Error
555+
// CHECK: [NONE] %3 = thin_to_thick_function %2 : $@convention(thin) () -> @error Error to $@noescape @callee_guaranteed () -> @error Error
557556
// CHECK: [NONE] // function_ref rethrowing(_:)
558557
// CHECK: bb1:
559-
// CHECK: [NONE] %7 = argument of bb1 : $()
558+
// CHECK: [NONE] %6 = argument of bb1 : $()
560559
// CHECK: bb2:
561-
// CHECK: [NONE] %9 = argument of bb2 : $Error
560+
// CHECK: [NONE] %8 = argument of bb2 : $Error
562561

563562
//===----------------------------------------------------------------------===//
564563
// Coroutine differentiation (`begin_apply`)

test/DebugInfo/patternvars.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public func mangle(s: [UnicodeScalar]) -> [UnicodeScalar] {
3535
// Do we care to expose these via lldb?
3636

3737
// CHECK: define {{.*}}@"$s11patternvars6mangle1sSayAA13UnicodeScalarVGAF_tFA2EXEfU_"
38-
// CHECK: %[[VAL:[0-9]+]] = call swiftcc i32 @"$s11patternvars13UnicodeScalarV5values6UInt32Vvg"(i32 %0)
38+
// CHECK: %[[VAL:[0-9]+]] = call swiftcc i32 @"$s11patternvars13UnicodeScalarV5values6UInt32Vvg"(
3939
// CHECK: {{[0-9]+}}:
4040
// CHECK-NOT: call void @llvm.dbg.value
4141
// CHECK-NOT: call void asm sideeffect "", "r"

test/IRGen/big_types_corner_cases.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ public func testGetFunc() {
203203
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} hidden swiftcc void @"$s22big_types_corner_cases7TestBigC4testyyF"(%T22big_types_corner_cases7TestBigC* swiftself %0)
204204
// CHECK: [[CALL1:%.*]] = call {{.*}} @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSayy22big_types_corner_cases9BigStructVcSgGMD"
205205
// CHECK: [[CALL2:%.*]] = call i8** @"$sSayy22big_types_corner_cases9BigStructVcSgGSayxGSlsWl
206-
// CHECK: call swiftcc void @"$sSlsE10firstIndex5where0B0QzSgSb7ElementQzKXE_tKF"(%swift.opaque* noalias nocapture sret({{.*}}) %{{[0-9]+}}, i8* bitcast ({{.*}}* @"$s22big_types_corner_cases9BigStruct{{.*}}_TRTA{{(\.ptrauth)?}}" to i8*), %swift.opaque* %{{[0-9]+}}, %swift.type* %{{[0-9]+}}, i8** [[CALL2]]
206+
// CHECK: call swiftcc void @"$sSlsE10firstIndex5where0B0QzSgSb7ElementQzKXE_tKF"(%swift.opaque* noalias nocapture sret({{.*}}) %{{[0-9]+}}, i8* bitcast ({{.*}}* @"$s22big_types_corner_cases7TestBig{{.*}}" to i8*), %swift.opaque* null, %swift.type* %{{[0-9]+}}, i8** [[CALL2]]
207207
class TestBig {
208208
typealias Handler = (BigStruct) -> Void
209209

test/Profiler/coverage_closure_returns_never.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
// CHECK-LABEL: closure #1 (Swift.Never) -> Swift.Never in coverage_closure_returns_never.closure_with_fatal_error(Swift.Array<Swift.Never>) -> ()
44
// CHECK: builtin "int_instrprof_increment"
5-
// CHECK-NEXT: debug_value {{.*}} : $Never
5+
// CHECK-NEXT: [[LOAD:%.*]] = load {{.*}} : $*Never
6+
// CHECK-NEXT: debug_value [[LOAD]] : $Never
67
// CHECK-NEXT: unreachable
78

89
func closure_with_fatal_error(_ arr: [Never]) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s -disable-availability-checking | %FileCheck %s
2+
// REQUIRES: concurrency
3+
4+
@_silgen_name("takeThrowingAsyncClosure")
5+
func takeThrowingAsyncClosure<T>(_: () async throws -> T)
6+
7+
// CHECK-LABEL: sil {{.*}} @{{.*}}34passNonthrowingAsyncClosureLiteral
8+
func passNonthrowingAsyncClosureLiteral() {
9+
// Check that the literal closure was emitted directly with an error return,
10+
// without a reabstraction thunk to convert from nonthrowing.
11+
// CHECK: [[INVOKE_FN:%.*]] = function_ref
12+
// CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[INVOKE_FN]]
13+
// CHECK: [[CALLEE:%.*]] = function_ref @takeThrowingAsyncClosure
14+
// CHECK: apply [[CALLEE]]<Int>([[CLOSURE]])
15+
takeThrowingAsyncClosure { return 42 }
16+
}

test/SILGen/rethrows.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,10 @@ func test2() {
7070
}
7171

7272
// CHECK-LABEL: sil hidden @$s8rethrows5test3yyF : $@convention(thin) () -> () {
73-
// CHECK: [[CLOSURE:%.*]] = function_ref @$s8rethrows5test3yyFSiyXEfU_ : $@convention(thin) () -> Int
73+
// CHECK: [[CLOSURE:%.*]] = function_ref @$s8rethrows5test3yyFSiyXEfU_ :
7474
// CHECK: [[T0:%.*]] = thin_to_thick_function [[CLOSURE]]
75-
// CHECK: [[T1:%.*]] = convert_function [[T0]] : $@noescape @callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> (Int, @error Error)
76-
// CHECK: [[RETHROWER:%.*]] = function_ref @$s8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
77-
// CHECK: try_apply [[RETHROWER]]([[T1]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
75+
// CHECK: [[RETHROWER:%.*]] = function_ref @$s8rethrows9rethroweryS2iyKXEKF :
76+
// CHECK: try_apply [[RETHROWER]]([[T0]])
7877
// CHECK: [[NORMAL]]({{%.*}} : $Int):
7978
// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
8079
// CHECK-NEXT: return [[RESULT]]

test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ struct S4<Base> where Base : P1, Base.Element: P1 {
6464
// CHECK-LABEL: {{^}}sil {{.*}} @${{.*}}2S4{{.*}}3foo{{.*}}F :
6565
// CHECK: @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : P1, τ_0_0 == τ_0_1, τ_0_0.Element : P1> (@in_guaranteed S3<τ_0_0>) -> () for <Base, Base>
6666
func foo(index: S3<Base>?) {
67-
_ = index.map({ _ = $0 })
67+
let f: (S3<Base>) -> () = { _ = $0 }
68+
_ = index.map(f)
6869
}
6970
}
7071

0 commit comments

Comments
 (0)