Skip to content

Commit 8e41dc8

Browse files
authored
Merge pull request #5167 from jckarter/partial-apply-callee-ownership
2 parents bf38b86 + 664390a commit 8e41dc8

File tree

14 files changed

+147
-38
lines changed

14 files changed

+147
-38
lines changed

docs/SIL.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2956,10 +2956,11 @@ partial_apply
29562956
`````````````
29572957
::
29582958

2959-
sil-instruction ::= 'partial_apply' sil-value
2959+
sil-instruction ::= 'partial_apply' callee-ownership-attr? sil-value
29602960
sil-apply-substitution-list?
29612961
'(' (sil-value (',' sil-value)*)? ')'
29622962
':' sil-type
2963+
callee-ownership-attr ::= '[callee_guaranteed]'
29632964

29642965
%c = partial_apply %0(%1, %2, ...) : $(Z..., A, B, ...) -> R
29652966
// Note that the type of the callee '%0' is specified *after* the arguments
@@ -2996,6 +2997,11 @@ currently implicitly performs abstraction difference transformations enabled
29962997
by the given substitutions, such as promoting address-only arguments and returns
29972998
to register arguments. This should be fixed.
29982999

3000+
By default, ``partial_apply`` creates a closure whose invocation takes ownership
3001+
of the context, meaning that a call implicitly releases the closure. The
3002+
``[callee_guaranteed]`` change this to a caller-guaranteed model, where the
3003+
caller promises not to release the closure while the function is being called.
3004+
29993005
This instruction is used to implement both curry thunks and closures. A
30003006
curried function in Swift::
30013007

include/swift/Option/FrontendOptions.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def enable_guaranteed_closure_contexts : Flag<["-"], "enable-guaranteed-closure-
164164
HelpText<"Use @guaranteed convention for closure context">;
165165

166166
def remove_runtime_asserts : Flag<["-"], "remove-runtime-asserts">,
167-
HelpText<"Remove runtime asserts.">;
167+
HelpText<"Remove runtime asserts.">;
168168

169169
def disable_access_control : Flag<["-"], "disable-access-control">,
170170
HelpText<"Don't respect access control restrictions">;

include/swift/SIL/SILBuilder.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ class SILBuilder {
195195
//===--------------------------------------------------------------------===//
196196

197197
static SILType getPartialApplyResultType(SILType Ty, unsigned ArgCount,
198-
SILModule &M,
199-
ArrayRef<Substitution> subs);
198+
SILModule &M,
199+
ArrayRef<Substitution> subs,
200+
ParameterConvention calleeConvention);
200201

201202
//===--------------------------------------------------------------------===//
202203
// CFG Manipulation

include/swift/SIL/SILInstruction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1329,7 +1329,7 @@ class PartialApplyInst
13291329
SILOpenedArchetypesState &OpenedArchetypes);
13301330

13311331
public:
1332-
/// Return the ast level function type of this partial apply.
1332+
/// Return the result function type of this partial apply.
13331333
CanSILFunctionType getFunctionType() const {
13341334
return getType().castTo<SILFunctionType>();
13351335
}

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 272; // Add tail_elems to alloc_ref_dynamic
57+
const uint16_t VERSION_MINOR = 273; // Last change: partial_apply ownership control
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

lib/Parse/ParseSIL.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3737,9 +3737,18 @@ bool SILParser::parseCallInstruction(SILLocation InstLoc,
37373737
UnresolvedValueName FnName;
37383738
SmallVector<UnresolvedValueName, 4> ArgNames;
37393739

3740+
auto PartialApplyConvention = ParameterConvention::Direct_Owned;
37403741
bool IsNonThrowingApply = false;
3741-
if (parseSILOptional(IsNonThrowingApply, *this, "nothrow"))
3742-
return true;
3742+
StringRef AttrName;
3743+
3744+
if (parseSILOptional(AttrName, *this)) {
3745+
if (AttrName.equals("nothrow"))
3746+
IsNonThrowingApply = true;
3747+
else if (AttrName.equals("callee_guaranteed"))
3748+
PartialApplyConvention = ParameterConvention::Direct_Guaranteed;
3749+
else
3750+
return true;
3751+
}
37433752

37443753
if (parseValueName(FnName))
37453754
return true;
@@ -3838,7 +3847,8 @@ bool SILParser::parseCallInstruction(SILLocation InstLoc,
38383847
}
38393848

38403849
SILType closureTy =
3841-
SILBuilder::getPartialApplyResultType(Ty, ArgNames.size(), SILMod, subs);
3850+
SILBuilder::getPartialApplyResultType(Ty, ArgNames.size(), SILMod, subs,
3851+
PartialApplyConvention);
38423852
// FIXME: Why the arbitrary order difference in IRBuilder type argument?
38433853
ResultVal = B.createPartialApply(InstLoc, FnVal, FnTy,
38443854
subs, Args, closureTy);

lib/SIL/SILBuilder.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ TupleInst *SILBuilder::createTuple(SILLocation loc, ArrayRef<SILValue> elts) {
2929
}
3030

3131
SILType SILBuilder::getPartialApplyResultType(SILType origTy, unsigned argCount,
32-
SILModule &M,
33-
ArrayRef<Substitution> subs) {
32+
SILModule &M,
33+
ArrayRef<Substitution> subs,
34+
ParameterConvention calleeConvention) {
3435
CanSILFunctionType FTI = origTy.castTo<SILFunctionType>();
3536
if (!subs.empty())
3637
FTI = FTI->substGenericArgs(M, M.getSwiftModule(), subs);
@@ -59,7 +60,7 @@ SILType SILBuilder::getPartialApplyResultType(SILType origTy, unsigned argCount,
5960
}
6061

6162
auto appliedFnType = SILFunctionType::get(nullptr, extInfo,
62-
ParameterConvention::Direct_Owned,
63+
calleeConvention,
6364
newParams,
6465
results,
6566
FTI->getOptionalErrorResult(),

lib/SIL/SILPrinter.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -910,10 +910,26 @@ class SILPrinter : public SILVisitor<SILPrinter> {
910910
*this << ", normal " << getID(AI->getNormalBB());
911911
*this << ", error " << getID(AI->getErrorBB());
912912
}
913-
914-
913+
915914
void visitPartialApplyInst(PartialApplyInst *CI) {
916915
*this << "partial_apply ";
916+
switch (CI->getFunctionType()->getCalleeConvention()) {
917+
case ParameterConvention::Direct_Owned:
918+
// Default; do nothing.
919+
break;
920+
case ParameterConvention::Direct_Guaranteed:
921+
*this << "[callee_guaranteed] ";
922+
break;
923+
924+
// Should not apply to callees.
925+
case ParameterConvention::Direct_Unowned:
926+
case ParameterConvention::Direct_Deallocating:
927+
case ParameterConvention::Indirect_In:
928+
case ParameterConvention::Indirect_Inout:
929+
case ParameterConvention::Indirect_In_Guaranteed:
930+
case ParameterConvention::Indirect_InoutAliasable:
931+
llvm_unreachable("unexpected callee convention!");
932+
}
917933
*this << getID(CI->getCallee());
918934
printSubstitutions(CI->getSubstitutions());
919935
*this << '(';

lib/SILGen/SILGenApply.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4405,7 +4405,8 @@ namespace {
44054405
constantInfo.getSILType(),
44064406
1,
44074407
gen.B.getModule(),
4408-
subs);
4408+
subs,
4409+
ParameterConvention::Direct_Owned);
44094410

44104411
auto &module = gen.getFunction().getModule();
44114412

@@ -5417,9 +5418,10 @@ static SILValue emitDynamicPartialApply(SILGenFunction &gen,
54175418
SILValue self,
54185419
CanFunctionType methodTy) {
54195420
auto partialApplyTy = SILBuilder::getPartialApplyResultType(method->getType(),
5420-
/*argCount*/1,
5421-
gen.SGM.M,
5422-
/*subs*/{});
5421+
/*argCount*/1,
5422+
gen.SGM.M,
5423+
/*subs*/{},
5424+
ParameterConvention::Direct_Owned);
54235425

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

lib/SILGen/SILGenFunction.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,8 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
428428
SILType closureTy =
429429
SILGenBuilder::getPartialApplyResultType(functionRef->getType(),
430430
capturedArgs.size(), SGM.M,
431-
subs);
431+
subs,
432+
ParameterConvention::Direct_Owned);
432433
auto toClosure =
433434
B.createPartialApply(loc, functionRef, functionTy,
434435
subs, forwardedArgs, closureTy);
@@ -840,7 +841,8 @@ void SILGenFunction::emitCurryThunk(ValueDecl *vd,
840841
// Partially apply the next uncurry level and return the result closure.
841842
auto closureTy =
842843
SILGenBuilder::getPartialApplyResultType(toFn->getType(), curriedArgs.size(),
843-
SGM.M, subs);
844+
SGM.M, subs,
845+
ParameterConvention::Direct_Owned);
844846
SILInstruction *toClosure =
845847
B.createPartialApply(vd, toFn, toTy, subs, curriedArgs, closureTy);
846848
if (resultTy != closureTy)

lib/Serialization/DeserializeSIL.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,20 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
10391039
auto Ty = MF->getType(TyID);
10401040
auto Ty2 = MF->getType(TyID2);
10411041
SILType FnTy = getSILType(Ty, SILValueCategory::Object);
1042-
SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object);
1042+
SILType closureTy = getSILType(Ty2, SILValueCategory::Object);
1043+
1044+
unsigned NumSub = NumSubs;
1045+
SmallVector<Substitution, 4> Substitutions;
1046+
while (NumSub--) {
1047+
auto sub = MF->maybeReadSubstitution(SILCursor);
1048+
assert(sub.hasValue() && "missing substitution");
1049+
Substitutions.push_back(*sub);
1050+
}
1051+
1052+
auto SubstFnTy = SILType::getPrimitiveObjectType(
1053+
FnTy.castTo<SILFunctionType>()
1054+
->substGenericArgs(Builder.getModule(),
1055+
Builder.getModule().getSwiftModule(), Substitutions));
10431056
SILFunctionType *FTI = SubstFnTy.castTo<SILFunctionType>();
10441057
auto ArgTys = FTI->getParameterSILTypes();
10451058

@@ -1052,22 +1065,6 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
10521065
for (unsigned I = 0, E = ListOfValues.size(); I < E; I++)
10531066
Args.push_back(getLocalValue(ListOfValues[I], ArgTys[I + unappliedArgs]));
10541067

1055-
// Compute the result type of the partial_apply, based on which arguments
1056-
// are getting applied.
1057-
SILType closureTy
1058-
= SILBuilder::getPartialApplyResultType(SubstFnTy,
1059-
Args.size(),
1060-
Fn->getModule(),
1061-
{});
1062-
1063-
unsigned NumSub = NumSubs;
1064-
SmallVector<Substitution, 4> Substitutions;
1065-
while (NumSub--) {
1066-
auto sub = MF->maybeReadSubstitution(SILCursor);
1067-
assert(sub.hasValue() && "missing substitution");
1068-
Substitutions.push_back(*sub);
1069-
}
1070-
10711068
// FIXME: Why the arbitrary order difference in IRBuilder type argument?
10721069
ResultVal = Builder.createPartialApply(Loc, FnVal, SubstFnTy,
10731070
Substitutions, Args,

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
792792
SILAbbrCodes[SILInstApplyLayout::Code], SIL_PARTIAL_APPLY,
793793
PAI->getSubstitutions().size(),
794794
S.addTypeRef(PAI->getCallee()->getType().getSwiftRValueType()),
795-
S.addTypeRef(PAI->getSubstCalleeType()),
795+
S.addTypeRef(PAI->getType().getSwiftRValueType()),
796796
addValueRef(PAI->getCallee()),
797797
Args);
798798
S.writeSubstitutions(PAI->getSubstitutions(), SILAbbrCodes);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend -emit-sil %s | %FileCheck %s
2+
3+
import Builtin
4+
5+
sil_stage canonical
6+
7+
sil @subject : $@convention(thin) (Builtin.Int64) -> ()
8+
9+
// CHECK-LABEL: sil @partial_apply_callee_owned_by_default : $@convention(thin) () -> @callee_owned () -> () {
10+
sil @partial_apply_callee_owned_by_default : $@convention(thin) () -> @callee_owned () -> () {
11+
entry:
12+
%f = function_ref @subject : $@convention(thin) (Builtin.Int64) -> ()
13+
%z = integer_literal $Builtin.Int64, 0
14+
// CHECK: [[PA:%.*]] = partial_apply {{.*}} $@convention(thin) (Builtin.Int64) -> ()
15+
%g = partial_apply %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
16+
// CHECK: return [[PA]] : $@callee_owned () -> ()
17+
return %g : $@callee_owned () -> ()
18+
}
19+
20+
// CHECK-LABEL: sil @partial_apply_callee_guaranteed_by_attr : $@convention(thin) () -> @callee_guaranteed () -> () {
21+
sil @partial_apply_callee_guaranteed_by_attr : $@convention(thin) () -> @callee_guaranteed () -> () {
22+
entry:
23+
%f = function_ref @subject : $@convention(thin) (Builtin.Int64) -> ()
24+
%z = integer_literal $Builtin.Int64, 0
25+
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] {{.*}} $@convention(thin) (Builtin.Int64) -> ()
26+
%g = partial_apply [callee_guaranteed] %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
27+
// CHECK: return [[PA]] : $@callee_guaranteed () -> ()
28+
return %g : $@callee_guaranteed () -> ()
29+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir %t
3+
// RUN: %target-build-swift -emit-module -Xfrontend -disable-diagnostic-passes -Xfrontend -sil-serialize-all -force-single-frontend-invocation -o %t/sil_partial_apply_ownership.swiftmodule %s
4+
// RUN: %target-build-swift -emit-sil -Xfrontend -sil-link-all -I %t %s | %FileCheck %s
5+
6+
import Builtin
7+
8+
sil_stage canonical
9+
10+
sil @subject : $@convention(thin) (Builtin.Int64) -> ()
11+
sil @generic_subject : $@convention(thin) <T> (@in T, @in T) -> ()
12+
13+
// CHECK-LABEL: sil @partial_apply_callee_owned_by_default : $@convention(thin) () -> @callee_owned () -> () {
14+
sil @partial_apply_callee_owned_by_default : $@convention(thin) () -> @callee_owned () -> () {
15+
entry:
16+
%f = function_ref @subject : $@convention(thin) (Builtin.Int64) -> ()
17+
%z = integer_literal $Builtin.Int64, 0
18+
// CHECK: [[PA:%.*]] = partial_apply {{.*}} $@convention(thin) (Builtin.Int64) -> ()
19+
%g = partial_apply %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
20+
// CHECK: return [[PA]] : $@callee_owned () -> ()
21+
return %g : $@callee_owned () -> ()
22+
}
23+
24+
// CHECK-LABEL: sil @partial_apply_callee_guaranteed_by_attr : $@convention(thin) () -> @callee_guaranteed () -> () {
25+
sil @partial_apply_callee_guaranteed_by_attr : $@convention(thin) () -> @callee_guaranteed () -> () {
26+
entry:
27+
%f = function_ref @subject : $@convention(thin) (Builtin.Int64) -> ()
28+
%z = integer_literal $Builtin.Int64, 0
29+
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] {{.*}} $@convention(thin) (Builtin.Int64) -> ()
30+
%g = partial_apply [callee_guaranteed] %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
31+
// CHECK: return [[PA]] : $@callee_guaranteed () -> ()
32+
return %g : $@callee_guaranteed () -> ()
33+
}
34+
35+
sil @partial_apply_generic : $@convention(thin) () -> @callee_owned (@in Builtin.Int64) -> () {
36+
entry:
37+
%f = function_ref @generic_subject : $@convention(thin) <T> (@in T, @in T) -> ()
38+
%z = integer_literal $Builtin.Int64, 0
39+
%s = alloc_stack $Builtin.Int64
40+
store %z to %s : $*Builtin.Int64
41+
// CHECK: [[PA:%.*]] = partial_apply {{.*}}<Builtin.Int64>({{.*}}) : $@convention(thin)
42+
%g = partial_apply %f<Builtin.Int64>(%s) : $@convention(thin) <T> (@in T, @in T) -> ()
43+
dealloc_stack %s : $*Builtin.Int64
44+
return %g : $@callee_owned (@in Builtin.Int64) -> ()
45+
}

0 commit comments

Comments
 (0)