@@ -86,8 +86,6 @@ using namespace swift;
8686// Temporary debugging flag until this pass is better tested.
8787static llvm::cl::opt<bool > EnableCopyForwarding (" enable-copyforwarding" ,
8888 llvm::cl::init (true ));
89- static llvm::cl::opt<bool > EnableDestroyHoisting (" enable-destroyhoisting" ,
90- llvm::cl::init (true ));
9189
9290// / \return true if the given copy source value can only be accessed via the
9391// / given def (this def uniquely identifies the object).
@@ -513,7 +511,6 @@ class CopyForwarding {
513511 PostOrderAnalysis *PostOrder;
514512 DominanceAnalysis *DomAnalysis;
515513 RCIdentityAnalysis *RCIAnalysis;
516- bool DoGlobalHoisting;
517514 bool HasChanged;
518515 bool HasChangedCFG;
519516
@@ -535,7 +532,6 @@ class CopyForwarding {
535532 SmallPtrSet<SILInstruction*, 16 > SrcUserInsts;
536533 SmallPtrSet<SILInstruction*, 4 > SrcDebugValueInsts;
537534 SmallVector<CopyAddrInst*, 4 > TakePoints;
538- SmallPtrSet<SILInstruction *, 16 > StoredValueUserInsts;
539535 SmallVector<DestroyAddrInst*, 4 > DestroyPoints;
540536 SmallPtrSet<SILBasicBlock*, 32 > DeadInBlocks;
541537
@@ -579,7 +575,7 @@ class CopyForwarding {
579575 CopyForwarding (PostOrderAnalysis *PO, DominanceAnalysis *DA,
580576 RCIdentityAnalysis *RCIAnalysis)
581577 : PostOrder(PO), DomAnalysis(DA), RCIAnalysis(RCIAnalysis),
582- DoGlobalHoisting ( false ), HasChanged(false ), HasChangedCFG(false ),
578+ HasChanged (false ), HasChangedCFG(false ),
583579 IsSrcLoadedFrom(false ), HasUnknownStoredValue(false ),
584580 HasForwardedToCopy(false ), CurrentCopy(nullptr ) {}
585581
@@ -590,7 +586,6 @@ class CopyForwarding {
590586 // some alloc_stack cases after global destroy hoisting. CopyForwarding will
591587 // be reapplied after the transparent function is inlined at which point
592588 // global hoisting will be done.
593- DoGlobalHoisting = !F->isTransparent ();
594589 if (HasChangedCFG) {
595590 // We are only invalidating the analysis that we use internally.
596591 // We'll invalidate the analysis that are used by other passes at the end.
@@ -605,7 +600,6 @@ class CopyForwarding {
605600 SrcUserInsts.clear ();
606601 SrcDebugValueInsts.clear ();
607602 TakePoints.clear ();
608- StoredValueUserInsts.clear ();
609603 DestroyPoints.clear ();
610604 DeadInBlocks.clear ();
611605 CurrentCopy = nullptr ;
@@ -621,15 +615,13 @@ class CopyForwarding {
621615 void forwardCopiesOf (SILValue Def, SILFunction *F);
622616
623617protected:
624- bool propagateCopy (CopyAddrInst *CopyInst, bool hoistingDestroy );
618+ bool propagateCopy (CopyAddrInst *CopyInst);
625619 CopyAddrInst *findCopyIntoDeadTemp (
626620 CopyAddrInst *destCopy,
627621 SmallVectorImpl<SILInstruction *> &debugInstsToDelete);
628622 bool forwardDeadTempCopy (CopyAddrInst *destCopy);
629623 bool forwardPropagateCopy ();
630624 bool backwardPropagateCopy ();
631- bool hoistDestroy (SILInstruction *DestroyPoint, SILLocation DestroyLoc,
632- SmallVectorImpl<SILInstruction *> &debugInstsToDelete);
633625
634626 bool isSourceDeadAtCopy ();
635627
@@ -671,7 +663,7 @@ class CopyDestUserVisitor : public AddressUserVisitor {
671663// / If the forwarded copy is not an [init], then insert a destroy of the copy's
672664// / dest.
673665bool CopyForwarding::
674- propagateCopy (CopyAddrInst *CopyInst, bool hoistingDestroy ) {
666+ propagateCopy (CopyAddrInst *CopyInst) {
675667 if (!EnableCopyForwarding)
676668 return false ;
677669
@@ -693,7 +685,7 @@ propagateCopy(CopyAddrInst *CopyInst, bool hoistingDestroy) {
693685
694686 // Handle copy-of-copy without analyzing uses.
695687 // Assumes that CurrentCopy->getSrc() is dead after CurrentCopy.
696- assert (CurrentCopy->isTakeOfSrc () || hoistingDestroy );
688+ assert (CurrentCopy->isTakeOfSrc ());
697689 if (forwardDeadTempCopy (CurrentCopy)) {
698690 HasChanged = true ;
699691 ++NumDeadTemp;
@@ -703,8 +695,7 @@ propagateCopy(CopyAddrInst *CopyInst, bool hoistingDestroy) {
703695 if (forwardPropagateCopy ()) {
704696 LLVM_DEBUG (llvm::dbgs () << " Forwarding Copy:" << *CurrentCopy);
705697 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.
708699 SILBuilderWithScope (CurrentCopy)
709700 .createDestroyAddr (CurrentCopy->getLoc (), CurrentCopy->getDest ());
710701 }
@@ -832,16 +823,7 @@ forwardDeadTempCopy(CopyAddrInst *destCopy) {
832823 deadDebugUser->eraseFromParent ();
833824 }
834825
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.
845827 destCopy->setSrc (srcCopy->getSrc ());
846828 destCopy->setIsTakeOfSrc (srcCopy->isTakeOfSrc ());
847829 srcCopy->eraseFromParent ();
@@ -878,8 +860,7 @@ bool CopyForwarding::doesCopyDominateDestUsers(
878860 return true ;
879861}
880862
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.
883864//
884865// To find all SSA users of storedValue, we first find the RC root, then search
885866// past any instructions that may propagate the reference.
@@ -900,19 +881,16 @@ bool CopyForwarding::markStoredValueUsers(SILValue storedValue) {
900881 // Recognize any uses that have no results as normal uses. They cannot
901882 // transitively propagate a reference.
902883 if (user->getResults ().empty ()) {
903- StoredValueUserInsts.insert (user);
904884 continue ;
905885 }
906886 // Recognize full applies as normal uses. They may transitively retain, but
907887 // the caller cannot rely on that.
908888 if (FullApplySite::isa (user)) {
909- StoredValueUserInsts.insert (user);
910889 continue ;
911890 }
912891 // A single-valued use is nontransitive if its result is trivial.
913892 if (auto *SVI = dyn_cast<SingleValueInstruction>(user)) {
914893 if (SVI->getType ().isTrivial (*F)) {
915- StoredValueUserInsts.insert (user);
916894 continue ;
917895 }
918896 }
@@ -957,8 +935,7 @@ static DeallocStackInst *getSingleDealloc(AllocStackInst *ASI) {
957935// / If the last use (deinit) is a copy, replace it with a destroy+copy[init].
958936// /
959937// / 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].
962939bool CopyForwarding::forwardPropagateCopy () {
963940
964941 SILValue CopyDest = CurrentCopy->getDest ();
@@ -1221,98 +1198,6 @@ bool CopyForwarding::backwardPropagateCopy() {
12211198 return true ;
12221199}
12231200
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-
13161201// / Perform CopyForwarding on the current Def.
13171202void CopyForwarding::forwardCopiesOf (SILValue Def, SILFunction *F) {
13181203 reset (F);
@@ -1322,97 +1207,9 @@ void CopyForwarding::forwardCopiesOf(SILValue Def, SILFunction *F) {
13221207 if (!visitAddressUsers (Def, nullptr , visitor))
13231208 return ;
13241209
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.
13271211 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);
14161213 }
14171214}
14181215
@@ -1539,7 +1336,7 @@ static llvm::cl::opt<int> ForwardStop("copy-forward-stop",
15391336class CopyForwardingPass : public SILFunctionTransform
15401337{
15411338 void run () override {
1542- if (!EnableCopyForwarding && !EnableDestroyHoisting )
1339+ if (!EnableCopyForwarding)
15431340 return ;
15441341
15451342 // This pass assumes that the ownership lifetime of a value in a memory
@@ -1570,7 +1367,7 @@ class CopyForwardingPass : public SILFunctionTransform
15701367 for (auto &BB : *getFunction ())
15711368 for (auto II = BB.begin (), IE = BB.end (); II != IE; ++II) {
15721369 if (auto *CopyInst = dyn_cast<CopyAddrInst>(&*II)) {
1573- if (EnableDestroyHoisting && canNRVO (CopyInst)) {
1370+ if (canNRVO (CopyInst)) {
15741371 NRVOCopies.push_back (CopyInst);
15751372 continue ;
15761373 }
0 commit comments