Skip to content

Commit 8391805

Browse files
committed
[move-only][borrow2destructure] Split cleanup code into the borrow specific cleanup and inserting compensating destroys.
1 parent b244df0 commit 8391805

File tree

2 files changed

+83
-75
lines changed

2 files changed

+83
-75
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructure.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ class BorrowToDestructureTransform {
6363
SmallVector<Operand *, 8> destructureNeedingUses;
6464
PostOrderAnalysis *poa;
6565
PostOrderFunctionInfo *pofi = nullptr;
66-
SILValue initialValue;
6766
SmallVector<SILInstruction *, 8> createdDestructures;
6867
SmallVector<SILPhiArgument *, 8> createdPhiArguments;
6968

@@ -92,10 +91,6 @@ class BorrowToDestructureTransform {
9291
pofi = poa->get(mmci->getFunction());
9392
return pofi;
9493
}
95-
96-
/// After we have rewritten uses, cleanup the IR by deleting the original
97-
/// borrow/struct_extract/copies and inserting compensating destroy_values.
98-
void cleanup(StackList<BeginBorrowInst *> &borrowWorklist);
9994
};
10095

10196
} // namespace siloptimizer

lib/SILOptimizer/Mandatory/MoveOnlyBorrowToDestructureTransform.cpp

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,53 @@ static SILLocation getSafeLoc(SILInstruction *inst) {
6060
return inst->getLoc();
6161
}
6262

63+
static void addCompensatingDestroys(SSAPrunedLiveness &liveness,
64+
PrunedLivenessBoundary &boundary,
65+
SILValue value) {
66+
InstructionSet consumingInsts(value->getFunction());
67+
liveness.initializeDef(value);
68+
for (auto *use : value->getUses()) {
69+
if (use->isConsuming())
70+
consumingInsts.insert(use->getUser());
71+
liveness.updateForUse(use->getUser(), use->isConsuming());
72+
if (auto *bbi = dyn_cast<BeginBorrowInst>(use->getUser())) {
73+
for (auto *ebi : bbi->getEndBorrows()) {
74+
liveness.updateForUse(ebi, false /*use is consuming*/);
75+
}
76+
}
77+
}
78+
liveness.computeBoundary(boundary);
79+
for (auto *user : boundary.lastUsers) {
80+
// If this is a consuming inst, just continue.
81+
if (consumingInsts.contains(user))
82+
continue;
83+
// Otherwise, we need to insert a destroy_value afterwards.
84+
auto *next = user->getNextInstruction();
85+
SILBuilderWithScope builder(next);
86+
builder.createDestroyValue(getSafeLoc(next), value);
87+
}
88+
89+
// Insert destroy_value along all boundary edges.
90+
for (auto *edge : boundary.boundaryEdges) {
91+
SILBuilderWithScope builder(edge->begin());
92+
builder.createDestroyValue(getSafeLoc(&*edge->begin()), value);
93+
}
94+
95+
// If we have a dead def, insert the destroy_value immediately at the def.
96+
for (auto *deadDef : boundary.deadDefs) {
97+
SILInstruction *nextInst = nullptr;
98+
if (auto *inst = dyn_cast<SILInstruction>(deadDef)) {
99+
nextInst = inst->getNextInstruction();
100+
} else if (auto *arg = dyn_cast<SILArgument>(deadDef)) {
101+
nextInst = arg->getNextInstruction();
102+
} else {
103+
llvm_unreachable("Unhandled dead def?!");
104+
}
105+
SILBuilderWithScope builder(nextInst);
106+
builder.createDestroyValue(getSafeLoc(nextInst), value);
107+
}
108+
}
109+
63110
//===----------------------------------------------------------------------===//
64111
// MARK: Available Values
65112
//===----------------------------------------------------------------------===//
@@ -137,15 +184,26 @@ struct borrowtodestructure::Implementation {
137184

138185
Optional<AvailableValueStore> blockToAvailableValues;
139186

140-
// Temporarily optional as this code is refactored.
187+
/// The liveness that we use for all borrows or for individual switch_enum
188+
/// arguments.
141189
FieldSensitiveSSAPrunedLiveRange liveness;
142190

191+
/// The copy_value we insert upon our mark_must_check or switch_enum argument
192+
/// so that we have an independent owned value.
193+
SILValue initialValue;
194+
143195
Implementation(BorrowToDestructureTransform &interface,
144196
SmallVectorImpl<SILBasicBlock *> &discoveredBlocks)
145197
: interface(interface),
146198
liveness(interface.mmci->getFunction(), &discoveredBlocks) {}
147199

200+
void clear() {
201+
liveness.clear();
202+
initialValue = SILValue();
203+
}
204+
148205
void init(SILValue rootAddress) {
206+
clear();
149207
liveness.init(rootAddress);
150208
liveness.initializeDef(rootAddress, TypeTreeLeafTypeRange(rootAddress));
151209
}
@@ -166,6 +224,8 @@ struct borrowtodestructure::Implementation {
166224
/// destructures as appropriate.
167225
void rewriteUses();
168226

227+
void cleanup();
228+
169229
AvailableValues &computeAvailableValues(SILBasicBlock *block);
170230

171231
/// Returns mark_must_check if we are processing borrows or the enum argument
@@ -741,7 +801,7 @@ AvailableValues &Implementation::computeAvailableValues(SILBasicBlock *block) {
741801
LLVM_DEBUG(llvm::dbgs()
742802
<< " In initial block, setting to initial value!\n");
743803
for (unsigned i : indices(newValues))
744-
newValues[i] = interface.initialValue;
804+
newValues[i] = initialValue;
745805
LLVM_DEBUG(newValues.print(llvm::dbgs(), " "));
746806
return newValues;
747807
}
@@ -1108,15 +1168,14 @@ void Implementation::rewriteUses() {
11081168
IntervalMapAllocator::Map typeSpanToValue(getAllocator());
11091169

11101170
auto *fn = getMarkedValue()->getFunction();
1111-
assert(!interface.initialValue);
1171+
assert(!initialValue);
11121172
{
11131173
// We are always going to copy our root value.
11141174
auto *next = getRootValue()->getNextInstruction();
11151175
SILBuilderWithScope builder(next);
1116-
interface.initialValue =
1117-
builder.createCopyValue(getSafeLoc(next), getRootValue());
1176+
initialValue = builder.createCopyValue(getSafeLoc(next), getRootValue());
11181177
}
1119-
assert(interface.initialValue);
1178+
assert(initialValue);
11201179

11211180
// Walking each block in RPO order.
11221181
for (auto *block : getPostOrderFunctionInfo()->getReversePostOrder(
@@ -1397,71 +1456,15 @@ void Implementation::rewriteUses() {
13971456
}
13981457
}
13991458

1400-
static void addCompensatingDestroys(SSAPrunedLiveness &liveness,
1401-
PrunedLivenessBoundary &boundary,
1402-
SILValue value) {
1403-
InstructionSet consumingInsts(value->getFunction());
1404-
liveness.initializeDef(value);
1405-
for (auto *use : value->getUses()) {
1406-
if (use->isConsuming())
1407-
consumingInsts.insert(use->getUser());
1408-
liveness.updateForUse(use->getUser(), use->isConsuming());
1409-
if (auto *bbi = dyn_cast<BeginBorrowInst>(use->getUser())) {
1410-
for (auto *ebi : bbi->getEndBorrows()) {
1411-
liveness.updateForUse(ebi, false /*use is consuming*/);
1412-
}
1413-
}
1414-
}
1415-
liveness.computeBoundary(boundary);
1416-
for (auto *user : boundary.lastUsers) {
1417-
// If this is a consuming inst, just continue.
1418-
if (consumingInsts.contains(user))
1419-
continue;
1420-
// Otherwise, we need to insert a destroy_value afterwards.
1421-
auto *next = user->getNextInstruction();
1422-
SILBuilderWithScope builder(next);
1423-
builder.createDestroyValue(getSafeLoc(next), value);
1424-
}
1425-
1426-
// Insert destroy_value along all boundary edges.
1427-
for (auto *edge : boundary.boundaryEdges) {
1428-
SILBuilderWithScope builder(edge->begin());
1429-
builder.createDestroyValue(getSafeLoc(&*edge->begin()), value);
1430-
}
1431-
1432-
// If we have a dead def, insert the destroy_value immediately at the def.
1433-
for (auto *deadDef : boundary.deadDefs) {
1434-
SILInstruction *nextInst = nullptr;
1435-
if (auto *inst = dyn_cast<SILInstruction>(deadDef)) {
1436-
nextInst = inst->getNextInstruction();
1437-
} else if (auto *arg = dyn_cast<SILArgument>(deadDef)) {
1438-
nextInst = arg->getNextInstruction();
1439-
} else {
1440-
llvm_unreachable("Unhandled dead def?!");
1441-
}
1442-
SILBuilderWithScope builder(nextInst);
1443-
builder.createDestroyValue(getSafeLoc(nextInst), value);
1444-
}
1445-
}
1446-
1447-
void BorrowToDestructureTransform::cleanup(
1448-
StackList<BeginBorrowInst *> &borrowWorklist) {
1449-
// First clean up all of our borrows/copies/struct_extracts which no longer
1450-
// have any uses...
1451-
InstructionDeleter deleter;
1452-
while (!borrowWorklist.empty()) {
1453-
deleter.recursivelyForceDeleteUsersAndFixLifetimes(
1454-
borrowWorklist.pop_back_val());
1455-
}
1456-
1459+
void Implementation::cleanup() {
14571460
// Then add destroys for any destructure elements that we inserted that we did
14581461
// not actually completely consume.
1459-
auto *fn = mmci->getFunction();
1462+
auto *fn = getMarkedValue()->getFunction();
14601463
SmallVector<SILBasicBlock *, 8> discoveredBlocks;
14611464
SSAPrunedLiveness liveness(&discoveredBlocks);
14621465
PrunedLivenessBoundary boundary;
1463-
while (!createdDestructures.empty()) {
1464-
auto *inst = createdDestructures.pop_back_val();
1466+
while (!interface.createdDestructures.empty()) {
1467+
auto *inst = interface.createdDestructures.pop_back_val();
14651468
assert(isa<DestructureStructInst>(inst) || isa<DestructureTupleInst>(inst));
14661469
for (auto result : inst->getResults()) {
14671470
if (result->getType().isTrivial(*fn))
@@ -1476,8 +1479,8 @@ void BorrowToDestructureTransform::cleanup(
14761479
}
14771480

14781481
// Then do this for our inserted phis.
1479-
while (!createdPhiArguments.empty()) {
1480-
auto *arg = createdPhiArguments.pop_back_val();
1482+
while (!interface.createdPhiArguments.empty()) {
1483+
auto *arg = interface.createdPhiArguments.pop_back_val();
14811484

14821485
// If we have a trivial argument, we do not ened to add any compensating
14831486
// destroys.
@@ -1636,8 +1639,18 @@ bool BorrowToDestructureTransform::transform() {
16361639
impl.blockToAvailableValues.emplace(impl.liveness);
16371640
impl.rewriteUses();
16381641

1639-
// Now that we have done our rewritting, we need to do a few cleanups.
1640-
cleanup(borrowWorklist);
1642+
// Now that we have done our rewritting, we need to do a few cleanups starting
1643+
// by inserting compensating destroys for all of our inserted
1644+
// phis/destructures/initial value copy.
1645+
impl.cleanup();
1646+
1647+
// Then clean up all of our borrows/copies/struct_extracts which no longer
1648+
// have any uses...
1649+
InstructionDeleter deleter;
1650+
while (!borrowWorklist.empty()) {
1651+
deleter.recursivelyForceDeleteUsersAndFixLifetimes(
1652+
borrowWorklist.pop_back_val());
1653+
}
16411654

16421655
return true;
16431656
}

0 commit comments

Comments
 (0)