Skip to content

Commit 599e169

Browse files
committed
[SILGen] InitAccessors: Produce partial apply of init accessor ref to produce substituted closure
Instead of dealing with substitutions during raw SIL lowering, let's produce a partial apply without argument to produce a substituted reference that could be used by SILVerifier and raw SIL lowering stages. (cherry picked from commit 80a1e2c)
1 parent 659adf3 commit 599e169

File tree

6 files changed

+60
-29
lines changed

6 files changed

+60
-29
lines changed

lib/SIL/IR/SILInstructions.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,10 +1284,17 @@ bool AssignOrInitInst::isPropertyAlreadyInitialized(unsigned propertyIdx) {
12841284
}
12851285

12861286
AccessorDecl *AssignOrInitInst::getReferencedInitAccessor() const {
1287-
auto *initRef = cast<FunctionRefInst>(getInitializer());
1288-
auto *accessorRef = initRef->getReferencedFunctionOrNull();
1289-
assert(accessorRef);
1290-
return dyn_cast_or_null<AccessorDecl>(accessorRef->getDeclContext());
1287+
SILValue initRef = getInitializer();
1288+
SILFunction *accessorFn = nullptr;
1289+
1290+
if (auto *PAI = dyn_cast<PartialApplyInst>(initRef)) {
1291+
accessorFn = PAI->getReferencedFunctionOrNull();
1292+
} else {
1293+
accessorFn = cast<FunctionRefInst>(initRef)->getReferencedFunctionOrNull();
1294+
}
1295+
1296+
assert(accessorFn);
1297+
return dyn_cast_or_null<AccessorDecl>(accessorFn->getDeclContext());
12911298
}
12921299

12931300
unsigned AssignOrInitInst::getNumInitializedProperties() const {

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,17 +2727,12 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
27272727
SILValue initFn = AI->getInitializer();
27282728
SILValue setterFn = AI->getSetter();
27292729

2730-
CanSILFunctionType initTy = initFn->getType().castTo<SILFunctionType>();
27312730
// Check init - it's an unapplied reference that takes property addresses
27322731
// and `initialValue`.
27332732
{
2734-
// We need to map un-applied function reference into context before
2735-
// check `initialValue` argument.
2736-
auto subs = cast<PartialApplyInst>(setterFn)->getSubstitutionMap();
2737-
initTy = initTy->substGenericArgs(F.getModule(), subs,
2738-
F.getTypeExpansionContext());
2739-
2733+
CanSILFunctionType initTy = initFn->getType().castTo<SILFunctionType>();
27402734
SILFunctionConventions initConv(initTy, AI->getModule());
2735+
27412736
require(initConv.getNumIndirectSILResults() ==
27422737
AI->getInitializedProperties().size(),
27432738
"init function has invalid number of indirect results");

lib/SILGen/SILGenLValue.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,25 @@ namespace {
16181618
SGF.getTypeExpansionContext());
16191619
};
16201620

1621+
auto emitPartialInitAccessorApply =
1622+
[&](AccessorDecl *initAccessor) -> SILValue {
1623+
assert(initAccessor->isInitAccessor());
1624+
auto initConstant = SGF.getAccessorDeclRef(initAccessor);
1625+
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1626+
1627+
// If there are no substitutions there is no need to emit partial
1628+
// apply.
1629+
if (Substitutions.empty())
1630+
return initFRef;
1631+
1632+
// Emit partial apply without argument to produce a substituted
1633+
// init accessor reference.
1634+
PartialApplyInst *initPAI = SGF.B.createPartialApply(
1635+
loc, initFRef, Substitutions, ArrayRef<SILValue>(),
1636+
ParameterConvention::Direct_Guaranteed);
1637+
return SGF.emitManagedRValueWithCleanup(initPAI).getValue();
1638+
};
1639+
16211640
auto emitPartialSetterApply =
16221641
[&](SILValue setterFRef,
16231642
const SILFunctionConventions &setterConv) -> ManagedValue {
@@ -1707,9 +1726,8 @@ namespace {
17071726
}
17081727

17091728
// Emit the init accessor function partially applied to the base.
1710-
auto *initAccessor = field->getOpaqueAccessor(AccessorKind::Init);
1711-
auto initConstant = SGF.getAccessorDeclRef(initAccessor);
1712-
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1729+
auto initFn = emitPartialInitAccessorApply(
1730+
field->getOpaqueAccessor(AccessorKind::Init));
17131731

17141732
// Emit the set accessor function partially applied to the base.
17151733
auto setterFRef = getSetterFRef();
@@ -1720,7 +1738,7 @@ namespace {
17201738
// Create the assign_or_init with the initializer and setter.
17211739
auto value = emitValue(field, FieldType, setterTy, setterConv);
17221740
SGF.B.createAssignOrInit(loc, base.getValue(), value.forward(SGF),
1723-
initFRef, setterFn.getValue(),
1741+
initFn, setterFn.getValue(),
17241742
AssignOrInitInst::Unknown);
17251743
return;
17261744
}

lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,6 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
284284
CanSILFunctionType fTy = initFn->getType().castTo<SILFunctionType>();
285285
SILFunctionConventions convention(fTy, inst->getModule());
286286

287-
auto *setterPA = dyn_cast<PartialApplyInst>(inst->getSetter());
288-
assert(setterPA);
289-
290287
auto selfValue = inst->getSelf();
291288
auto isRefSelf = selfValue->getType().getASTType()->mayHaveSuperclass();
292289

@@ -337,18 +334,21 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
337334
for (auto *property : inst->getAccessedProperties())
338335
arguments.push_back(emitFieldReference(property));
339336

340-
b.createApply(loc, initFn, setterPA->getSubstitutionMap(), arguments);
337+
b.createApply(loc, initFn, SubstitutionMap(), arguments);
341338

342339
if (isRefSelf) {
343340
b.emitEndBorrowOperation(loc, selfRef);
344341
} else {
345342
b.createEndAccess(loc, selfRef, /*aborted=*/false);
346343
}
347344

345+
auto *setterPA = dyn_cast<PartialApplyInst>(inst->getSetter());
346+
assert(setterPA);
347+
348348
// The unused partial_apply violates memory lifetime rules in case "self"
349349
// is an inout. Therefore we cannot keep it as a dead closure to be
350350
// cleaned up later. We have to delete it in this pass.
351-
toDelete.insert(inst->getSetter());
351+
toDelete.insert(setterPA);
352352

353353
// Also the argument of the closure (which usually is a "load") has to be
354354
// deleted to avoid memory lifetime violations.

test/SILOptimizer/init_accessor_raw_sil_lowering.swift

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@ struct Test1 {
2727

2828
// CHECK-LABEL: sil hidden [ossa] @$s23assign_or_init_lowering5Test1V1aACSi_tcfC : $@convention(method) (Int, @thin Test1.Type) -> @owned Test1
2929
init(a: Int) {
30-
// CHECK: assign_or_init [init] self {{.*}}, value [[VALUE:%.*]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
30+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering5Test1V1aSivi : $@convention(thin) (Int) -> @out Int
31+
// CHECK: assign_or_init [init] self {{.*}}, value [[VALUE:%.*]] : $Int, init [[INIT_REF]] : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
3132
self.a = a
32-
// CHECK: assign_or_init [init] [assign=0] self {{.*}}, value [[VALUE:%.*]] : $String, init {{.*}} : $@convention(thin) (@owned String) -> (@out Int, @out String), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
33+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering5Test1V1bSSvi : $@convention(thin) (@owned String) -> (@out Int, @out String)
34+
// CHECK: assign_or_init [init] [assign=0] self {{.*}}, value [[VALUE:%.*]] : $String, init [[INIT_REF]] : $@convention(thin) (@owned String) -> (@out Int, @out String), set {{.*}} : $@callee_guaranteed (@owned String) -> ()
3335
self.a = -1
3436
self.b = ""
35-
// CHECK: assign_or_init [set] self {{.*}}, value [[VALUE:%.*]] : $Int, init {{.*}} : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
37+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering5Test1V1aSivi : $@convention(thin) (Int) -> @out Int
38+
// CHECK: assign_or_init [set] self {{.*}}, value [[VALUE:%.*]] : $Int, init [[INIT_REF]] : $@convention(thin) (Int) -> @out Int, set {{.*}} : $@callee_guaranteed (Int) -> ()
3639
self.a = a
3740
}
3841
}
@@ -54,12 +57,18 @@ struct Test2<T> {
5457

5558
// CHECK-LABEL: sil hidden [ossa] @$s23assign_or_init_lowering5Test2V1a1bACyxGSi_xtcfC : $@convention(method) <T> (Int, @in T, @thin Test2<T>.Type) -> @out Test2<T>
5659
init(a: Int, b: T) {
57-
// CHECK: assign_or_init [init] self {{.*}}, value [[VALUE:%.*]] : $*(Int, T), init {{.*}} : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0), set {{.*}} : $@callee_guaranteed (Int, @in T) -> ()
60+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering5Test2V4pairSi_xtvi : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0)
61+
// CHECK-NEXT: [[SUBST_INIT_REF:%.*]] = partial_apply [callee_guaranteed] [[INIT_REF]]<T>() : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0)
62+
// CHECK: assign_or_init [init] self {{.*}}, value [[VALUE:%.*]] : $*(Int, T), init [[SUBST_INIT_REF]] : $@callee_guaranteed (Int, @in T) -> (@out Int, @out T), set {{.*}} : $@callee_guaranteed (Int, @in T) -> ()
5863
self.pair = (a, b)
59-
// CHECK: assign_or_init [init] [assign=0] [assign=1] self {{.*}}, value [[VALUE:%.*]] : $*(Int, T), init {{.*}} : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0), set {{.*}} : $@callee_guaranteed (Int, @in T) -> ()
64+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering5Test2V4pairSi_xtvi : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0)
65+
// CHECK-NEXT: [[SUBST_INIT_REF:%.*]] = partial_apply [callee_guaranteed] [[INIT_REF]]<T>() : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0)
66+
// CHECK: assign_or_init [init] [assign=0] [assign=1] self {{.*}}, value [[VALUE:%.*]] : $*(Int, T), init [[SUBST_INIT_REF]] : $@callee_guaranteed (Int, @in T) -> (@out Int, @out T), set {{.*}} : $@callee_guaranteed (Int, @in T) -> ()
6067
self.pair = (0, b)
6168
self._c = ""
62-
// CHECK: assign_or_init [set] self {{.*}}, value [[VALUE:%.*]] : $*(Int, T), init {{.*}} : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0), set {{.*}} : $@callee_guaranteed (Int, @in T) -> ()
69+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering5Test2V4pairSi_xtvi : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0)
70+
// CHECK-NEXT: [[SUBST_INIT_REF:%.*]] = partial_apply [callee_guaranteed] [[INIT_REF]]<T>() : $@convention(thin) <τ_0_0> (Int, @in τ_0_0) -> (@out Int, @out τ_0_0)
71+
// CHECK: assign_or_init [set] self {{.*}}, value [[VALUE:%.*]] : $*(Int, T), init [[SUBST_INIT_REF]] : $@callee_guaranteed (Int, @in T) -> (@out Int, @out T), set {{.*}} : $@callee_guaranteed (Int, @in T) -> ()
6372
self.pair = (1, b)
6473
}
6574
}
@@ -75,7 +84,8 @@ struct Test {
7584

7685
// CHECK-LABEL: sil hidden [ossa] @$s23assign_or_init_lowering4TestV1vACSi_tcfC : $@convention(method) (Int, @thin Test.Type) -> Test
7786
init(v: Int) {
78-
// CHECK: assign_or_init [set] self {{.*}}, value %0 : $Int, init {{.*}} : $@convention(thin) (Int) -> (), set {{.*}} : $@callee_guaranteed (Int) -> ()
87+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s23assign_or_init_lowering4TestV4testSivi : $@convention(thin) (Int) -> ()
88+
// CHECK: assign_or_init [set] self {{.*}}, value %0 : $Int, init [[INIT_REF]] : $@convention(thin) (Int) -> (), set {{.*}} : $@callee_guaranteed (Int) -> ()
7989
self.test = v
8090
}
8191
}

test/SILOptimizer/init_accessors.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,12 @@ struct TestGeneric<T, U> {
293293
// CHECK-LABEL: sil hidden [ossa] @$s14init_accessors11TestGenericV1a1b1cACyxq_Gx_xq_tcfC : $@convention(method) <T, U> (@in T, @in T, @in U, @thin TestGeneric<T, U>.Type) -> @out TestGeneric<T, U>
294294
//
295295
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s14init_accessors11TestGenericV4datax_xtvi : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout τ_0_1) -> (@out τ_0_0, @out τ_0_0)
296-
// CHECK: {{.*}} = apply [[INIT_ACCESSOR]]<T, U>({{.*}}) : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout τ_0_1) -> (@out τ_0_0, @out τ_0_0)
296+
// CHECK-NEXT: [[SUBST_INIT_ACCESSOR:%.*]] = partial_apply [callee_guaranteed] [[INIT_ACCESSOR]]<T, U>() : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout τ_0_1) -> (@out τ_0_0, @out τ_0_0)
297+
// CHECK: {{.*}} = apply [[SUBST_INIT_ACCESSOR]]({{.*}}) : $@callee_guaranteed (@in T, @in T, @inout U) -> (@out T, @out T)
297298
//
298299
// CHECK: [[SETTER:%.*]] = function_ref @$s14init_accessors11TestGenericV4datax_xtvs : $@convention(method) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout TestGeneric<τ_0_0, τ_0_1>) -> ()
299300
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER]]<T, U>([[SELF_VALUE:%.*]]) : $@convention(method) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout TestGeneric<τ_0_0, τ_0_1>) -> ()
300-
// CHECK: %55 = apply [[SETTER_CLOSURE]]({{.*}}) : $@callee_guaranteed (@in T, @in T) -> ()
301+
// CHECK: {{.*}} = apply [[SETTER_CLOSURE]]({{.*}}) : $@callee_guaranteed (@in T, @in T) -> ()
301302
// CHECK-NEXT: end_access [[SELF_VALUE]] : $*TestGeneric<T, U>
302303
init(a: T, b: T, c: U) {
303304
self.c = c

0 commit comments

Comments
 (0)