Skip to content

Commit ec86a2b

Browse files
committed
[InstCombine] Collect users iteratively
This is an NFC patch to collect (indirect) users of an alloca non-recursively instead.
1 parent dea5aa7 commit ec86a2b

File tree

1 file changed

+56
-46
lines changed

1 file changed

+56
-46
lines changed

llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "InstCombineInternal.h"
1414
#include "llvm/ADT/MapVector.h"
1515
#include "llvm/ADT/SetOperations.h"
16+
#include "llvm/ADT/SetVector.h"
1617
#include "llvm/ADT/SmallString.h"
1718
#include "llvm/ADT/Statistic.h"
1819
#include "llvm/Analysis/AliasAnalysis.h"
@@ -24,6 +25,7 @@
2425
#include "llvm/IR/PatternMatch.h"
2526
#include "llvm/Transforms/InstCombine/InstCombiner.h"
2627
#include "llvm/Transforms/Utils/Local.h"
28+
#include <stack>
2729
using namespace llvm;
2830
using namespace PatternMatch;
2931

@@ -244,11 +246,10 @@ class PointerReplacer {
244246
void replacePointer(Value *V);
245247

246248
private:
247-
bool collectUsersRecursive(Instruction &I);
248249
void replace(Instruction *I);
249250
Value *getReplacement(Value *I);
250251
bool isAvailable(Instruction *I) const {
251-
return I == &Root || Worklist.contains(I);
252+
return I == &Root || UsersToReplace.contains(I);
252253
}
253254

254255
bool isEqualOrValidAddrSpaceCast(const Instruction *I,
@@ -260,8 +261,7 @@ class PointerReplacer {
260261
return (FromAS == ToAS) || IC.isValidAddrSpaceCast(FromAS, ToAS);
261262
}
262263

263-
SmallPtrSet<Instruction *, 32> ValuesToRevisit;
264-
SmallSetVector<Instruction *, 4> Worklist;
264+
SmallSetVector<Instruction *, 4> UsersToReplace;
265265
MapVector<Value *, Value *> WorkMap;
266266
InstCombinerImpl &IC;
267267
Instruction &Root;
@@ -270,77 +270,87 @@ class PointerReplacer {
270270
} // end anonymous namespace
271271

272272
bool PointerReplacer::collectUsers() {
273-
if (!collectUsersRecursive(Root))
274-
return false;
273+
std::stack<User *> Worklist;
274+
SmallSetVector<Instruction *, 4> ValuesToRevisit;
275275

276-
// Ensure that all outstanding (indirect) users of I
277-
// are inserted into the Worklist. Return false
278-
// otherwise.
279-
return llvm::set_is_subset(ValuesToRevisit, Worklist);
280-
}
276+
auto PushUsersToWorklist = [&](Instruction *Inst) {
277+
for (auto *U : Inst->users())
278+
if (isa<Instruction>(U) && !isAvailable(cast<Instruction>(U)))
279+
Worklist.push(U);
280+
};
281281

282-
bool PointerReplacer::collectUsersRecursive(Instruction &I) {
283-
for (auto *U : I.users()) {
284-
auto *Inst = cast<Instruction>(&*U);
282+
PushUsersToWorklist(&Root);
283+
while (!Worklist.empty()) {
284+
auto *Inst = dyn_cast<Instruction>(Worklist.top());
285+
Worklist.pop();
286+
if (!Inst)
287+
return false;
288+
if (isAvailable(Inst))
289+
continue;
285290
if (auto *Load = dyn_cast<LoadInst>(Inst)) {
286291
if (Load->isVolatile())
287292
return false;
288-
Worklist.insert(Load);
293+
UsersToReplace.insert(Load);
289294
} else if (auto *PHI = dyn_cast<PHINode>(Inst)) {
290295
// All incoming values must be instructions for replacability
291296
if (any_of(PHI->incoming_values(),
292297
[](Value *V) { return !isa<Instruction>(V); }))
293298
return false;
294299

295-
// If at least one incoming value of the PHI is not in Worklist,
296-
// store the PHI for revisiting and skip this iteration of the
297-
// loop.
298-
if (any_of(PHI->incoming_values(), [this](Value *V) {
299-
return !isAvailable(cast<Instruction>(V));
300-
})) {
301-
ValuesToRevisit.insert(Inst);
300+
// If all incoming values are available, mark this PHI as
301+
// replacable and push it's users into the worklist.
302+
if (all_of(PHI->incoming_values(),
303+
[&](Value *V) { return isAvailable(cast<Instruction>(V)); })) {
304+
UsersToReplace.insert(PHI);
305+
PushUsersToWorklist(PHI);
302306
continue;
303307
}
304308

305-
Worklist.insert(PHI);
306-
if (!collectUsersRecursive(*PHI))
307-
return false;
308-
} else if (auto *SI = dyn_cast<SelectInst>(Inst)) {
309-
if (!isa<Instruction>(SI->getTrueValue()) ||
310-
!isa<Instruction>(SI->getFalseValue()))
309+
// Not all incoming values are available. If this PHI was already
310+
// visited prior to this iteration, return false.
311+
if (ValuesToRevisit.contains(PHI))
311312
return false;
312313

313-
if (!isAvailable(cast<Instruction>(SI->getTrueValue())) ||
314-
!isAvailable(cast<Instruction>(SI->getFalseValue()))) {
315-
ValuesToRevisit.insert(Inst);
316-
continue;
314+
// Revisit PHI, after all it's incoming values have been visited.
315+
Worklist.push(PHI);
316+
ValuesToRevisit.insert(PHI);
317+
for (unsigned Idx = 0; Idx < PHI->getNumIncomingValues(); ++Idx) {
318+
auto *IncomingValue = cast<Instruction>(PHI->getIncomingValue(Idx));
319+
if (UsersToReplace.contains(IncomingValue))
320+
continue;
321+
if (ValuesToRevisit.contains(IncomingValue))
322+
return false;
323+
ValuesToRevisit.insert(IncomingValue);
324+
Worklist.push(IncomingValue);
317325
}
318-
Worklist.insert(SI);
319-
if (!collectUsersRecursive(*SI))
320-
return false;
321-
} else if (isa<GetElementPtrInst>(Inst)) {
322-
Worklist.insert(Inst);
323-
if (!collectUsersRecursive(*Inst))
326+
} else if (auto *SI = dyn_cast<SelectInst>(Inst)) {
327+
auto *TrueInst = dyn_cast<Instruction>(SI->getTrueValue());
328+
auto *FalseInst = dyn_cast<Instruction>(SI->getFalseValue());
329+
if (!TrueInst || !FalseInst)
324330
return false;
331+
332+
UsersToReplace.insert(SI);
333+
PushUsersToWorklist(SI);
334+
} else if (auto *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
335+
UsersToReplace.insert(GEP);
336+
PushUsersToWorklist(GEP);
325337
} else if (auto *MI = dyn_cast<MemTransferInst>(Inst)) {
326338
if (MI->isVolatile())
327339
return false;
328-
Worklist.insert(Inst);
340+
UsersToReplace.insert(Inst);
329341
} else if (isEqualOrValidAddrSpaceCast(Inst, FromAS)) {
330-
Worklist.insert(Inst);
331-
if (!collectUsersRecursive(*Inst))
332-
return false;
342+
UsersToReplace.insert(Inst);
343+
PushUsersToWorklist(Inst);
333344
} else if (Inst->isLifetimeStartOrEnd()) {
334345
continue;
335346
} else {
336347
// TODO: For arbitrary uses with address space mismatches, should we check
337348
// if we can introduce a valid addrspacecast?
338-
LLVM_DEBUG(dbgs() << "Cannot handle pointer user: " << *U << '\n');
349+
LLVM_DEBUG(dbgs() << "Cannot handle pointer user: " << *Inst << '\n');
339350
return false;
340351
}
341352
}
342-
343-
return true;
353+
return llvm::set_is_subset(ValuesToRevisit, UsersToReplace);
344354
}
345355

346356
Value *PointerReplacer::getReplacement(Value *V) { return WorkMap.lookup(V); }
@@ -443,7 +453,7 @@ void PointerReplacer::replacePointer(Value *V) {
443453
#endif
444454
WorkMap[&Root] = V;
445455

446-
for (Instruction *Workitem : Worklist)
456+
for (Instruction *Workitem : UsersToReplace)
447457
replace(Workitem);
448458
}
449459

0 commit comments

Comments
 (0)