Skip to content

Commit 80a1e2c

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.
1 parent 3063e9d commit 80a1e2c

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
@@ -1288,10 +1288,17 @@ bool AssignOrInitInst::isPropertyAlreadyInitialized(unsigned propertyIdx) {
12881288
}
12891289

12901290
AccessorDecl *AssignOrInitInst::getReferencedInitAccessor() const {
1291-
auto *initRef = cast<FunctionRefInst>(getInitializer());
1292-
auto *accessorRef = initRef->getReferencedFunctionOrNull();
1293-
assert(accessorRef);
1294-
return dyn_cast_or_null<AccessorDecl>(accessorRef->getDeclContext());
1291+
SILValue initRef = getInitializer();
1292+
SILFunction *accessorFn = nullptr;
1293+
1294+
if (auto *PAI = dyn_cast<PartialApplyInst>(initRef)) {
1295+
accessorFn = PAI->getReferencedFunctionOrNull();
1296+
} else {
1297+
accessorFn = cast<FunctionRefInst>(initRef)->getReferencedFunctionOrNull();
1298+
}
1299+
1300+
assert(accessorFn);
1301+
return dyn_cast_or_null<AccessorDecl>(accessorFn->getDeclContext());
12951302
}
12961303

12971304
unsigned AssignOrInitInst::getNumInitializedProperties() const {

lib/SIL/Verifier/SILVerifier.cpp

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

2728-
CanSILFunctionType initTy = initFn->getType().castTo<SILFunctionType>();
27292728
// Check init - it's an unapplied reference that takes property addresses
27302729
// and `initialValue`.
27312730
{
2732-
// We need to map un-applied function reference into context before
2733-
// check `initialValue` argument.
2734-
auto subs = cast<PartialApplyInst>(setterFn)->getSubstitutionMap();
2735-
initTy = initTy->substGenericArgs(F.getModule(), subs,
2736-
F.getTypeExpansionContext());
2737-
2731+
CanSILFunctionType initTy = initFn->getType().castTo<SILFunctionType>();
27382732
SILFunctionConventions initConv(initTy, AI->getModule());
2733+
27392734
require(initConv.getNumIndirectSILResults() ==
27402735
AI->getInitializedProperties().size(),
27412736
"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
@@ -1630,6 +1630,25 @@ namespace {
16301630
SGF.getTypeExpansionContext());
16311631
};
16321632

1633+
auto emitPartialInitAccessorApply =
1634+
[&](AccessorDecl *initAccessor) -> SILValue {
1635+
assert(initAccessor->isInitAccessor());
1636+
auto initConstant = SGF.getAccessorDeclRef(initAccessor);
1637+
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1638+
1639+
// If there are no substitutions there is no need to emit partial
1640+
// apply.
1641+
if (Substitutions.empty())
1642+
return initFRef;
1643+
1644+
// Emit partial apply without argument to produce a substituted
1645+
// init accessor reference.
1646+
PartialApplyInst *initPAI = SGF.B.createPartialApply(
1647+
loc, initFRef, Substitutions, ArrayRef<SILValue>(),
1648+
ParameterConvention::Direct_Guaranteed);
1649+
return SGF.emitManagedRValueWithCleanup(initPAI).getValue();
1650+
};
1651+
16331652
auto emitPartialSetterApply =
16341653
[&](SILValue setterFRef,
16351654
const SILFunctionConventions &setterConv) -> ManagedValue {
@@ -1719,9 +1738,8 @@ namespace {
17191738
}
17201739

17211740
// Emit the init accessor function partially applied to the base.
1722-
auto *initAccessor = field->getOpaqueAccessor(AccessorKind::Init);
1723-
auto initConstant = SGF.getAccessorDeclRef(initAccessor);
1724-
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1741+
auto initFn = emitPartialInitAccessorApply(
1742+
field->getOpaqueAccessor(AccessorKind::Init));
17251743

17261744
// Emit the set accessor function partially applied to the base.
17271745
auto setterFRef = getSetterFRef();
@@ -1732,7 +1750,7 @@ namespace {
17321750
// Create the assign_or_init with the initializer and setter.
17331751
auto value = emitValue(field, FieldType, setterTy, setterConv);
17341752
SGF.B.createAssignOrInit(loc, base.getValue(), value.forward(SGF),
1735-
initFRef, setterFn.getValue(),
1753+
initFn, setterFn.getValue(),
17361754
AssignOrInitInst::Unknown);
17371755
return;
17381756
}

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)