@@ -60,6 +60,53 @@ static SILLocation getSafeLoc(SILInstruction *inst) {
60
60
return inst->getLoc ();
61
61
}
62
62
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
+
63
110
// ===----------------------------------------------------------------------===//
64
111
// MARK: Available Values
65
112
// ===----------------------------------------------------------------------===//
@@ -137,15 +184,26 @@ struct borrowtodestructure::Implementation {
137
184
138
185
Optional<AvailableValueStore> blockToAvailableValues;
139
186
140
- // Temporarily optional as this code is refactored.
187
+ // / The liveness that we use for all borrows or for individual switch_enum
188
+ // / arguments.
141
189
FieldSensitiveSSAPrunedLiveRange liveness;
142
190
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
+
143
195
Implementation (BorrowToDestructureTransform &interface,
144
196
SmallVectorImpl<SILBasicBlock *> &discoveredBlocks)
145
197
: interface(interface),
146
198
liveness (interface.mmci->getFunction (), &discoveredBlocks) {}
147
199
200
+ void clear () {
201
+ liveness.clear ();
202
+ initialValue = SILValue ();
203
+ }
204
+
148
205
void init (SILValue rootAddress) {
206
+ clear ();
149
207
liveness.init (rootAddress);
150
208
liveness.initializeDef (rootAddress, TypeTreeLeafTypeRange (rootAddress));
151
209
}
@@ -166,6 +224,8 @@ struct borrowtodestructure::Implementation {
166
224
// / destructures as appropriate.
167
225
void rewriteUses ();
168
226
227
+ void cleanup ();
228
+
169
229
AvailableValues &computeAvailableValues (SILBasicBlock *block);
170
230
171
231
// / Returns mark_must_check if we are processing borrows or the enum argument
@@ -741,7 +801,7 @@ AvailableValues &Implementation::computeAvailableValues(SILBasicBlock *block) {
741
801
LLVM_DEBUG (llvm::dbgs ()
742
802
<< " In initial block, setting to initial value!\n " );
743
803
for (unsigned i : indices (newValues))
744
- newValues[i] = interface. initialValue ;
804
+ newValues[i] = initialValue;
745
805
LLVM_DEBUG (newValues.print (llvm::dbgs (), " " ));
746
806
return newValues;
747
807
}
@@ -1108,15 +1168,14 @@ void Implementation::rewriteUses() {
1108
1168
IntervalMapAllocator::Map typeSpanToValue (getAllocator ());
1109
1169
1110
1170
auto *fn = getMarkedValue ()->getFunction ();
1111
- assert (!interface. initialValue );
1171
+ assert (!initialValue);
1112
1172
{
1113
1173
// We are always going to copy our root value.
1114
1174
auto *next = getRootValue ()->getNextInstruction ();
1115
1175
SILBuilderWithScope builder (next);
1116
- interface.initialValue =
1117
- builder.createCopyValue (getSafeLoc (next), getRootValue ());
1176
+ initialValue = builder.createCopyValue (getSafeLoc (next), getRootValue ());
1118
1177
}
1119
- assert (interface. initialValue );
1178
+ assert (initialValue);
1120
1179
1121
1180
// Walking each block in RPO order.
1122
1181
for (auto *block : getPostOrderFunctionInfo ()->getReversePostOrder (
@@ -1397,71 +1456,15 @@ void Implementation::rewriteUses() {
1397
1456
}
1398
1457
}
1399
1458
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 () {
1457
1460
// Then add destroys for any destructure elements that we inserted that we did
1458
1461
// not actually completely consume.
1459
- auto *fn = mmci ->getFunction ();
1462
+ auto *fn = getMarkedValue () ->getFunction ();
1460
1463
SmallVector<SILBasicBlock *, 8 > discoveredBlocks;
1461
1464
SSAPrunedLiveness liveness (&discoveredBlocks);
1462
1465
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 ();
1465
1468
assert (isa<DestructureStructInst>(inst) || isa<DestructureTupleInst>(inst));
1466
1469
for (auto result : inst->getResults ()) {
1467
1470
if (result->getType ().isTrivial (*fn))
@@ -1476,8 +1479,8 @@ void BorrowToDestructureTransform::cleanup(
1476
1479
}
1477
1480
1478
1481
// 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 ();
1481
1484
1482
1485
// If we have a trivial argument, we do not ened to add any compensating
1483
1486
// destroys.
@@ -1636,8 +1639,18 @@ bool BorrowToDestructureTransform::transform() {
1636
1639
impl.blockToAvailableValues .emplace (impl.liveness );
1637
1640
impl.rewriteUses ();
1638
1641
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
+ }
1641
1654
1642
1655
return true ;
1643
1656
}
0 commit comments