Skip to content

Commit b25344b

Browse files
committed
SILGen: Conditionally use @callee_guaranteed contexts
We need to borrow guaranteed values with sil ownership and need to distinguish between @callee_guaranteed and other context conventions in a few places. SR-5441 rdar://33255593
1 parent 2b1921b commit b25344b

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
@@ -3415,6 +3415,12 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
34153415
bool isCalleeConsumed() const {
34163416
return getCalleeConvention() == ParameterConvention::Direct_Owned;
34173417
}
3418+
bool isCalleeUnowned() const {
3419+
return getCalleeConvention() == ParameterConvention::Direct_Unowned;
3420+
}
3421+
bool isCalleeGuaranteed() const {
3422+
return getCalleeConvention() == ParameterConvention::Direct_Guaranteed;
3423+
}
34183424

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

lib/SIL/SILFunctionType.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ enum class ConventionsKind : uint8_t {
231231
getDirectParameter(unsigned index,
232232
const AbstractionPattern &type,
233233
const TypeLowering &substTL) const = 0;
234-
virtual ParameterConvention getCallee() const = 0;
234+
virtual ParameterConvention getCallee(bool useGuaranteedContext) const = 0;
235235
virtual ResultConvention getResult(const TypeLowering &resultTL) const = 0;
236236
virtual ParameterConvention
237237
getIndirectSelfParameter(const AbstractionPattern &type) const = 0;
@@ -946,7 +946,8 @@ static CanSILFunctionType getSILFunctionType(SILModule &M,
946946

947947
auto calleeConvention = ParameterConvention::Direct_Unowned;
948948
if (extInfo.hasContext())
949-
calleeConvention = conventions.getCallee();
949+
calleeConvention =
950+
conventions.getCallee(M.getOptions().EnableGuaranteedClosureContexts);
950951

951952
bool pseudogeneric = (constant ? isPseudogeneric(*constant) : false);
952953

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

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

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

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

@@ -1092,7 +1095,7 @@ namespace {
10921095
return ParameterConvention::Direct_Unowned;
10931096
}
10941097

1095-
ParameterConvention getCallee() const override {
1098+
ParameterConvention getCallee(bool) const override {
10961099
return ParameterConvention::Direct_Unowned;
10971100
}
10981101

@@ -1261,7 +1264,7 @@ namespace {
12611264
return getDirectCParameterConvention(Method->param_begin()[index]);
12621265
}
12631266

1264-
ParameterConvention getCallee() const override {
1267+
ParameterConvention getCallee(bool) const override {
12651268
// Always thin.
12661269
return ParameterConvention::Direct_Unowned;
12671270
}
@@ -1412,7 +1415,7 @@ namespace {
14121415
return getDirectCParameterConvention(getParamType(index));
14131416
}
14141417

1415-
ParameterConvention getCallee() const override {
1418+
ParameterConvention getCallee(bool) const override {
14161419
// FIXME: blocks should be Direct_Guaranteed.
14171420
return ParameterConvention::Direct_Unowned;
14181421
}
@@ -1702,7 +1705,7 @@ namespace {
17021705
return ParameterConvention::Direct_Unowned;
17031706
}
17041707

1705-
ParameterConvention getCallee() const override {
1708+
ParameterConvention getCallee(bool) const override {
17061709
// Always thin.
17071710
return ParameterConvention::Direct_Unowned;
17081711
}

lib/SILGen/SILGenApply.cpp

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

16941696
SmallVector<SILValue, 4> argValues;
16951697

@@ -4372,9 +4374,11 @@ CallEmission::applyPartiallyAppliedSuperMethod(unsigned uncurryLevel,
43724374
functionTy);
43734375
}
43744376
}
4377+
auto calleeConvention = SGF.SGM.M.getOptions().EnableGuaranteedClosureContexts
4378+
? ParameterConvention::Direct_Guaranteed
4379+
: ParameterConvention::Direct_Owned;
43754380
auto closureTy = SILGenBuilder::getPartialApplyResultType(
4376-
constantInfo.getSILType(), 1, SGF.B.getModule(), subs,
4377-
ParameterConvention::Direct_Owned);
4381+
constantInfo.getSILType(), 1, SGF.B.getModule(), subs, calleeConvention);
43784382

43794383
auto &module = SGF.getFunction().getModule();
43804384

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

55815588
// Retain 'self' because the partial apply will take ownership.
55825589
// 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)