Skip to content

Commit

Permalink
Add iterator range variants of isGuaranteedToTransferExecutionToSucce…
Browse files Browse the repository at this point in the history
…ssor [mostly-nfc]

This factors out utilities for scanning a bounded block of instructions since we have this code repeated in a bunch of places.  The change to InlineFunction isn't strictly NFC as the limit mechanism there didn't handle debug instructions correctly.
  • Loading branch information
preames committed Oct 8, 2021
1 parent 75b3169 commit d694dd0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 37 deletions.
12 changes: 12 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Expand Up @@ -574,6 +574,18 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6;
/// instruction variant of this function.
bool isGuaranteedToTransferExecutionToSuccessor(const BasicBlock *BB);

/// Return true if every instruction in the range (Begin, End) is
/// guaranteed to transfer execution to its static successor. \p ScanLimit
/// bounds the search to avoid scanning huge blocks.
bool isGuaranteedToTransferExecutionToSuccessor(
BasicBlock::const_iterator Begin, BasicBlock::const_iterator End,
unsigned ScanLimit = 32);

/// Same as previous, but with range expressed via iterator_range.
bool isGuaranteedToTransferExecutionToSuccessor(
iterator_range<BasicBlock::const_iterator> Range,
unsigned ScanLimit = 32);

/// Return true if this function can prove that the instruction I
/// is executed for every iteration of the loop L.
///
Expand Down
31 changes: 6 additions & 25 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Expand Up @@ -6631,39 +6631,20 @@ ScalarEvolution::getDefiningScopeBound(ArrayRef<const SCEV *> Ops) {
return Bound ? Bound : &*F.getEntryBlock().begin();
}


static bool
isGuaranteedToTransferExecutionToSuccessor(BasicBlock::const_iterator Begin,
BasicBlock::const_iterator End) {
// Limit number of instructions we look at, to avoid scanning through large
// blocks. The current limit is chosen arbitrarily.
unsigned ScanLimit = 32;
for (const Instruction &I : make_range(Begin, End)) {
if (isa<DbgInfoIntrinsic>(I))
continue;
if (--ScanLimit == 0)
return false;

if (!isGuaranteedToTransferExecutionToSuccessor(&I))
return false;
}
return true;
}

bool ScalarEvolution::isGuaranteedToTransferExecutionTo(const Instruction *A,
const Instruction *B) {
if (A->getParent() == B->getParent() &&
::isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
B->getIterator()))
isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
B->getIterator()))
return true;

auto *BLoop = LI.getLoopFor(B->getParent());
if (BLoop && BLoop->getHeader() == B->getParent() &&
BLoop->getLoopPreheader() == A->getParent() &&
::isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
A->getParent()->end()) &&
::isGuaranteedToTransferExecutionToSuccessor(B->getParent()->begin(),
B->getIterator()))
isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
A->getParent()->end()) &&
isGuaranteedToTransferExecutionToSuccessor(B->getParent()->begin(),
B->getIterator()))
return true;
return false;
}
Expand Down
28 changes: 24 additions & 4 deletions llvm/lib/Analysis/ValueTracking.cpp
Expand Up @@ -542,10 +542,9 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
// We limit the scan distance between the assume and its context instruction
// to avoid a compile-time explosion. This limit is chosen arbitrarily, so
// it can be adjusted if needed (could be turned into a cl::opt).
unsigned ScanLimit = 15;
for (BasicBlock::const_iterator I(CxtI), IE(Inv); I != IE; ++I)
if (!isGuaranteedToTransferExecutionToSuccessor(&*I) || --ScanLimit == 0)
return false;
auto Range = make_range(CxtI->getIterator(), Inv->getIterator());
if (!isGuaranteedToTransferExecutionToSuccessor(Range, 15))
return false;

return !isEphemeralValueOf(Inv, CxtI);
}
Expand Down Expand Up @@ -5331,6 +5330,27 @@ bool llvm::isGuaranteedToTransferExecutionToSuccessor(const BasicBlock *BB) {
return true;
}

bool llvm::isGuaranteedToTransferExecutionToSuccessor(
BasicBlock::const_iterator Begin, BasicBlock::const_iterator End,
unsigned ScanLimit) {
return isGuaranteedToTransferExecutionToSuccessor(make_range(Begin, End),
ScanLimit);
}

bool llvm::isGuaranteedToTransferExecutionToSuccessor(
iterator_range<BasicBlock::const_iterator> Range, unsigned ScanLimit) {
assert(ScanLimit && "scan limit must be non-zero");
for (const Instruction &I : Range) {
if (isa<DbgInfoIntrinsic>(I))
continue;
if (--ScanLimit == 0)
return false;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
return false;
}
return true;
}

bool llvm::isGuaranteedToExecuteForEveryIteration(const Instruction *I,
const Loop *L) {
// The loop header is guaranteed to be executed for every iteration.
Expand Down
10 changes: 2 additions & 8 deletions llvm/lib/Transforms/Utils/InlineFunction.cpp
Expand Up @@ -1177,14 +1177,8 @@ static bool MayContainThrowingOrExitingCall(Instruction *Begin,

assert(Begin->getParent() == End->getParent() &&
"Expected to be in same basic block!");
unsigned NumInstChecked = 0;
// Check that all instructions in the range [Begin, End) are guaranteed to
// transfer execution to successor.
for (auto &I : make_range(Begin->getIterator(), End->getIterator()))
if (NumInstChecked++ > InlinerAttributeWindow ||
!isGuaranteedToTransferExecutionToSuccessor(&I))
return true;
return false;
return !llvm::isGuaranteedToTransferExecutionToSuccessor(
Begin->getIterator(), End->getIterator(), InlinerAttributeWindow + 1);
}

static AttrBuilder IdentifyValidAttributes(CallBase &CB) {
Expand Down

0 comments on commit d694dd0

Please sign in to comment.