Skip to content

Commit f352ef1

Browse files
Merge pull request #12719 from aschwaighofer/silgen_callee_guaranteed
SILGen: Conditionally use @callee_guaranteed contexts
2 parents f54d8b4 + b25344b commit f352ef1

File tree

9 files changed

+102
-37
lines changed

9 files changed

+102
-37
lines changed

include/swift/AST/Types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3418,6 +3418,12 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
34183418
bool isCalleeConsumed() const {
34193419
return getCalleeConvention() == ParameterConvention::Direct_Owned;
34203420
}
3421+
bool isCalleeUnowned() const {
3422+
return getCalleeConvention() == ParameterConvention::Direct_Unowned;
3423+
}
3424+
bool isCalleeGuaranteed() const {
3425+
return getCalleeConvention() == ParameterConvention::Direct_Guaranteed;
3426+
}
34213427

34223428
/// Return the array of all result information. This may contain inter-mingled
34233429
/// direct and indirect results.

lib/SIL/SILFunctionType.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ enum class ConventionsKind : uint8_t {
234234
getDirectParameter(unsigned index,
235235
const AbstractionPattern &type,
236236
const TypeLowering &substTL) const = 0;
237-
virtual ParameterConvention getCallee() const = 0;
237+
virtual ParameterConvention getCallee(bool useGuaranteedContext) const = 0;
238238
virtual ResultConvention getResult(const TypeLowering &resultTL) const = 0;
239239
virtual ParameterConvention
240240
getIndirectSelfParameter(const AbstractionPattern &type) const = 0;
@@ -948,7 +948,8 @@ static CanSILFunctionType getSILFunctionType(
948948

949949
auto calleeConvention = ParameterConvention::Direct_Unowned;
950950
if (extInfo.hasContext())
951-
calleeConvention = conventions.getCallee();
951+
calleeConvention =
952+
conventions.getCallee(M.getOptions().EnableGuaranteedClosureContexts);
952953

953954
bool pseudogeneric = (constant ? isPseudogeneric(*constant) : false);
954955

@@ -986,7 +987,7 @@ struct DeallocatorConventions : Conventions {
986987
llvm_unreachable("Deallocators do not have non-self direct parameters");
987988
}
988989

989-
ParameterConvention getCallee() const override {
990+
ParameterConvention getCallee(bool) const override {
990991
llvm_unreachable("Deallocators do not have callees");
991992
}
992993

@@ -1036,7 +1037,9 @@ namespace {
10361037
return ParameterConvention::Direct_Owned;
10371038
}
10381039

1039-
ParameterConvention getCallee() const override {
1040+
ParameterConvention getCallee(bool useGuaranteedContext) const override {
1041+
if (useGuaranteedContext)
1042+
return ParameterConvention::Direct_Guaranteed;
10401043
return DefaultThickCalleeConvention;
10411044
}
10421045

@@ -1093,7 +1096,7 @@ namespace {
10931096
return ParameterConvention::Direct_Unowned;
10941097
}
10951098

1096-
ParameterConvention getCallee() const override {
1099+
ParameterConvention getCallee(bool) const override {
10971100
return ParameterConvention::Direct_Unowned;
10981101
}
10991102

@@ -1263,7 +1266,7 @@ namespace {
12631266
return getDirectCParameterConvention(Method->param_begin()[index]);
12641267
}
12651268

1266-
ParameterConvention getCallee() const override {
1269+
ParameterConvention getCallee(bool) const override {
12671270
// Always thin.
12681271
return ParameterConvention::Direct_Unowned;
12691272
}
@@ -1414,7 +1417,7 @@ namespace {
14141417
return getDirectCParameterConvention(getParamType(index));
14151418
}
14161419

1417-
ParameterConvention getCallee() const override {
1420+
ParameterConvention getCallee(bool) const override {
14181421
// FIXME: blocks should be Direct_Guaranteed.
14191422
return ParameterConvention::Direct_Unowned;
14201423
}
@@ -1707,7 +1710,7 @@ namespace {
17071710
return ParameterConvention::Direct_Unowned;
17081711
}
17091712

1710-
ParameterConvention getCallee() const override {
1713+
ParameterConvention getCallee(bool) const override {
17111714
// Always thin.
17121715
return ParameterConvention::Direct_Unowned;
17131716
}

lib/SILGen/SILGenApply.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,9 +1684,11 @@ static SILValue emitRawApply(SILGenFunction &SGF,
16841684
ArrayRef<SILValue> indirectResultAddrs) {
16851685
SILFunctionConventions substFnConv(substFnType, SGF.SGM.M);
16861686
// Get the callee value.
1687-
SILValue fnValue = substFnType->isCalleeConsumed()
1688-
? fn.forward(SGF)
1689-
: fn.getValue();
1687+
bool isConsumed = substFnType->isCalleeConsumed();
1688+
bool isUnowned = substFnType->isCalleeUnowned();
1689+
SILValue fnValue =
1690+
isUnowned ? fn.getValue()
1691+
: isConsumed ? fn.forward(SGF) : fn.borrow(SGF, loc).getValue();
16901692

16911693
SmallVector<SILValue, 4> argValues;
16921694

@@ -4369,9 +4371,11 @@ CallEmission::applyPartiallyAppliedSuperMethod(unsigned uncurryLevel,
43694371
functionTy);
43704372
}
43714373
}
4374+
auto calleeConvention = SGF.SGM.M.getOptions().EnableGuaranteedClosureContexts
4375+
? ParameterConvention::Direct_Guaranteed
4376+
: ParameterConvention::Direct_Owned;
43724377
auto closureTy = SILGenBuilder::getPartialApplyResultType(
4373-
constantInfo.getSILType(), 1, SGF.B.getModule(), subs,
4374-
ParameterConvention::Direct_Owned);
4378+
constantInfo.getSILType(), 1, SGF.B.getModule(), subs, calleeConvention);
43754379

43764380
auto &module = SGF.getFunction().getModule();
43774381

@@ -5569,11 +5573,14 @@ static ManagedValue emitDynamicPartialApply(SILGenFunction &SGF,
55695573
SILValue self,
55705574
CanAnyFunctionType foreignFormalType,
55715575
CanAnyFunctionType nativeFormalType) {
5572-
auto partialApplyTy = SILBuilder::getPartialApplyResultType(method->getType(),
5573-
/*argCount*/1,
5574-
SGF.SGM.M,
5575-
/*subs*/{},
5576-
ParameterConvention::Direct_Owned);
5576+
auto calleeConvention = SGF.SGM.M.getOptions().EnableGuaranteedClosureContexts
5577+
? ParameterConvention::Direct_Guaranteed
5578+
: ParameterConvention::Direct_Owned;
5579+
5580+
auto partialApplyTy =
5581+
SILBuilder::getPartialApplyResultType(method->getType(),
5582+
/*argCount*/ 1, SGF.SGM.M,
5583+
/*subs*/ {}, calleeConvention);
55775584

55785585
// Retain 'self' because the partial apply will take ownership.
55795586
// We can't simply forward 'self' because the partial apply is conditional.

lib/SILGen/SILGenFunction.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
210210
// Our 'let' binding can guarantee the lifetime for the callee,
211211
// if we don't need to do anything more to it.
212212
if (canGuarantee && !var->getType()->is<ReferenceStorageType>()) {
213-
auto guaranteed = ManagedValue::forUnmanaged(Val);
213+
auto guaranteed = ManagedValue::forUnmanaged(Val).borrow(*this, loc);
214214
capturedArgs.push_back(guaranteed);
215215
break;
216216
}
@@ -256,7 +256,8 @@ void SILGenFunction::emitCaptures(SILLocation loc,
256256
if (vl.box) {
257257
// We can guarantee our own box to the callee.
258258
if (canGuarantee) {
259-
capturedArgs.push_back(ManagedValue::forUnmanaged(vl.box));
259+
capturedArgs.push_back(
260+
ManagedValue::forUnmanaged(vl.box).borrow(*this, loc));
260261
} else {
261262
capturedArgs.push_back(emitManagedRetain(loc, vl.box));
262263
}
@@ -282,7 +283,11 @@ void SILGenFunction::emitCaptures(SILLocation loc,
282283
ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox, 0);
283284
B.createCopyAddr(loc, vl.value, boxAddress, IsNotTake,
284285
IsInitialization);
285-
capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox));
286+
if (canGuarantee)
287+
capturedArgs.push_back(
288+
emitManagedRValueWithCleanup(allocBox).borrow(*this, loc));
289+
else
290+
capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox));
286291
}
287292

288293
break;
@@ -357,11 +362,14 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
357362
for (auto capture : capturedArgs)
358363
forwardedArgs.push_back(capture.forward(*this));
359364

360-
SILType closureTy =
361-
SILGenBuilder::getPartialApplyResultType(functionRef->getType(),
362-
capturedArgs.size(), SGM.M,
363-
subs,
364-
ParameterConvention::Direct_Owned);
365+
auto calleeConvention = SGM.M.getOptions().EnableGuaranteedClosureContexts
366+
? ParameterConvention::Direct_Guaranteed
367+
: ParameterConvention::Direct_Owned;
368+
369+
SILType closureTy = SILGenBuilder::getPartialApplyResultType(
370+
functionRef->getType(), capturedArgs.size(), SGM.M, subs,
371+
calleeConvention);
372+
365373
auto toClosure =
366374
B.createPartialApply(loc, functionRef, functionTy,
367375
subs, forwardedArgs, closureTy);

lib/SILGen/SILGenPoly.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,11 +2624,12 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
26242624
// Add the rest of the arguments.
26252625
forwardFunctionArguments(SGF, loc, fnType, args, argValues);
26262626

2627+
auto fun = fnType->isCalleeGuaranteed() ? fnValue.borrow(SGF, loc).getValue()
2628+
: fnValue.forward(SGF);
26272629
SILValue innerResult =
2628-
SGF.emitApplyWithRethrow(loc, fnValue.forward(SGF),
2629-
/*substFnType*/ fnValue.getType(),
2630-
/*substitutions*/ {},
2631-
argValues);
2630+
SGF.emitApplyWithRethrow(loc, fun,
2631+
/*substFnType*/ fnValue.getType(),
2632+
/*substitutions*/ {}, argValues);
26322633

26332634
// Reabstract the result.
26342635
SILValue outerResult = resultPlanner.execute(innerResult);

lib/SILGen/SILGenProlog.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@ static void emitCaptureArguments(SILGenFunction &SGF,
396396
// temporary within the closure to provide this address.
397397
if (VD->isSettable(VD->getDeclContext())) {
398398
auto addr = SGF.emitTemporaryAllocation(VD, ty);
399+
if (SGF.SGM.M.getOptions().EnableGuaranteedClosureContexts)
400+
val = SGF.B.createCopyValue(Loc, val);
399401
lowering.emitStore(SGF.B, VD, val, addr, StoreOwnershipQualifier::Init);
400402
val = addr;
401403
}

lib/SILGen/SILGenThunk.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,13 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) {
165165
resultTy = F.mapTypeIntoContext(resultTy);
166166
auto substTy = toFn->getType().substGenericArgs(SGM.M, subs);
167167

168+
auto calleeConvention = SGM.M.getOptions().EnableGuaranteedClosureContexts
169+
? ParameterConvention::Direct_Guaranteed
170+
: ParameterConvention::Direct_Owned;
171+
168172
// Partially apply the next uncurry level and return the result closure.
169-
auto closureTy =
170-
SILGenBuilder::getPartialApplyResultType(toFn->getType(), /*appliedParams=*/1,
171-
SGM.M, subs,
172-
ParameterConvention::Direct_Owned);
173+
auto closureTy = SILGenBuilder::getPartialApplyResultType(
174+
toFn->getType(), /*appliedParams=*/1, SGM.M, subs, calleeConvention);
173175
SILValue toClosure =
174176
B.createPartialApply(vd, toFn, substTy, subs, {selfArg}, closureTy);
175177
if (resultTy != closureTy)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -parse-as-library -enable-guaranteed-closure-contexts -emit-silgen %s | %FileCheck %s
2+
import Swift
3+
4+
// CHECK-LABEL: sil @{{.*}}apply{{.*}} : $@convention(thin) (@owned @noescape @callee_guaranteed () -> Int)
5+
// bb0(%0 : @owned $@noescape @callee_guaranteed () -> Int):
6+
// [[B1:%.*]] = begin_borrow %0 : $@noescape @callee_guaranteed () -> Int
7+
// [[C1:%.*]] = copy_value %2 : $@noescape @callee_guaranteed () -> Int
8+
//
9+
// The important part is that the call borrow's the function value -- we are
10+
// @callee_guaranteed.
11+
// [[B2:%.*]] = begin_borrow [[C1]] : $@noescape @callee_guaranteed () -> Int
12+
// [[R:%.*]] = apply [[B2]]() : $@noescape @callee_guaranteed () -> Int
13+
// end_borrow [[B2]] from [[C1]] : $@noescape @callee_guaranteed () -> Int, $@noescape @callee_guaranteed () -> Int
14+
//
15+
// destroy_value [[C1]] : $@noescape @callee_guaranteed () -> Int
16+
// end_borrow [[B1]] from %0 : $@noescape @callee_guaranteed () -> Int, $@noescape @callee_guaranteed () -> Int
17+
// destroy_value %0 : $@noescape @callee_guaranteed () -> Int
18+
// return [[R]] : $Int
19+
public func apply(_ f : () -> Int) -> Int {
20+
return f()
21+
}
22+
23+
// CHECK-LABEL: sil @{{.*}}test{{.*}} : $@convention(thin) () -> ()
24+
// CHECK: [[A:%.*]] = function_ref @{{.*}}apply{{.*}} : $@convention(thin) (@owned @noescape @callee_guaranteed () -> Int) -> Int
25+
// CHECK: [[C1:%.*]] = function_ref @{{.*}}test{{.*}} : $@convention(thin) () -> Int
26+
// CHECK: [[C2:%.*]] = convert_function [[C1]] : $@convention(thin) () -> Int to $@convention(thin) @noescape () -> Int
27+
// CHECK: [[C3:%.*]] = thin_to_thick_function [[C2]] : $@convention(thin) @noescape () -> Int to $@noescape @callee_guaranteed () -> Int
28+
// CHECK: apply [[A]]([[C3]]) : $@convention(thin) (@owned @noescape @callee_guaranteed () -> Int) -> Int
29+
public func test() {
30+
let res = apply({ return 1 })
31+
}

test/SILGen/guaranteed_closure_context.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -parse-as-library -emit-silgen -enable-guaranteed-closure-contexts %s | %FileCheck %s
1+
// RUN: %target-swift-frontend -parse-as-library -emit-silgen -enable-sil-ownership -enable-guaranteed-closure-contexts %s | %FileCheck %s
22

33
func use<T>(_: T) {}
44

@@ -33,10 +33,16 @@ func guaranteed_captures() {
3333
// CHECK-NOT: copy_value [[MUTABLE_RETAINABLE_BOX]]
3434
// CHECK-NOT: copy_value [[MUTABLE_ADDRESS_ONLY_BOX]]
3535
// CHECK-NOT: copy_value [[IMMUTABLE_RETAINABLE]]
36+
37+
// CHECK: [[B_MUTABLE_TRIVIAL_BOX:%.*]] = begin_borrow [[MUTABLE_TRIVIAL_BOX]] : ${ var S }
38+
// CHECK: [[B_MUTABLE_RETAINABLE_BOX:%.*]] = begin_borrow [[MUTABLE_RETAINABLE_BOX]] : ${ var C }
39+
// CHECK: [[B_MUTABLE_ADDRESS_ONLY_BOX:%.*]] = begin_borrow [[MUTABLE_ADDRESS_ONLY_BOX]] : ${ var P }
40+
// CHECK: [[B_IMMUTABLE_RETAINABLE:%.*]] = begin_borrow [[IMMUTABLE_RETAINABLE]] : $C
3641
// CHECK: [[IMMUTABLE_AO_BOX:%.*]] = alloc_box ${ var P }
42+
// CHECK: [[B_IMMUTABLE_AO_BOX:%.*]] = begin_borrow [[IMMUTABLE_AO_BOX]] : ${ var P }
3743

3844
// CHECK: [[FN:%.*]] = function_ref [[FN_NAME:@_T026guaranteed_closure_context0A9_capturesyyF17captureEverythingL_yyF]]
39-
// CHECK: apply [[FN]]([[MUTABLE_TRIVIAL_BOX]], [[MUTABLE_RETAINABLE_BOX]], [[MUTABLE_ADDRESS_ONLY_BOX]], [[IMMUTABLE_TRIVIAL]], [[IMMUTABLE_RETAINABLE]], [[IMMUTABLE_AO_BOX]])
45+
// CHECK: apply [[FN]]([[B_MUTABLE_TRIVIAL_BOX]], [[B_MUTABLE_RETAINABLE_BOX]], [[B_MUTABLE_ADDRESS_ONLY_BOX]], [[IMMUTABLE_TRIVIAL]], [[B_IMMUTABLE_RETAINABLE]], [[B_IMMUTABLE_AO_BOX]])
4046
captureEverything()
4147

4248
// CHECK: destroy_value [[IMMUTABLE_AO_BOX]]
@@ -64,7 +70,6 @@ func guaranteed_captures() {
6470
// CHECK-NOT: destroy_value [[IMMUTABLE_AO_BOX]]
6571

6672
escape(captureEverything)
67-
6873
}
6974

7075
// CHECK: sil private [[FN_NAME]] : $@convention(thin) (@guaranteed { var S }, @guaranteed { var C }, @guaranteed { var P }, S, @guaranteed C, @guaranteed { var P })

0 commit comments

Comments
 (0)