6565
6666#define DEBUG_TYPE " copy-propagation"
6767
68- #include " swift/Basic/Assertions.h"
6968#include " swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h"
69+ #include " swift/Basic/Assertions.h"
7070#include " swift/SIL/InstructionUtils.h"
7171#include " swift/SIL/NodeDatastructures.h"
7272#include " swift/SIL/OSSALifetimeCompletion.h"
@@ -132,17 +132,29 @@ static bool isDestroyOfCopyOf(SILInstruction *instruction, SILValue def) {
132132bool CanonicalizeOSSALifetime::computeCanonicalLiveness () {
133133 LLVM_DEBUG (llvm::dbgs () << " Computing canonical liveness from:\n " ;
134134 getCurrentDef ()->print (llvm::dbgs ()));
135- defUseWorklist.initialize (getCurrentDef ());
135+ SmallVector<unsigned , 8 > indexWorklist;
136+ ValueSet visitedDefs (getCurrentDef ()->getFunction ());
137+ auto addDefToWorklist = [&](Def def) {
138+ if (!visitedDefs.insert (def.getValue ()))
139+ return ;
140+ discoveredDefs.push_back (def);
141+ indexWorklist.push_back (discoveredDefs.size () - 1 );
142+ };
143+ discoveredDefs.clear ();
144+ addDefToWorklist (Def::root (getCurrentDef ()));
136145 // Only the first level of reborrows need to be consider. All nested inner
137146 // adjacent reborrows and phis are encapsulated within their lifetimes.
138147 SILPhiArgument *arg;
139148 if ((arg = dyn_cast<SILPhiArgument>(getCurrentDef ())) && arg->isPhi ()) {
140149 visitInnerAdjacentPhis (arg, [&](SILArgument *reborrow) {
141- defUseWorklist. insert ( reborrow);
150+ addDefToWorklist ( Def:: reborrow(reborrow) );
142151 return true ;
143152 });
144153 }
145- while (SILValue value = defUseWorklist.pop ()) {
154+ while (!indexWorklist.empty ()) {
155+ auto index = indexWorklist.pop_back_val ();
156+ auto def = discoveredDefs[index];
157+ auto value = def.getValue ();
146158 LLVM_DEBUG (llvm::dbgs () << " Uses of value:\n " ;
147159 value->print (llvm::dbgs ()));
148160
@@ -153,11 +165,20 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
153165 auto *user = use->getUser ();
154166 // Recurse through copies.
155167 if (auto *copy = dyn_cast<CopyValueInst>(user)) {
156- defUseWorklist.insert (copy);
168+ // Don't recurse through copies of borrowed-froms or reborrows.
169+ switch (def) {
170+ case Def::Kind::Root:
171+ case Def::Kind::Copy:
172+ addDefToWorklist (Def::copy (copy));
173+ break ;
174+ case Def::Kind::Reborrow:
175+ case Def::Kind::BorrowedFrom:
176+ break ;
177+ }
157178 continue ;
158179 }
159180 if (auto *bfi = dyn_cast<BorrowedFromInst>(user)) {
160- defUseWorklist. insert ( bfi);
181+ addDefToWorklist ( Def::borrowedFrom ( bfi) );
161182 continue ;
162183 }
163184 // Handle debug_value instructions separately.
@@ -244,7 +265,7 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
244265 // This branch reborrows a guaranteed phi whose lifetime is dependent on
245266 // currentDef. Uses of the reborrowing phi extend liveness.
246267 auto *reborrow = PhiOperand (use).getValue ();
247- defUseWorklist. insert ( reborrow);
268+ addDefToWorklist ( Def:: reborrow(reborrow) );
248269 break ;
249270 }
250271 }
@@ -1148,20 +1169,17 @@ void CanonicalizeOSSALifetime::rewriteCopies(
11481169 SmallVectorImpl<DestroyValueInst *> const &newDestroys) {
11491170 assert (getCurrentDef ()->getOwnershipKind () == OwnershipKind::Owned);
11501171
1172+ // Shadow discoveredDefs in order to constrain its uses.
1173+ const auto &discoveredDefs = this ->discoveredDefs ;
1174+
11511175 InstructionSetVector instsToDelete (getCurrentDef ()->getFunction ());
1152- defUseWorklist.clear ();
11531176
11541177 // Visit each operand in the def-use chain.
11551178 //
11561179 // Return true if the operand can use the current definition. Return false if
11571180 // it requires a copy.
11581181 auto visitUse = [&](Operand *use) {
11591182 auto *user = use->getUser ();
1160- // Recurse through copies.
1161- if (auto *copy = dyn_cast<CopyValueInst>(user)) {
1162- defUseWorklist.insert (copy);
1163- return true ;
1164- }
11651183 if (destroys.contains (user)) {
11661184 auto *destroy = cast<DestroyValueInst>(user);
11671185 // If this destroy was marked as a final destroy, ignore it; otherwise,
@@ -1195,37 +1213,54 @@ void CanonicalizeOSSALifetime::rewriteCopies(
11951213 };
11961214
11971215 // Perform a def-use traversal, visiting each use operand.
1198- for (auto useIter = getCurrentDef ()->use_begin (),
1199- endIter = getCurrentDef ()->use_end (); useIter != endIter;) {
1200- Operand *use = *useIter++;
1201- if (!visitUse (use)) {
1202- copyLiveUse (use, getCallbacks ());
1203- }
1204- }
1205- while (SILValue value = defUseWorklist.pop ()) {
1206- CopyValueInst *srcCopy = cast<CopyValueInst>(value);
1207- // Recurse through copies while replacing their uses.
1208- Operand *reusedCopyOp = nullptr ;
1209- for (auto useIter = srcCopy->use_begin (); useIter != srcCopy->use_end ();) {
1210- Operand *use = *useIter++;
1211- if (!visitUse (use)) {
1212- if (!reusedCopyOp && srcCopy->getParent () == use->getParentBlock ()) {
1213- reusedCopyOp = use;
1214- } else {
1216+ for (auto def : discoveredDefs) {
1217+ switch (def) {
1218+ case Def::Kind::BorrowedFrom:
1219+ case Def::Kind::Reborrow:
1220+ // Direct uses of these defs never need to be rewritten. Being guaranteed
1221+ // values, none of their direct uses consume an owned value.
1222+ assert (def.getValue ()->getOwnershipKind () == OwnershipKind::Guaranteed);
1223+ break ;
1224+ case Def::Kind::Root: {
1225+ SILValue value = def.getValue ();
1226+ for (auto useIter = value->use_begin (), endIter = value->use_end ();
1227+ useIter != endIter;) {
1228+ Operand *use = *useIter++;
1229+ if (!visitUse (use)) {
12151230 copyLiveUse (use, getCallbacks ());
12161231 }
12171232 }
1233+ break ;
12181234 }
1219- if (!(reusedCopyOp && srcCopy->hasOneUse ())) {
1220- getCallbacks ().replaceValueUsesWith (srcCopy, srcCopy->getOperand ());
1221- if (reusedCopyOp) {
1222- reusedCopyOp->set (srcCopy);
1223- } else {
1224- if (instsToDelete.insert (srcCopy)) {
1225- LLVM_DEBUG (llvm::dbgs () << " Removing " << *srcCopy);
1226- ++NumCopiesAndMovesEliminated;
1235+ case Def::Kind::Copy: {
1236+ SILValue value = def.getValue ();
1237+ CopyValueInst *srcCopy = cast<CopyValueInst>(value);
1238+ // Recurse through copies while replacing their uses.
1239+ Operand *reusedCopyOp = nullptr ;
1240+ for (auto useIter = srcCopy->use_begin ();
1241+ useIter != srcCopy->use_end ();) {
1242+ Operand *use = *useIter++;
1243+ if (!visitUse (use)) {
1244+ if (!reusedCopyOp && srcCopy->getParent () == use->getParentBlock ()) {
1245+ reusedCopyOp = use;
1246+ } else {
1247+ copyLiveUse (use, getCallbacks ());
1248+ }
12271249 }
12281250 }
1251+ if (!(reusedCopyOp && srcCopy->hasOneUse ())) {
1252+ getCallbacks ().replaceValueUsesWith (srcCopy, srcCopy->getOperand ());
1253+ if (reusedCopyOp) {
1254+ reusedCopyOp->set (srcCopy);
1255+ } else {
1256+ if (instsToDelete.insert (srcCopy)) {
1257+ LLVM_DEBUG (llvm::dbgs () << " Removing " << *srcCopy);
1258+ ++NumCopiesAndMovesEliminated;
1259+ }
1260+ }
1261+ }
1262+ break ;
1263+ }
12291264 }
12301265 }
12311266 assert (!consumes.hasUnclaimedConsumes ());
0 commit comments