|
22 | 22 | /// ensuring that removing an instruction is not unnecessarily expensive and
|
23 | 23 | /// that only valid instructions are removed from the list.
|
24 | 24 | ///
|
| 25 | +/// Additionally, SILInstructionWorklist provides conveniences for simple |
| 26 | +/// instruction modifications and ensuring that the appropriate instructions |
| 27 | +/// will be visited accordingly. For example, if provides a method for |
| 28 | +/// replacing an operation which has already been removed with a new instruction |
| 29 | +/// determined by a SILInstructionVisitor. |
| 30 | +/// |
25 | 31 | //===----------------------------------------------------------------------===//
|
26 | 32 |
|
27 | 33 | #include "swift/Basic/BlotSetVector.h"
|
28 | 34 | #include "swift/SIL/SILInstruction.h"
|
29 | 35 | #include "swift/SIL/SILValue.h"
|
| 36 | +#include "swift/SILOptimizer/Utils/Local.h" |
30 | 37 | #include "llvm/ADT/DenseMap.h"
|
31 | 38 | #include "llvm/ADT/SmallVector.h"
|
32 | 39 |
|
@@ -126,6 +133,171 @@ class SILInstructionWorklist : SILInstructionWorklistBase {
|
126 | 133 | // Do an explicit clear, shrinking the storage if needed.
|
127 | 134 | worklist.clear();
|
128 | 135 | }
|
| 136 | + |
| 137 | + /// Find usages of \p I and replace them with usages of \p Result. |
| 138 | + /// |
| 139 | + /// Intended to be called during visitation after \p I has been removed from |
| 140 | + /// the worklist. |
| 141 | + /// |
| 142 | + /// \p I the instruction whose usages will be replaced |
| 143 | + /// \p Result the instruction whose usages will replace \p I |
| 144 | + bool replaceInstructionWithInstruction( |
| 145 | + SILInstruction *I, |
| 146 | + SILInstruction *Result |
| 147 | +#ifndef NDNEBUG |
| 148 | + , std::string OrigI |
| 149 | +#endif |
| 150 | + ) { |
| 151 | + if (Result != I) { |
| 152 | + assert(&*std::prev(SILBasicBlock::iterator(I)) == Result && |
| 153 | + "Expected new instruction inserted before existing instruction!"); |
| 154 | + |
| 155 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 156 | + stream << loggingName << ": Old = " << *I << '\n' |
| 157 | + << " " << " New = " << *Result << '\n'; |
| 158 | + }); |
| 159 | + |
| 160 | + // Everything uses the new instruction now. |
| 161 | + replaceInstUsesPairwiseWith(I, Result); |
| 162 | + |
| 163 | + // Push the new instruction and any users onto the worklist. |
| 164 | + add(Result); |
| 165 | + addUsersOfAllResultsToWorklist(Result); |
| 166 | + |
| 167 | + eraseInstFromFunction(*I); |
| 168 | + |
| 169 | + return true; |
| 170 | + } else { |
| 171 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 172 | + stream << loggingName << ": Mod = " << OrigI << '\n' |
| 173 | + << " " << " New = " << *I << '\n'; |
| 174 | + }); |
| 175 | + |
| 176 | + // If the instruction was modified, it's possible that it is now dead. |
| 177 | + // if so, remove it. |
| 178 | + if (isInstructionTriviallyDead(I)) { |
| 179 | + eraseInstFromFunction(*I); |
| 180 | + } else { |
| 181 | + add(I); |
| 182 | + addUsersOfAllResultsToWorklist(I); |
| 183 | + } |
| 184 | + return false; |
| 185 | + } |
| 186 | + } |
| 187 | + |
| 188 | + // Insert the instruction New before instruction Old in Old's parent BB. Add |
| 189 | + // New to the worklist. |
| 190 | + SILInstruction *insertNewInstBefore(SILInstruction *New, SILInstruction &Old) { |
| 191 | + assert(New && New->getParent() == nullptr && |
| 192 | + "New instruction already inserted into a basic block!"); |
| 193 | + SILBasicBlock *BB = Old.getParent(); |
| 194 | + BB->insert(&Old, New); // Insert inst |
| 195 | + add(New); |
| 196 | + return New; |
| 197 | + } |
| 198 | + |
| 199 | + // This method is to be used when an instruction is found to be dead, |
| 200 | + // replaceable with another preexisting expression. Here we add all uses of I |
| 201 | + // to the worklist, and replace all uses of I with the new value. |
| 202 | + void replaceInstUsesWith(SingleValueInstruction &I, ValueBase *V) { |
| 203 | + addUsersToWorklist(&I); // Add all modified instrs to worklist. |
| 204 | + |
| 205 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 206 | + stream << loggingName << ": Replacing " << I << '\n' |
| 207 | + << " " << " with " << *V << '\n'; |
| 208 | + }); |
| 209 | + |
| 210 | + I.replaceAllUsesWith(V); |
| 211 | + } |
| 212 | + |
| 213 | + // This method is to be used when a value is found to be dead, |
| 214 | + // replaceable with another preexisting expression. Here we add all |
| 215 | + // uses of oldValue to the worklist, replace all uses of oldValue |
| 216 | + // with newValue. |
| 217 | + void replaceValueUsesWith(SILValue oldValue, SILValue newValue) { |
| 218 | + addUsersToWorklist(oldValue); // Add all modified instrs to worklist. |
| 219 | + |
| 220 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 221 | + stream << loggingName << ": Replacing " << oldValue << '\n' |
| 222 | + << " " << " with " << newValue << '\n'; |
| 223 | + }); |
| 224 | + |
| 225 | + oldValue->replaceAllUsesWith(newValue); |
| 226 | + } |
| 227 | + |
| 228 | + void replaceInstUsesPairwiseWith(SILInstruction *oldI, SILInstruction *newI) { |
| 229 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 230 | + stream << loggingName << ": Replacing " << *oldI << '\n' |
| 231 | + << " " << " with " << *newI << '\n'; |
| 232 | + }); |
| 233 | + |
| 234 | + auto oldResults = oldI->getResults(); |
| 235 | + auto newResults = newI->getResults(); |
| 236 | + assert(oldResults.size() == newResults.size()); |
| 237 | + for (auto i : indices(oldResults)) { |
| 238 | + // Add all modified instrs to worklist. |
| 239 | + addUsersToWorklist(oldResults[i]); |
| 240 | + |
| 241 | + oldResults[i]->replaceAllUsesWith(newResults[i]); |
| 242 | + } |
| 243 | + } |
| 244 | + |
| 245 | + // Some instructions can never be "trivially dead" due to side effects or |
| 246 | + // producing a void value. In those cases visit methods should use this |
| 247 | + // method to delete the given instruction and upon completion of their |
| 248 | + // peephole return the value returned by this method. |
| 249 | + void eraseInstFromFunction(SILInstruction &I, |
| 250 | + SILBasicBlock::iterator &InstIter, |
| 251 | + bool AddOperandsToWorklist = true) { |
| 252 | + // Delete any debug users first. |
| 253 | + for (auto result : I.getResults()) { |
| 254 | + while (!result->use_empty()) { |
| 255 | + auto *user = result->use_begin()->getUser(); |
| 256 | + assert(user->isDebugInstruction()); |
| 257 | + if (InstIter == user->getIterator()) |
| 258 | + ++InstIter; |
| 259 | + erase(user); |
| 260 | + user->eraseFromParent(); |
| 261 | + } |
| 262 | + } |
| 263 | + if (InstIter == I.getIterator()) |
| 264 | + ++InstIter; |
| 265 | + |
| 266 | + eraseSingleInstFromFunction(I, AddOperandsToWorklist); |
| 267 | + } |
| 268 | + |
| 269 | + void eraseInstFromFunction(SILInstruction &I, |
| 270 | + bool AddOperandsToWorklist = true) { |
| 271 | + SILBasicBlock::iterator nullIter; |
| 272 | + return eraseInstFromFunction(I, nullIter, AddOperandsToWorklist); |
| 273 | + } |
| 274 | + |
| 275 | + void eraseSingleInstFromFunction( |
| 276 | + SILInstruction &I, |
| 277 | + bool AddOperandsToWorklist) { |
| 278 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 279 | + stream << loggingName << ": ERASE " << I << '\n'; |
| 280 | + }); |
| 281 | + |
| 282 | + assert(!I.hasUsesOfAnyResult() && "Cannot erase instruction that is used!"); |
| 283 | + |
| 284 | + // Make sure that we reprocess all operands now that we reduced their |
| 285 | + // use counts. |
| 286 | + if (I.getNumOperands() < 8 && AddOperandsToWorklist) { |
| 287 | + for (auto &OpI : I.getAllOperands()) { |
| 288 | + if (auto *Op = OpI.get()->getDefiningInstruction()) { |
| 289 | + withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) { |
| 290 | + stream << loggingName << ": add op " << *Op << '\n' |
| 291 | + << " from erased inst to worklist\n"; |
| 292 | + }); |
| 293 | + add(Op); |
| 294 | + } |
| 295 | + } |
| 296 | + } |
| 297 | + erase(&I); |
| 298 | + I.eraseFromParent(); |
| 299 | + } |
| 300 | + |
129 | 301 | };
|
130 | 302 |
|
131 | 303 | // TODO: This name is somewhat unpleasant. Once the type is templated over its
|
|
0 commit comments