Skip to content

Commit

Permalink
[SCEV] Move canReuseInstruction() helper into SCEV (NFC)
Browse files Browse the repository at this point in the history
To allow reusing it in IndVars.

(cherry picked from commit 43dd1e8)
  • Loading branch information
nikic authored and tstellar committed Feb 21, 2024
1 parent 4223b22 commit dc0ed54
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 63 deletions.
7 changes: 7 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,13 @@ class ScalarEvolution {
void getPoisonGeneratingValues(SmallPtrSetImpl<const Value *> &Result,
const SCEV *S);

/// Check whether it is poison-safe to represent the expression S using the
/// instruction I. If such a replacement is performed, the poison flags of
/// instructions in DropPoisonGeneratingInsts must be dropped.
bool canReuseInstruction(
const SCEV *S, Instruction *I,
SmallVectorImpl<Instruction *> &DropPoisonGeneratingInsts);

class FoldID {
const SCEV *Op = nullptr;
const Type *Ty = nullptr;
Expand Down
62 changes: 62 additions & 0 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4184,6 +4184,68 @@ void ScalarEvolution::getPoisonGeneratingValues(
Result.insert(SU->getValue());
}

bool ScalarEvolution::canReuseInstruction(
const SCEV *S, Instruction *I,
SmallVectorImpl<Instruction *> &DropPoisonGeneratingInsts) {
// If the instruction cannot be poison, it's always safe to reuse.
if (programUndefinedIfPoison(I))
return true;

// Otherwise, it is possible that I is more poisonous that S. Collect the
// poison-contributors of S, and then check whether I has any additional
// poison-contributors. Poison that is contributed through poison-generating
// flags is handled by dropping those flags instead.
SmallPtrSet<const Value *, 8> PoisonVals;
getPoisonGeneratingValues(PoisonVals, S);

SmallVector<Value *> Worklist;
SmallPtrSet<Value *, 8> Visited;
Worklist.push_back(I);
while (!Worklist.empty()) {
Value *V = Worklist.pop_back_val();
if (!Visited.insert(V).second)
continue;

// Avoid walking large instruction graphs.
if (Visited.size() > 16)
return false;

// Either the value can't be poison, or the S would also be poison if it
// is.
if (PoisonVals.contains(V) || isGuaranteedNotToBePoison(V))
continue;

auto *I = dyn_cast<Instruction>(V);
if (!I)
return false;

// Disjoint or instructions are interpreted as adds by SCEV. However, we
// can't replace an arbitrary add with disjoint or, even if we drop the
// flag. We would need to convert the or into an add.
if (auto *PDI = dyn_cast<PossiblyDisjointInst>(I))
if (PDI->isDisjoint())
return false;

// FIXME: Ignore vscale, even though it technically could be poison. Do this
// because SCEV currently assumes it can't be poison. Remove this special
// case once we proper model when vscale can be poison.
if (auto *II = dyn_cast<IntrinsicInst>(I);
II && II->getIntrinsicID() == Intrinsic::vscale)
continue;

if (canCreatePoison(cast<Operator>(I), /*ConsiderFlagsAndMetadata*/ false))
return false;

// If the instruction can't create poison, we can recurse to its operands.
if (I->hasPoisonGeneratingFlagsOrMetadata())
DropPoisonGeneratingInsts.push_back(I);

for (Value *Op : I->operands())
Worklist.push_back(Op);
}
return true;
}

const SCEV *
ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind,
SmallVectorImpl<const SCEV *> &Ops) {
Expand Down
64 changes: 1 addition & 63 deletions llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,68 +1366,6 @@ Value *SCEVExpander::expandCodeFor(const SCEV *SH, Type *Ty) {
return V;
}

static bool
canReuseInstruction(ScalarEvolution &SE, const SCEV *S, Instruction *I,
SmallVectorImpl<Instruction *> &DropPoisonGeneratingInsts) {
// If the instruction cannot be poison, it's always safe to reuse.
if (programUndefinedIfPoison(I))
return true;

// Otherwise, it is possible that I is more poisonous that S. Collect the
// poison-contributors of S, and then check whether I has any additional
// poison-contributors. Poison that is contributed through poison-generating
// flags is handled by dropping those flags instead.
SmallPtrSet<const Value *, 8> PoisonVals;
SE.getPoisonGeneratingValues(PoisonVals, S);

SmallVector<Value *> Worklist;
SmallPtrSet<Value *, 8> Visited;
Worklist.push_back(I);
while (!Worklist.empty()) {
Value *V = Worklist.pop_back_val();
if (!Visited.insert(V).second)
continue;

// Avoid walking large instruction graphs.
if (Visited.size() > 16)
return false;

// Either the value can't be poison, or the S would also be poison if it
// is.
if (PoisonVals.contains(V) || isGuaranteedNotToBePoison(V))
continue;

auto *I = dyn_cast<Instruction>(V);
if (!I)
return false;

// Disjoint or instructions are interpreted as adds by SCEV. However, we
// can't replace an arbitrary add with disjoint or, even if we drop the
// flag. We would need to convert the or into an add.
if (auto *PDI = dyn_cast<PossiblyDisjointInst>(I))
if (PDI->isDisjoint())
return false;

// FIXME: Ignore vscale, even though it technically could be poison. Do this
// because SCEV currently assumes it can't be poison. Remove this special
// case once we proper model when vscale can be poison.
if (auto *II = dyn_cast<IntrinsicInst>(I);
II && II->getIntrinsicID() == Intrinsic::vscale)
continue;

if (canCreatePoison(cast<Operator>(I), /*ConsiderFlagsAndMetadata*/ false))
return false;

// If the instruction can't create poison, we can recurse to its operands.
if (I->hasPoisonGeneratingFlagsOrMetadata())
DropPoisonGeneratingInsts.push_back(I);

for (Value *Op : I->operands())
Worklist.push_back(Op);
}
return true;
}

Value *SCEVExpander::FindValueInExprValueMap(
const SCEV *S, const Instruction *InsertPt,
SmallVectorImpl<Instruction *> &DropPoisonGeneratingInsts) {
Expand Down Expand Up @@ -1455,7 +1393,7 @@ Value *SCEVExpander::FindValueInExprValueMap(
continue;

// Make sure reusing the instruction is poison-safe.
if (canReuseInstruction(SE, S, EntInst, DropPoisonGeneratingInsts))
if (SE.canReuseInstruction(S, EntInst, DropPoisonGeneratingInsts))
return V;
DropPoisonGeneratingInsts.clear();
}
Expand Down

0 comments on commit dc0ed54

Please sign in to comment.