Skip to content

Commit ea8fa6c

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 ea8fa6c

File tree

1 file changed

+58
-47
lines changed

1 file changed

+58
-47
lines changed

llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp

Lines changed: 58 additions & 47 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"
@@ -244,11 +245,10 @@ class PointerReplacer {
244245
void replacePointer(Value *V);
245246

246247
private:
247-
bool collectUsersRecursive(Instruction &I);
248248
void replace(Instruction *I);
249249
Value *getReplacement(Value *I);
250250
bool isAvailable(Instruction *I) const {
251-
return I == &Root || Worklist.contains(I);
251+
return I == &Root || UsersToReplace.contains(I);
252252
}
253253

254254
bool isEqualOrValidAddrSpaceCast(const Instruction *I,
@@ -260,8 +260,7 @@ class PointerReplacer {
260260
return (FromAS == ToAS) || IC.isValidAddrSpaceCast(FromAS, ToAS);
261261
}
262262

263-
SmallPtrSet<Instruction *, 32> ValuesToRevisit;
264-
SmallSetVector<Instruction *, 4> Worklist;
263+
SmallSetVector<Instruction *, 4> UsersToReplace;
265264
MapVector<Value *, Value *> WorkMap;
266265
InstCombinerImpl &IC;
267266
Instruction &Root;
@@ -270,77 +269,89 @@ class PointerReplacer {
270269
} // end anonymous namespace
271270

272271
bool PointerReplacer::collectUsers() {
273-
if (!collectUsersRecursive(Root))
274-
return false;
275-
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-
}
272+
SmallVector<Instruction *> Worklist;
273+
SmallSetVector<Instruction *, 4> ValuesToRevisit;
274+
275+
auto PushUsersToWorklist = [&](Instruction *Inst) {
276+
for (auto *U : Inst->users()) {
277+
if (auto *I = dyn_cast<Instruction>(U)) {
278+
if (!isAvailable(I) && !ValuesToRevisit.contains(I))
279+
Worklist.emplace_back(I);
280+
}
281+
}
282+
};
281283

282-
bool PointerReplacer::collectUsersRecursive(Instruction &I) {
283-
for (auto *U : I.users()) {
284-
auto *Inst = cast<Instruction>(&*U);
284+
PushUsersToWorklist(&Root);
285+
while (!Worklist.empty()) {
286+
auto *Inst = Worklist.pop_back_val();
287+
if (!Inst)
288+
return false;
289+
if (isAvailable(Inst))
290+
continue;
285291
if (auto *Load = dyn_cast<LoadInst>(Inst)) {
286292
if (Load->isVolatile())
287293
return false;
288-
Worklist.insert(Load);
294+
UsersToReplace.insert(Load);
289295
} else if (auto *PHI = dyn_cast<PHINode>(Inst)) {
290296
// All incoming values must be instructions for replacability
291297
if (any_of(PHI->incoming_values(),
292298
[](Value *V) { return !isa<Instruction>(V); }))
293299
return false;
294300

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);
301+
// If all incoming values are available, mark this PHI as
302+
// replacable and push it's users into the worklist.
303+
if (all_of(PHI->incoming_values(),
304+
[&](Value *V) { return isAvailable(cast<Instruction>(V)); })) {
305+
UsersToReplace.insert(PHI);
306+
PushUsersToWorklist(PHI);
302307
continue;
303308
}
304309

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()))
310+
// Not all incoming values are available. If this PHI was already
311+
// visited prior to this iteration, return false.
312+
if (!ValuesToRevisit.insert(PHI))
311313
return false;
312314

313-
if (!isAvailable(cast<Instruction>(SI->getTrueValue())) ||
314-
!isAvailable(cast<Instruction>(SI->getFalseValue()))) {
315-
ValuesToRevisit.insert(Inst);
316-
continue;
315+
// Push PHI back into the stack, followed by unavailable
316+
// incoming values.
317+
/// FIXME: test.ll (originating from rccl) is failing
318+
Worklist.emplace_back(PHI);
319+
for (unsigned Idx = 0; Idx < PHI->getNumIncomingValues(); ++Idx) {
320+
auto *IncomingValue = cast<Instruction>(PHI->getIncomingValue(Idx));
321+
if (UsersToReplace.contains(IncomingValue))
322+
continue;
323+
if (!ValuesToRevisit.insert(IncomingValue))
324+
return false;
325+
Worklist.emplace_back(IncomingValue);
317326
}
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))
327+
} else if (auto *SI = dyn_cast<SelectInst>(Inst)) {
328+
auto *TrueInst = dyn_cast<Instruction>(SI->getTrueValue());
329+
auto *FalseInst = dyn_cast<Instruction>(SI->getFalseValue());
330+
if (!TrueInst || !FalseInst)
324331
return false;
332+
333+
UsersToReplace.insert(SI);
334+
PushUsersToWorklist(SI);
335+
} else if (auto *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
336+
UsersToReplace.insert(GEP);
337+
PushUsersToWorklist(GEP);
325338
} else if (auto *MI = dyn_cast<MemTransferInst>(Inst)) {
326339
if (MI->isVolatile())
327340
return false;
328-
Worklist.insert(Inst);
341+
UsersToReplace.insert(Inst);
329342
} else if (isEqualOrValidAddrSpaceCast(Inst, FromAS)) {
330-
Worklist.insert(Inst);
331-
if (!collectUsersRecursive(*Inst))
332-
return false;
343+
UsersToReplace.insert(Inst);
344+
PushUsersToWorklist(Inst);
333345
} else if (Inst->isLifetimeStartOrEnd()) {
334346
continue;
335347
} else {
336348
// TODO: For arbitrary uses with address space mismatches, should we check
337349
// if we can introduce a valid addrspacecast?
338-
LLVM_DEBUG(dbgs() << "Cannot handle pointer user: " << *U << '\n');
350+
LLVM_DEBUG(dbgs() << "Cannot handle pointer user: " << *Inst << '\n');
339351
return false;
340352
}
341353
}
342-
343-
return true;
354+
return llvm::set_is_subset(ValuesToRevisit, UsersToReplace);
344355
}
345356

346357
Value *PointerReplacer::getReplacement(Value *V) { return WorkMap.lookup(V); }
@@ -443,7 +454,7 @@ void PointerReplacer::replacePointer(Value *V) {
443454
#endif
444455
WorkMap[&Root] = V;
445456

446-
for (Instruction *Workitem : Worklist)
457+
for (Instruction *Workitem : UsersToReplace)
447458
replace(Workitem);
448459
}
449460

0 commit comments

Comments
 (0)