@@ -86,8 +86,6 @@ using namespace swift;
86
86
// Temporary debugging flag until this pass is better tested.
87
87
static llvm::cl::opt<bool > EnableCopyForwarding (" enable-copyforwarding" ,
88
88
llvm::cl::init (true ));
89
- static llvm::cl::opt<bool > EnableDestroyHoisting (" enable-destroyhoisting" ,
90
- llvm::cl::init (true ));
91
89
92
90
// / \return true if the given copy source value can only be accessed via the
93
91
// / given def (this def uniquely identifies the object).
@@ -513,7 +511,6 @@ class CopyForwarding {
513
511
PostOrderAnalysis *PostOrder;
514
512
DominanceAnalysis *DomAnalysis;
515
513
RCIdentityAnalysis *RCIAnalysis;
516
- bool DoGlobalHoisting;
517
514
bool HasChanged;
518
515
bool HasChangedCFG;
519
516
@@ -535,7 +532,6 @@ class CopyForwarding {
535
532
SmallPtrSet<SILInstruction*, 16 > SrcUserInsts;
536
533
SmallPtrSet<SILInstruction*, 4 > SrcDebugValueInsts;
537
534
SmallVector<CopyAddrInst*, 4 > TakePoints;
538
- SmallPtrSet<SILInstruction *, 16 > StoredValueUserInsts;
539
535
SmallVector<DestroyAddrInst*, 4 > DestroyPoints;
540
536
SmallPtrSet<SILBasicBlock*, 32 > DeadInBlocks;
541
537
@@ -579,7 +575,7 @@ class CopyForwarding {
579
575
CopyForwarding (PostOrderAnalysis *PO, DominanceAnalysis *DA,
580
576
RCIdentityAnalysis *RCIAnalysis)
581
577
: PostOrder(PO), DomAnalysis(DA), RCIAnalysis(RCIAnalysis),
582
- DoGlobalHoisting ( false ), HasChanged(false ), HasChangedCFG(false ),
578
+ HasChanged (false ), HasChangedCFG(false ),
583
579
IsSrcLoadedFrom(false ), HasUnknownStoredValue(false ),
584
580
HasForwardedToCopy(false ), CurrentCopy(nullptr ) {}
585
581
@@ -590,7 +586,6 @@ class CopyForwarding {
590
586
// some alloc_stack cases after global destroy hoisting. CopyForwarding will
591
587
// be reapplied after the transparent function is inlined at which point
592
588
// global hoisting will be done.
593
- DoGlobalHoisting = !F->isTransparent ();
594
589
if (HasChangedCFG) {
595
590
// We are only invalidating the analysis that we use internally.
596
591
// We'll invalidate the analysis that are used by other passes at the end.
@@ -605,7 +600,6 @@ class CopyForwarding {
605
600
SrcUserInsts.clear ();
606
601
SrcDebugValueInsts.clear ();
607
602
TakePoints.clear ();
608
- StoredValueUserInsts.clear ();
609
603
DestroyPoints.clear ();
610
604
DeadInBlocks.clear ();
611
605
CurrentCopy = nullptr ;
@@ -621,15 +615,13 @@ class CopyForwarding {
621
615
void forwardCopiesOf (SILValue Def, SILFunction *F);
622
616
623
617
protected:
624
- bool propagateCopy (CopyAddrInst *CopyInst, bool hoistingDestroy );
618
+ bool propagateCopy (CopyAddrInst *CopyInst);
625
619
CopyAddrInst *findCopyIntoDeadTemp (
626
620
CopyAddrInst *destCopy,
627
621
SmallVectorImpl<SILInstruction *> &debugInstsToDelete);
628
622
bool forwardDeadTempCopy (CopyAddrInst *destCopy);
629
623
bool forwardPropagateCopy ();
630
624
bool backwardPropagateCopy ();
631
- bool hoistDestroy (SILInstruction *DestroyPoint, SILLocation DestroyLoc,
632
- SmallVectorImpl<SILInstruction *> &debugInstsToDelete);
633
625
634
626
bool isSourceDeadAtCopy ();
635
627
@@ -671,7 +663,7 @@ class CopyDestUserVisitor : public AddressUserVisitor {
671
663
// / If the forwarded copy is not an [init], then insert a destroy of the copy's
672
664
// / dest.
673
665
bool CopyForwarding::
674
- propagateCopy (CopyAddrInst *CopyInst, bool hoistingDestroy ) {
666
+ propagateCopy (CopyAddrInst *CopyInst) {
675
667
if (!EnableCopyForwarding)
676
668
return false ;
677
669
@@ -693,7 +685,7 @@ propagateCopy(CopyAddrInst *CopyInst, bool hoistingDestroy) {
693
685
694
686
// Handle copy-of-copy without analyzing uses.
695
687
// Assumes that CurrentCopy->getSrc() is dead after CurrentCopy.
696
- assert (CurrentCopy->isTakeOfSrc () || hoistingDestroy );
688
+ assert (CurrentCopy->isTakeOfSrc ());
697
689
if (forwardDeadTempCopy (CurrentCopy)) {
698
690
HasChanged = true ;
699
691
++NumDeadTemp;
@@ -703,8 +695,7 @@ propagateCopy(CopyAddrInst *CopyInst, bool hoistingDestroy) {
703
695
if (forwardPropagateCopy ()) {
704
696
LLVM_DEBUG (llvm::dbgs () << " Forwarding Copy:" << *CurrentCopy);
705
697
if (!CurrentCopy->isInitializationOfDest ()) {
706
- // Replace the original copy with a destroy. We may be able to hoist it
707
- // more in another pass but don't currently iterate.
698
+ // Replace the original copy with a destroy.
708
699
SILBuilderWithScope (CurrentCopy)
709
700
.createDestroyAddr (CurrentCopy->getLoc (), CurrentCopy->getDest ());
710
701
}
@@ -832,16 +823,7 @@ forwardDeadTempCopy(CopyAddrInst *destCopy) {
832
823
deadDebugUser->eraseFromParent ();
833
824
}
834
825
835
- // Either `destCopy` is a take, or the caller is hoisting a destroy:
836
- // copy_addr %temp, %dest
837
- // ...
838
- // destroy %temp
839
- //
840
- // If the caller is hoisting a destroy, and we return `true` then it will
841
- // erase the destroy for us. Either way, it's safe to simply rewrite destCopy.
842
- // For now, don't bother finding the subsequent destroy, because this isn't
843
- // the common case.
844
-
826
+ // `destCopy` is a take. It's safe to simply rewrite destCopy.
845
827
destCopy->setSrc (srcCopy->getSrc ());
846
828
destCopy->setIsTakeOfSrc (srcCopy->isTakeOfSrc ());
847
829
srcCopy->eraseFromParent ();
@@ -878,8 +860,7 @@ bool CopyForwarding::doesCopyDominateDestUsers(
878
860
return true ;
879
861
}
880
862
881
- // Add all recognized users of storedValue to StoredValueUserInsts. Return true
882
- // if all users were recgonized.
863
+ // Return true if all users were recgonized.
883
864
//
884
865
// To find all SSA users of storedValue, we first find the RC root, then search
885
866
// past any instructions that may propagate the reference.
@@ -900,19 +881,16 @@ bool CopyForwarding::markStoredValueUsers(SILValue storedValue) {
900
881
// Recognize any uses that have no results as normal uses. They cannot
901
882
// transitively propagate a reference.
902
883
if (user->getResults ().empty ()) {
903
- StoredValueUserInsts.insert (user);
904
884
continue ;
905
885
}
906
886
// Recognize full applies as normal uses. They may transitively retain, but
907
887
// the caller cannot rely on that.
908
888
if (FullApplySite::isa (user)) {
909
- StoredValueUserInsts.insert (user);
910
889
continue ;
911
890
}
912
891
// A single-valued use is nontransitive if its result is trivial.
913
892
if (auto *SVI = dyn_cast<SingleValueInstruction>(user)) {
914
893
if (SVI->getType ().isTrivial (*F)) {
915
- StoredValueUserInsts.insert (user);
916
894
continue ;
917
895
}
918
896
}
@@ -957,8 +935,7 @@ static DeallocStackInst *getSingleDealloc(AllocStackInst *ASI) {
957
935
// / If the last use (deinit) is a copy, replace it with a destroy+copy[init].
958
936
// /
959
937
// / The caller has already guaranteed that the lifetime of the copy's source
960
- // / ends at this copy. Either the copy is a [take] or a destroy can be hoisted
961
- // / to the copy.
938
+ // / ends at this copy. The copy is a [take].
962
939
bool CopyForwarding::forwardPropagateCopy () {
963
940
964
941
SILValue CopyDest = CurrentCopy->getDest ();
@@ -1221,98 +1198,6 @@ bool CopyForwarding::backwardPropagateCopy() {
1221
1198
return true ;
1222
1199
}
1223
1200
1224
- // / Attempt to hoist a destroy point up to the last use. If the last use is a
1225
- // / copy, eliminate both the copy and the destroy.
1226
- // /
1227
- // / The copy will be eliminated if the original is not accessed between the
1228
- // / point of copy and the original's destruction.
1229
- // /
1230
- // / CurrentDef = <uniquely identified> // no aliases
1231
- // / ...
1232
- // / Copy = copy_addr [init] Def
1233
- // / ... // no access to CurrentDef
1234
- // / destroy_addr Def
1235
- // /
1236
- // / Return true if a destroy was inserted, forwarded from a copy, or the
1237
- // / block was marked dead-in.
1238
- // / \p debugInstsToDelete will contain the debug_value users of copy src
1239
- // / that need to be deleted if the hoist is successful
1240
- bool CopyForwarding::hoistDestroy (
1241
- SILInstruction *DestroyPoint, SILLocation DestroyLoc,
1242
- SmallVectorImpl<SILInstruction *> &debugInstsToDelete) {
1243
- if (!EnableDestroyHoisting)
1244
- return false ;
1245
-
1246
- assert (!SrcUserInsts.count (DestroyPoint) && " caller should check terminator" );
1247
- SILBasicBlock *BB = DestroyPoint->getParent ();
1248
-
1249
- // If DestroyPoint is a block terminator, we must hoist.
1250
- bool MustHoist = (DestroyPoint == BB->getTerminator ());
1251
- // If we haven't seen anything significant, avoid useless hoisting.
1252
- bool ShouldHoist = MustHoist;
1253
-
1254
- auto tryToInsertHoistedDestroyAfter = [&](SILInstruction *afterInst) {
1255
- if (!ShouldHoist)
1256
- return false ;
1257
- LLVM_DEBUG (llvm::dbgs () << " Hoisting to Use:" << *afterInst);
1258
- SILBuilderWithScope (std::next (afterInst->getIterator ()), afterInst)
1259
- .createDestroyAddr (DestroyLoc, CurrentDef);
1260
- HasChanged = true ;
1261
- return true ;
1262
- };
1263
-
1264
- auto SI = DestroyPoint->getIterator (), SE = BB->begin ();
1265
- while (SI != SE) {
1266
- --SI;
1267
- SILInstruction *Inst = &*SI;
1268
- if (!SrcUserInsts.count (Inst)) {
1269
- if (StoredValueUserInsts.count (Inst)) {
1270
- // The current definition may take ownership of a value stored into its
1271
- // address. Its lifetime cannot end before the last use of that stored
1272
- // value.
1273
- // CurrentDef = ...
1274
- // Copy = copy_addr CurrentDef to ...
1275
- // store StoredValue to CurrentDef
1276
- // ... // no access to CurrentDef
1277
- // retain StoredValue
1278
- // destroy_addr CurrentDef
1279
- LLVM_DEBUG (llvm::dbgs () << " Cannot hoist above stored value use:"
1280
- << *Inst);
1281
- return tryToInsertHoistedDestroyAfter (Inst);
1282
- }
1283
- if (isa<DebugValueInst>(Inst)) {
1284
- // Collect debug_value uses of copy src. If the hoist is
1285
- // successful, these instructions will have consumed operand and need to
1286
- // be erased.
1287
- if (SrcDebugValueInsts.contains (Inst)) {
1288
- debugInstsToDelete.push_back (Inst);
1289
- }
1290
- }
1291
- if (!ShouldHoist && isa<ApplyInst>(Inst))
1292
- ShouldHoist = true ;
1293
- continue ;
1294
- }
1295
- if (auto *CopyInst = dyn_cast<CopyAddrInst>(Inst)) {
1296
- if (!CopyInst->isTakeOfSrc () && CopyInst->getSrc () == CurrentDef) {
1297
- // This use is a copy of CurrentDef. Attempt to forward CurrentDef to
1298
- // all uses of the copy's value.
1299
- if (propagateCopy (CopyInst, /* hoistingDestroy=*/ true ))
1300
- return true ;
1301
- }
1302
- }
1303
- return tryToInsertHoistedDestroyAfter (Inst);
1304
- }
1305
- if (!DoGlobalHoisting) {
1306
- // If DoGlobalHoisting is set, then we should never mark a DeadInBlock, so
1307
- // MustHoist should be false.
1308
- assert (!MustHoist &&
1309
- " Cannot hoist above a terminator with global hoisting disabled." );
1310
- return false ;
1311
- }
1312
- DeadInBlocks.insert (BB);
1313
- return true ;
1314
- }
1315
-
1316
1201
// / Perform CopyForwarding on the current Def.
1317
1202
void CopyForwarding::forwardCopiesOf (SILValue Def, SILFunction *F) {
1318
1203
reset (F);
@@ -1322,97 +1207,9 @@ void CopyForwarding::forwardCopiesOf(SILValue Def, SILFunction *F) {
1322
1207
if (!visitAddressUsers (Def, nullptr , visitor))
1323
1208
return ;
1324
1209
1325
- // First forward any copies that implicitly destroy CurrentDef. There is no
1326
- // need to hoist Destroy for these.
1210
+ // Forward any copies that implicitly destroy CurrentDef.
1327
1211
for (auto *CopyInst : TakePoints) {
1328
- propagateCopy (CopyInst, /* hoistingDestroy=*/ false );
1329
- }
1330
- // If the copied address is also loaded from, then destroy hoisting is unsafe.
1331
- //
1332
- // TODO: Record all loads during collectUsers. Implement findRetainPoints to
1333
- // peek though projections of the load, like unchecked_enum_data to find the
1334
- // true extent of the lifetime including transitively referenced objects.
1335
- if (IsSrcLoadedFrom || HasUnknownStoredValue)
1336
- return ;
1337
-
1338
- bool HoistedDestroyFound = false ;
1339
- SILLocation HoistedDestroyLoc = F->getLocation ();
1340
- const SILDebugScope *HoistedDebugScope = nullptr ;
1341
- SmallVector<SILInstruction *, 2 > debugInstsToDelete;
1342
-
1343
- for (auto *Destroy : DestroyPoints) {
1344
- // If hoistDestroy returns false, it was not worth hoisting.
1345
- if (hoistDestroy (Destroy, Destroy->getLoc (), debugInstsToDelete)) {
1346
- // Propagate DestroyLoc for any destroy hoisted above a block.
1347
- if (DeadInBlocks.count (Destroy->getParent ())) {
1348
- HoistedDestroyLoc = Destroy->getLoc ();
1349
- HoistedDebugScope = Destroy->getDebugScope ();
1350
- HoistedDestroyFound = true ;
1351
- }
1352
- // We either just created a new destroy, forwarded a copy, or will
1353
- // continue propagating from this dead-in block. In any case, erase the
1354
- // original Destroy.
1355
- Destroy->eraseFromParent ();
1356
- assert (HasChanged || !DeadInBlocks.empty () && " HasChanged should be set" );
1357
- // Since the hoist was successful, delete all dead debug_value
1358
- for (auto *deadDebugUser : debugInstsToDelete) {
1359
- deadDebugUser->eraseFromParent ();
1360
- }
1361
- }
1362
- debugInstsToDelete.clear ();
1363
- }
1364
- // Any blocks containing a DestroyPoints where hoistDestroy did not find a use
1365
- // are now marked in DeadInBlocks.
1366
- if (DeadInBlocks.empty ())
1367
- return ;
1368
-
1369
- assert (HoistedDestroyFound && " Hoisted destroy should have been found" );
1370
-
1371
- DestroyPoints.clear ();
1372
-
1373
- // Propagate dead-in blocks upward via PostOrder traversal.
1374
- // TODO: We could easily handle hoisting above loops if LoopInfo is available.
1375
- //
1376
- for (auto *BB : PostOrder->get (F)->getPostOrder ()) {
1377
- SmallVector<unsigned , 4 > DeadInSuccs;
1378
- ArrayRef<SILSuccessor> Succs = BB->getSuccessors ();
1379
- if (Succs.empty ())
1380
- continue ;
1381
-
1382
- for (unsigned EdgeIdx = 0 , End = Succs.size (); EdgeIdx != End; ++EdgeIdx) {
1383
- if (DeadInBlocks.count (Succs[EdgeIdx].getBB ()))
1384
- DeadInSuccs.push_back (EdgeIdx);
1385
- }
1386
- if (DeadInSuccs.size () == Succs.size () &&
1387
- !SrcUserInsts.count (BB->getTerminator ())) {
1388
- // All successors are dead, so continue hoisting.
1389
- bool WasHoisted = hoistDestroy (BB->getTerminator (), HoistedDestroyLoc,
1390
- debugInstsToDelete);
1391
- (void )WasHoisted;
1392
- assert (WasHoisted && " should always hoist above a terminator" );
1393
- for (auto *deadDebugUser : debugInstsToDelete) {
1394
- deadDebugUser->eraseFromParent ();
1395
- }
1396
- debugInstsToDelete.clear ();
1397
- continue ;
1398
- }
1399
- // Emit a destroy on each CFG edge leading to a dead-in block. This requires
1400
- // splitting critical edges and will naturally handle redundant branch
1401
- // targets.
1402
- for (unsigned EdgeIdx : DeadInSuccs) {
1403
- SILBasicBlock *SuccBB = splitCriticalEdge (BB->getTerminator (), EdgeIdx);
1404
- if (SuccBB)
1405
- HasChangedCFG = true ;
1406
- else
1407
- SuccBB = BB->getSuccessors ()[EdgeIdx];
1408
-
1409
- // We make no attempt to use the best DebugLoc, because in all known
1410
- // cases, we only have one.
1411
- SILBuilder B (SuccBB->begin ());
1412
- B.setCurrentDebugScope (HoistedDebugScope);
1413
- B.createDestroyAddr (HoistedDestroyLoc, CurrentDef);
1414
- HasChanged = true ;
1415
- }
1212
+ propagateCopy (CopyInst);
1416
1213
}
1417
1214
}
1418
1215
@@ -1539,7 +1336,7 @@ static llvm::cl::opt<int> ForwardStop("copy-forward-stop",
1539
1336
class CopyForwardingPass : public SILFunctionTransform
1540
1337
{
1541
1338
void run () override {
1542
- if (!EnableCopyForwarding && !EnableDestroyHoisting )
1339
+ if (!EnableCopyForwarding)
1543
1340
return ;
1544
1341
1545
1342
// This pass assumes that the ownership lifetime of a value in a memory
@@ -1570,7 +1367,7 @@ class CopyForwardingPass : public SILFunctionTransform
1570
1367
for (auto &BB : *getFunction ())
1571
1368
for (auto II = BB.begin (), IE = BB.end (); II != IE; ++II) {
1572
1369
if (auto *CopyInst = dyn_cast<CopyAddrInst>(&*II)) {
1573
- if (EnableDestroyHoisting && canNRVO (CopyInst)) {
1370
+ if (canNRVO (CopyInst)) {
1574
1371
NRVOCopies.push_back (CopyInst);
1575
1372
continue ;
1576
1373
}
0 commit comments