@@ -204,41 +204,40 @@ class DeinitBarriers {
204
204
// Debug instructions that are no longer within this lifetime after shrinking.
205
205
SmallVector<SILInstruction *, 4 > deadUsers;
206
206
207
- explicit DeinitBarriers (SILFunction *function)
208
- : destroyReachesBeginBlocks(function),
209
- destroyReachesEndBlocks(function)
210
- {}
211
-
212
- void compute (const KnownStorageUses &knownUses) {
213
- DestroyReachability (knownUses, *this ).solveBackward ();
207
+ explicit DeinitBarriers (bool ignoreDeinitBarriers,
208
+ const KnownStorageUses &knownUses,
209
+ SILFunction *function)
210
+ : destroyReachesBeginBlocks(function), destroyReachesEndBlocks(function),
211
+ ignoreDeinitBarriers(ignoreDeinitBarriers), knownUses(knownUses) {
212
+ auto rootValue = knownUses.getStorage ().getRoot ();
213
+ assert (rootValue && " HoistDestroys requires a single storage root" );
214
+ // null for function args
215
+ storageDefInst = rootValue->getDefiningInstruction ();
214
216
}
215
217
218
+ void compute () { DestroyReachability (*this ).solveBackward (); }
219
+
216
220
private:
217
221
DeinitBarriers (DeinitBarriers const &) = delete ;
218
222
DeinitBarriers &operator =(DeinitBarriers const &) = delete ;
219
223
220
- // Conforms to BackwardReachability::BlockReachability
224
+ bool ignoreDeinitBarriers;
225
+ const KnownStorageUses &knownUses;
226
+ SILInstruction *storageDefInst = nullptr ;
227
+
228
+ // Implements BackwardReachability::BlockReachability
221
229
class DestroyReachability {
222
- const KnownStorageUses &knownUses;
223
230
DeinitBarriers &result;
224
- SILInstruction *storageDefInst = nullptr ; // null for function args
225
231
226
232
enum class Classification { DeadUser, Barrier, Other };
227
233
228
234
BackwardReachability<DestroyReachability> reachability;
229
235
230
236
public:
231
- DestroyReachability (const KnownStorageUses &knownUses,
232
- DeinitBarriers &result)
233
- : knownUses(knownUses), result(result),
234
- reachability (knownUses.getFunction(), *this) {
235
-
236
- auto rootValue = knownUses.getStorage ().getRoot ();
237
- assert (rootValue && " HoistDestroys requires a single storage root" );
238
- storageDefInst = rootValue->getDefiningInstruction ();
239
-
237
+ DestroyReachability (DeinitBarriers &result)
238
+ : result(result), reachability(result.knownUses.getFunction(), *this ) {
240
239
// Seed backward reachability with destroy points.
241
- for (SILInstruction *destroy : knownUses.originalDestroys ) {
240
+ for (SILInstruction *destroy : result. knownUses .originalDestroys ) {
242
241
reachability.initLastUse (destroy);
243
242
}
244
243
}
@@ -272,16 +271,16 @@ class DeinitBarriers {
272
271
273
272
DeinitBarriers::DestroyReachability::Classification
274
273
DeinitBarriers::DestroyReachability::classifyInstruction (SILInstruction *inst) {
275
- if (knownUses.debugInsts .contains (inst)) {
274
+ if (result. knownUses .debugInsts .contains (inst)) {
276
275
return Classification::DeadUser;
277
276
}
278
- if (inst == storageDefInst) {
277
+ if (inst == result. storageDefInst ) {
279
278
return Classification::Barrier;
280
279
}
281
- if (knownUses.storageUsers .contains (inst)) {
280
+ if (result. knownUses .storageUsers .contains (inst)) {
282
281
return Classification::Barrier;
283
282
}
284
- if (isDeinitBarrier (inst)) {
283
+ if (!result. ignoreDeinitBarriers && isDeinitBarrier (inst)) {
285
284
return Classification::Barrier;
286
285
}
287
286
return Classification::Other;
@@ -341,6 +340,7 @@ bool DeinitBarriers::DestroyReachability::checkReachablePhiBarrier(
341
340
// / object.
342
341
class HoistDestroys {
343
342
SILValue storageRoot;
343
+ bool ignoreDeinitBarriers;
344
344
InstructionDeleter &deleter;
345
345
346
346
// Book-keeping for the rewriting stage.
@@ -349,9 +349,10 @@ class HoistDestroys {
349
349
BasicBlockSetVector destroyMergeBlocks;
350
350
351
351
public:
352
- HoistDestroys (SILValue storageRoot, InstructionDeleter &deleter)
353
- : storageRoot(storageRoot), deleter(deleter),
354
- destroyMergeBlocks (getFunction()) {}
352
+ HoistDestroys (SILValue storageRoot, bool ignoreDeinitBarriers,
353
+ InstructionDeleter &deleter)
354
+ : storageRoot(storageRoot), ignoreDeinitBarriers(ignoreDeinitBarriers),
355
+ deleter (deleter), destroyMergeBlocks(getFunction()) {}
355
356
356
357
bool perform ();
357
358
@@ -386,8 +387,8 @@ bool HoistDestroys::perform() {
386
387
if (!knownUses.findUses ())
387
388
return false ;
388
389
389
- DeinitBarriers deinitBarriers (getFunction ());
390
- deinitBarriers.compute (knownUses );
390
+ DeinitBarriers deinitBarriers (ignoreDeinitBarriers, knownUses, getFunction ());
391
+ deinitBarriers.compute ();
391
392
392
393
// No SIL changes happen before rewriting.
393
394
return rewriteDestroys (knownUses, deinitBarriers);
@@ -530,7 +531,8 @@ void HoistDestroys::mergeDestroys(SILBasicBlock *mergeBlock) {
530
531
// Top-Level API
531
532
// =============================================================================
532
533
533
- bool hoistDestroys (SILValue root, InstructionDeleter &deleter) {
534
+ bool hoistDestroys (SILValue root, bool ignoreDeinitBarriers,
535
+ InstructionDeleter &deleter) {
534
536
LLVM_DEBUG (llvm::dbgs () << " Performing destroy hoisting on " << root);
535
537
536
538
SILFunction *function = root->getFunction ();
@@ -540,7 +542,7 @@ bool hoistDestroys(SILValue root, InstructionDeleter &deleter) {
540
542
// The algorithm assumes no critical edges.
541
543
assert (function->hasOwnership () && " requires OSSA" );
542
544
543
- return HoistDestroys (root, deleter).perform ();
545
+ return HoistDestroys (root, ignoreDeinitBarriers, deleter).perform ();
544
546
}
545
547
546
548
// =============================================================================
@@ -607,18 +609,23 @@ void SSADestroyHoisting::run() {
607
609
// the end will result in hoisting inner begin_access' destroy_addrs first.
608
610
while (!bais.empty ()) {
609
611
auto *bai = bais.pop_back_val ();
610
- changed |= hoistDestroys (bai, deleter);
612
+ changed |= hoistDestroys (bai, /* ignoreDeinitBarriers= */ true , deleter);
611
613
}
612
614
// Alloc stacks always enclose their accesses.
613
615
for (auto *asi : asis) {
614
- changed |= hoistDestroys (asi, deleter);
616
+ changed |= hoistDestroys (asi, /* ignoreDeinitBarriers= */ false , deleter);
615
617
}
616
618
// Arguments enclose everything.
617
619
for (auto *arg : getFunction ()->getArguments ()) {
618
620
if (arg->getType ().isAddress ()) {
619
- changed |= hoistDestroys (arg, deleter);
621
+ bool isInout = cast<SILFunctionArgument>(arg)
622
+ ->getArgumentConvention ()
623
+ .isInoutConvention ();
624
+ changed |= hoistDestroys (arg, /* ignoreDeinitBarriers=*/
625
+ isInout, deleter);
620
626
}
621
627
}
628
+
622
629
if (changed) {
623
630
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
624
631
}
0 commit comments