Skip to content

Commit a851476

Browse files
authored
Merge pull request #12454 from slavapestov/di-self-consumed-analysis-volume-2
DI: self-consumed analysis rework, volume 2
2 parents 4b2f008 + 196559e commit a851476

14 files changed

+1550
-603
lines changed

lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp

Lines changed: 74 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -426,52 +426,8 @@ bool DIMemoryUse::onlyTouchesTrivialElements(
426426
// DIElementUseInfo Implementation
427427
//===----------------------------------------------------------------------===//
428428

429-
void DIElementUseInfo::trackFailableInitCall(
430-
const DIMemoryObjectInfo &MemoryInfo, SILInstruction *I) {
431-
// If we have a store to self inside the normal BB, we have a 'real'
432-
// try_apply. Otherwise, this is a 'try? self.init()' or similar,
433-
// and there is a store after.
434-
if (auto *TAI = dyn_cast<TryApplyInst>(I)) {
435-
trackFailureBlock(MemoryInfo, TAI, TAI->getNormalBB());
436-
return;
437-
}
438-
439-
if (auto *AI = dyn_cast<ApplyInst>(I)) {
440-
// See if this is an optional initializer.
441-
for (auto Op : AI->getUses()) {
442-
SILInstruction *User = Op->getUser();
443-
444-
if (!isa<SelectEnumInst>(User) && !isa<SelectEnumAddrInst>(User))
445-
continue;
446-
447-
auto value = cast<SingleValueInstruction>(User);
448-
449-
if (!value->hasOneUse())
450-
continue;
451-
452-
User = value->use_begin()->getUser();
453-
if (auto *CBI = dyn_cast<CondBranchInst>(User)) {
454-
trackFailureBlock(MemoryInfo, CBI, CBI->getTrueBB());
455-
return;
456-
}
457-
}
458-
}
459-
}
460-
461-
/// We have to detect if the self box contents were consumed. Do this by
462-
/// checking for a store into the self box in the success branch. Once we rip
463-
/// this out of SILGen, DI will be able to figure this out in a more logical
464-
/// manner.
465-
void DIElementUseInfo::trackFailureBlock(const DIMemoryObjectInfo &TheMemory,
466-
TermInst *TI, SILBasicBlock *BB) {
467-
for (auto &II : *BB) {
468-
if (auto *SI = dyn_cast<StoreInst>(&II)) {
469-
if (SI->getDest() == TheMemory.MemoryInst) {
470-
FailableInits.push_back(TI);
471-
return;
472-
}
473-
}
474-
}
429+
void DIElementUseInfo::trackStoreToSelf(SILInstruction *I) {
430+
StoresToSelf.push_back(I);
475431
}
476432

477433
//===----------------------------------------------------------------------===//
@@ -1103,10 +1059,14 @@ void ElementUseCollector::collectClassSelfUses() {
11031059
return;
11041060
}
11051061

1062+
// The number of stores of the initial 'self' argument into the self box
1063+
// that we saw.
1064+
unsigned StoresOfArgumentToSelf = 0;
1065+
11061066
// Okay, given that we have a proper setup, we walk the use chains of the self
11071067
// box to find any accesses to it. The possible uses are one of:
11081068
//
1109-
// 1) The initialization store (TheStore).
1069+
// 1) The initialization store.
11101070
// 2) Loads of the box, which have uses of self hanging off of them.
11111071
// 3) An assign to the box, which happens at super.init.
11121072
// 4) Potential escapes after super.init, if self is closed over.
@@ -1115,10 +1075,29 @@ void ElementUseCollector::collectClassSelfUses() {
11151075
for (auto *Op : MUI->getUses()) {
11161076
SILInstruction *User = Op->getUser();
11171077

1118-
// Stores to self are initializations store or the rebind of self as
1119-
// part of the super.init call. Ignore both of these.
1120-
if (isa<StoreInst>(User) && Op->getOperandNumber() == 1)
1121-
continue;
1078+
// Stores to self.
1079+
if (auto *SI = dyn_cast<StoreInst>(User)) {
1080+
if (Op->getOperandNumber() == 1) {
1081+
// The initial store of 'self' into the box at the start of the
1082+
// function. Ignore it.
1083+
if (auto *Arg = dyn_cast<SILArgument>(SI->getSrc())) {
1084+
if (Arg->getParent() == MUI->getParent()) {
1085+
StoresOfArgumentToSelf++;
1086+
continue;
1087+
}
1088+
}
1089+
1090+
// A store of a load from the box is ignored.
1091+
// FIXME: SILGen should not emit these.
1092+
if (auto *LI = dyn_cast<LoadInst>(SI->getSrc()))
1093+
if (LI->getOperand() == MUI)
1094+
continue;
1095+
1096+
// Any other store needs to be recorded.
1097+
UseInfo.trackStoreToSelf(SI);
1098+
continue;
1099+
}
1100+
}
11221101

11231102
// Ignore end_borrows. These can only come from us being the source of a
11241103
// load_borrow.
@@ -1149,6 +1128,9 @@ void ElementUseCollector::collectClassSelfUses() {
11491128
// and super.init must be called.
11501129
trackUse(DIMemoryUse(User, DIUseKind::Load, 0, TheMemory.NumElements));
11511130
}
1131+
1132+
assert(StoresOfArgumentToSelf == 1 &&
1133+
"The 'self' argument should have been stored into the box exactly once");
11521134
}
11531135

11541136
static bool isSuperInitUse(SILInstruction *User) {
@@ -1406,7 +1388,6 @@ void ElementUseCollector::collectClassSelfUses(
14061388
(isSelfInitUse(User) || isSuperInitUse(User))) {
14071389
if (isSelfOperand(Op, User)) {
14081390
Kind = DIUseKind::SelfInit;
1409-
UseInfo.trackFailableInitCall(TheMemory, User);
14101391
}
14111392
}
14121393

@@ -1459,6 +1440,10 @@ void DelegatingInitElementUseCollector::collectClassInitSelfUses() {
14591440
assert(TheMemory.NumElements == 1 && "delegating inits only have 1 bit");
14601441
auto *MUI = cast<MarkUninitializedInst>(TheMemory.MemoryInst);
14611442

1443+
// The number of stores of the initial 'self' argument into the self box
1444+
// that we saw.
1445+
unsigned StoresOfArgumentToSelf = 0;
1446+
14621447
// We walk the use chains of the self MUI to find any accesses to it. The
14631448
// possible uses are:
14641449
// 1) The initialization store.
@@ -1475,14 +1460,33 @@ void DelegatingInitElementUseCollector::collectClassInitSelfUses() {
14751460
if (isa<EndBorrowInst>(User))
14761461
continue;
14771462

1478-
// Stores to self are initializations store or the rebind of self as
1479-
// part of the super.init call. Ignore both of these.
1480-
if (isa<StoreInst>(User) && Op->getOperandNumber() == 1)
1481-
continue;
1463+
// Stores to self.
1464+
if (auto *SI = dyn_cast<StoreInst>(User)) {
1465+
if (Op->getOperandNumber() == 1) {
1466+
// The initial store of 'self' into the box at the start of the
1467+
// function. Ignore it.
1468+
if (auto *Arg = dyn_cast<SILArgument>(SI->getSrc())) {
1469+
if (Arg->getParent() == MUI->getParent()) {
1470+
StoresOfArgumentToSelf++;
1471+
continue;
1472+
}
1473+
}
1474+
1475+
// A store of a load from the box is ignored.
1476+
// FIXME: SILGen should not emit these.
1477+
if (auto *LI = dyn_cast<LoadInst>(SI->getSrc()))
1478+
if (LI->getOperand() == MUI)
1479+
continue;
1480+
1481+
// Any other store needs to be recorded.
1482+
UseInfo.trackStoreToSelf(SI);
1483+
continue;
1484+
}
1485+
}
14821486

14831487
// For class initializers, the assign into the self box may be
14841488
// captured as SelfInit or SuperInit elsewhere.
1485-
if (TheMemory.isClassInitSelf() && isa<AssignInst>(User) &&
1489+
if (isa<AssignInst>(User) &&
14861490
Op->getOperandNumber() == 1) {
14871491
// If the source of the assignment is an application of a C
14881492
// function, there is no metatype argument, so treat the
@@ -1491,6 +1495,7 @@ void DelegatingInitElementUseCollector::collectClassInitSelfUses() {
14911495
if (auto *Fn = AI->getCalleeFunction()) {
14921496
if (Fn->getRepresentation() ==
14931497
SILFunctionTypeRepresentation::CFunctionPointer) {
1498+
UseInfo.trackStoreToSelf(User);
14941499
UseInfo.trackUse(DIMemoryUse(User, DIUseKind::SelfInit, 0, 1));
14951500
continue;
14961501
}
@@ -1503,13 +1508,15 @@ void DelegatingInitElementUseCollector::collectClassInitSelfUses() {
15031508
if (auto *AI = dyn_cast<AssignInst>(User)) {
15041509
if (auto *AssignSource = AI->getOperand(0)->getDefiningInstruction()) {
15051510
if (isSelfInitUse(AssignSource) || isSuperInitUse(AssignSource)) {
1511+
UseInfo.trackStoreToSelf(User);
15061512
UseInfo.trackUse(DIMemoryUse(User, DIUseKind::SelfInit, 0, 1));
15071513
continue;
15081514
}
15091515
}
15101516
if (auto *AssignSource = dyn_cast<SILArgument>(AI->getOperand(0))) {
15111517
if (AssignSource->getParent() == AI->getParent() &&
15121518
(isSelfInitUse(AssignSource) || isSuperInitUse(AssignSource))) {
1519+
UseInfo.trackStoreToSelf(User);
15131520
UseInfo.trackUse(DIMemoryUse(User, DIUseKind::SelfInit, 0, 1));
15141521
continue;
15151522
}
@@ -1534,6 +1541,9 @@ void DelegatingInitElementUseCollector::collectClassInitSelfUses() {
15341541
UseInfo.trackUse(DIMemoryUse(User, DIUseKind::Escape, 0, 1));
15351542
}
15361543

1544+
assert(StoresOfArgumentToSelf == 1 &&
1545+
"The 'self' argument should have been stored into the box exactly once");
1546+
15371547
// The MUI must be used on an alloc_box or alloc_stack instruction. If we have
15381548
// an alloc_stack, there is nothing further to do.
15391549
if (isa<AllocStackInst>(MUI->getOperand()))
@@ -1573,13 +1583,17 @@ void DelegatingInitElementUseCollector::collectValueTypeInitSelfUses(
15731583
// Stores *to* the allocation are writes. If the value being stored is a
15741584
// call to self.init()... then we have a self.init call.
15751585
if (auto *AI = dyn_cast<AssignInst>(User)) {
1576-
if (AI->getDest() == I)
1586+
if (AI->getDest() == I) {
1587+
UseInfo.trackStoreToSelf(AI);
15771588
Kind = DIUseKind::InitOrAssign;
1589+
}
15781590
}
15791591

15801592
if (auto *CAI = dyn_cast<CopyAddrInst>(User)) {
1581-
if (CAI->getDest() == I)
1593+
if (CAI->getDest() == I) {
1594+
UseInfo.trackStoreToSelf(CAI);
15821595
Kind = DIUseKind::InitOrAssign;
1596+
}
15831597
}
15841598

15851599
// Look through begin_access
@@ -1665,7 +1679,6 @@ void DelegatingInitElementUseCollector::collectDelegatingClassInitSelfLoadUses(
16651679
(isSelfInitUse(User) || isSuperInitUse(User))) {
16661680
if (isSelfOperand(Op, User)) {
16671681
Kind = DIUseKind::SelfInit;
1668-
UseInfo.trackFailableInitCall(TheMemory, User);
16691682
}
16701683
}
16711684

@@ -1701,7 +1714,7 @@ void swift::ownership::collectDIElementUsesFrom(
17011714
// collector.
17021715
if (MemoryInfo.isDelegatingInit()) {
17031716
DelegatingInitElementUseCollector UseCollector(MemoryInfo, UseInfo);
1704-
if (MemoryInfo.getType()->hasReferenceSemantics()) {
1717+
if (MemoryInfo.isClassInitSelf()) {
17051718
UseCollector.collectClassInitSelfUses();
17061719
} else {
17071720
UseCollector.collectValueTypeInitSelfUses();

lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ class DIMemoryObjectInfo {
150150
return false;
151151
}
152152

153+
/// True if this memory object is the 'self' of a non-root class init method.
154+
bool isNonRootClassSelf() const {
155+
if (isClassInitSelf())
156+
if (auto MUI = dyn_cast<MarkUninitializedInst>(MemoryInst))
157+
return !MUI->isRootSelf();
158+
159+
return false;
160+
}
161+
153162
/// isDelegatingInit - True if this is a delegating initializer, one that
154163
/// calls 'self.init'.
155164
bool isDelegatingInit() const {
@@ -269,18 +278,13 @@ struct DIMemoryUse {
269278
struct DIElementUseInfo {
270279
SmallVector<DIMemoryUse, 16> Uses;
271280
SmallVector<SILInstruction *, 4> Releases;
272-
TinyPtrVector<TermInst *> FailableInits;
281+
TinyPtrVector<SILInstruction *> StoresToSelf;
273282

274283
void trackUse(DIMemoryUse Use) { Uses.push_back(Use); }
275284

276285
void trackDestroy(SILInstruction *Destroy) { Releases.push_back(Destroy); }
277286

278-
void trackFailableInitCall(const DIMemoryObjectInfo &TheMemory,
279-
SILInstruction *I);
280-
281-
private:
282-
void trackFailureBlock(const DIMemoryObjectInfo &TheMemory, TermInst *TI,
283-
SILBasicBlock *BB);
287+
void trackStoreToSelf(SILInstruction *I);
284288
};
285289

286290
/// collectDIElementUsesFrom - Analyze all uses of the specified allocation

0 commit comments

Comments
 (0)