65
65
66
66
#define DEBUG_TYPE " copy-propagation"
67
67
68
- #include " swift/Basic/Assertions.h"
69
68
#include " swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h"
69
+ #include " swift/Basic/Assertions.h"
70
70
#include " swift/SIL/InstructionUtils.h"
71
71
#include " swift/SIL/NodeDatastructures.h"
72
72
#include " swift/SIL/OSSALifetimeCompletion.h"
@@ -132,17 +132,29 @@ static bool isDestroyOfCopyOf(SILInstruction *instruction, SILValue def) {
132
132
bool CanonicalizeOSSALifetime::computeCanonicalLiveness () {
133
133
LLVM_DEBUG (llvm::dbgs () << " Computing canonical liveness from:\n " ;
134
134
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 ()));
136
145
// Only the first level of reborrows need to be consider. All nested inner
137
146
// adjacent reborrows and phis are encapsulated within their lifetimes.
138
147
SILPhiArgument *arg;
139
148
if ((arg = dyn_cast<SILPhiArgument>(getCurrentDef ())) && arg->isPhi ()) {
140
149
visitInnerAdjacentPhis (arg, [&](SILArgument *reborrow) {
141
- defUseWorklist. insert ( reborrow);
150
+ addDefToWorklist ( Def:: reborrow(reborrow) );
142
151
return true ;
143
152
});
144
153
}
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 ();
146
158
LLVM_DEBUG (llvm::dbgs () << " Uses of value:\n " ;
147
159
value->print (llvm::dbgs ()));
148
160
@@ -153,11 +165,20 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
153
165
auto *user = use->getUser ();
154
166
// Recurse through copies.
155
167
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
+ }
157
178
continue ;
158
179
}
159
180
if (auto *bfi = dyn_cast<BorrowedFromInst>(user)) {
160
- defUseWorklist. insert ( bfi);
181
+ addDefToWorklist ( Def::borrowedFrom ( bfi) );
161
182
continue ;
162
183
}
163
184
// Handle debug_value instructions separately.
@@ -244,7 +265,7 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
244
265
// This branch reborrows a guaranteed phi whose lifetime is dependent on
245
266
// currentDef. Uses of the reborrowing phi extend liveness.
246
267
auto *reborrow = PhiOperand (use).getValue ();
247
- defUseWorklist. insert ( reborrow);
268
+ addDefToWorklist ( Def:: reborrow(reborrow) );
248
269
break ;
249
270
}
250
271
}
@@ -1148,20 +1169,17 @@ void CanonicalizeOSSALifetime::rewriteCopies(
1148
1169
SmallVectorImpl<DestroyValueInst *> const &newDestroys) {
1149
1170
assert (getCurrentDef ()->getOwnershipKind () == OwnershipKind::Owned);
1150
1171
1172
+ // Shadow discoveredDefs in order to constrain its uses.
1173
+ const auto &discoveredDefs = this ->discoveredDefs ;
1174
+
1151
1175
InstructionSetVector instsToDelete (getCurrentDef ()->getFunction ());
1152
- defUseWorklist.clear ();
1153
1176
1154
1177
// Visit each operand in the def-use chain.
1155
1178
//
1156
1179
// Return true if the operand can use the current definition. Return false if
1157
1180
// it requires a copy.
1158
1181
auto visitUse = [&](Operand *use) {
1159
1182
auto *user = use->getUser ();
1160
- // Recurse through copies.
1161
- if (auto *copy = dyn_cast<CopyValueInst>(user)) {
1162
- defUseWorklist.insert (copy);
1163
- return true ;
1164
- }
1165
1183
if (destroys.contains (user)) {
1166
1184
auto *destroy = cast<DestroyValueInst>(user);
1167
1185
// If this destroy was marked as a final destroy, ignore it; otherwise,
@@ -1195,37 +1213,54 @@ void CanonicalizeOSSALifetime::rewriteCopies(
1195
1213
};
1196
1214
1197
1215
// 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)) {
1215
1230
copyLiveUse (use, getCallbacks ());
1216
1231
}
1217
1232
}
1233
+ break ;
1218
1234
}
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
+ }
1227
1249
}
1228
1250
}
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
+ }
1229
1264
}
1230
1265
}
1231
1266
assert (!consumes.hasUnclaimedConsumes ());
0 commit comments