Skip to content

Commit ce37b93

Browse files
preamesmemfrob
authored andcommitted
[SCEV] Split isSCEVExprNeverPoison reasoning explicitly into scope and mustexecute parts [NFC]
Inspired by the needs to D111001 and D109845. The seperation of concerns also amakes it easier to reason about correctness and completeness.
1 parent c421a98 commit ce37b93

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

llvm/include/llvm/Analysis/ScalarEvolution.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,16 @@ class ScalarEvolution {
19201920
/// would trigger undefined behavior on overflow.
19211921
SCEV::NoWrapFlags getNoWrapFlagsFromUB(const Value *V);
19221922

1923+
/// If S trivially defines a scope (without needing to recurse through
1924+
/// operands), return the first instruction in it. Else, return nullptr.
1925+
/// (See scope definition rules associated with flag discussion above)
1926+
const Instruction *getDefinedScopeRoot(const SCEV *S);
1927+
1928+
/// Given two instructions in the same function, return true if we can
1929+
/// prove B must execute given A executes.
1930+
bool isGuaranteedToTransferExecutionTo(const Instruction *A,
1931+
const Instruction *B);
1932+
19231933
/// Return true if the SCEV corresponding to \p I is never poison. Proving
19241934
/// this is more complex than proving that just \p I is never poison, since
19251935
/// SCEV commons expressions across control flow, and you can have cases

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6569,6 +6569,31 @@ SCEV::NoWrapFlags ScalarEvolution::getNoWrapFlagsFromUB(const Value *V) {
65696569
return isSCEVExprNeverPoison(BinOp) ? Flags : SCEV::FlagAnyWrap;
65706570
}
65716571

6572+
const Instruction *ScalarEvolution::getDefinedScopeRoot(const SCEV *S) {
6573+
if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(S))
6574+
return &*AddRec->getLoop()->getHeader()->begin();
6575+
// TODO: add SCEVConstant and SCEVUnknown caxes here
6576+
return nullptr;
6577+
}
6578+
6579+
static bool
6580+
isGuaranteedToTransferExecutionToSuccessor(BasicBlock::const_iterator Begin,
6581+
BasicBlock::const_iterator End) {
6582+
return llvm::all_of( make_range(Begin, End), [](const Instruction &I) {
6583+
return isGuaranteedToTransferExecutionToSuccessor(&I);
6584+
});
6585+
}
6586+
6587+
bool ScalarEvolution::isGuaranteedToTransferExecutionTo(const Instruction *A,
6588+
const Instruction *B) {
6589+
if (A->getParent() == B->getParent() &&
6590+
::isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
6591+
B->getIterator()))
6592+
return true;
6593+
return false;
6594+
}
6595+
6596+
65726597
bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) {
65736598
// Here we check that I is in the header of the innermost loop containing I,
65746599
// since we only deal with instructions in the loop header. The actual loop we
@@ -6600,11 +6625,9 @@ bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) {
66006625
// TODO: We can do better here in some cases.
66016626
if (!isSCEVable(Op->getType()))
66026627
return false;
6603-
const SCEV *OpS = getSCEV(Op);
6604-
if (auto *AddRecS = dyn_cast<SCEVAddRecExpr>(OpS)) {
6605-
if (isGuaranteedToExecuteForEveryIteration(I, AddRecS->getLoop()))
6628+
if (auto *DefI = getDefinedScopeRoot(getSCEV(Op)))
6629+
if (isGuaranteedToTransferExecutionTo(DefI, I))
66066630
return true;
6607-
}
66086631
}
66096632
return false;
66106633
}

0 commit comments

Comments
 (0)