Skip to content

Commit bf8f266

Browse files
committed
[SIL] Extracted instruction methods from SILCombiner.
SILCombiner has a number of conveniences for inserting, replacing, and removing instructions that involve modifying a worklist as part of their behavior. Here, that functionality is added to the SILInstructionWorklist; in a subsequent commit it will be removed from SILCombiner which will then call through to SILInstructionWorklist.
1 parent 0b18006 commit bf8f266

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

include/swift/SIL/SILInstructionWorklist.h

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@
2222
/// ensuring that removing an instruction is not unnecessarily expensive and
2323
/// that only valid instructions are removed from the list.
2424
///
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+
///
2531
//===----------------------------------------------------------------------===//
2632

2733
#include "swift/Basic/BlotSetVector.h"
2834
#include "swift/SIL/SILInstruction.h"
2935
#include "swift/SIL/SILValue.h"
36+
#include "swift/SILOptimizer/Utils/Local.h"
3037
#include "llvm/ADT/DenseMap.h"
3138
#include "llvm/ADT/SmallVector.h"
3239

@@ -126,6 +133,171 @@ class SILInstructionWorklist : SILInstructionWorklistBase {
126133
// Do an explicit clear, shrinking the storage if needed.
127134
worklist.clear();
128135
}
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+
129301
};
130302

131303
// TODO: This name is somewhat unpleasant. Once the type is templated over its

0 commit comments

Comments
 (0)