Speed up Value::isUsedInBasicBlock() for long use lists.

This is expanding Ben's original heuristic for short basic blocks to
also work for longer basic blocks and huge use lists.

Scan the basic block and the use list in parallel, terminating the
search when the shorter list ends. In almost all cases, either the basic
block or the use list is short, and the function returns quickly.

In one crazy test case with very long use chains, CodeGenPrepare runs
400x faster. When compiling ARMDisassembler.cpp it is 5x faster.

<rdar://problem/13840497>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181851 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jakob Stoklund Olesen 2013-05-14 23:45:56 +00:00
parent da2ed458b4
commit a88d974ce2

View File

@ -112,21 +112,20 @@ bool Value::hasNUsesOrMore(unsigned N) const {
/// isUsedInBasicBlock - Return true if this value is used in the specified
/// basic block.
bool Value::isUsedInBasicBlock(const BasicBlock *BB) const {
// Start by scanning over the instructions looking for a use before we start
// the expensive use iteration.
unsigned MaxBlockSize = 3;
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
if (std::find(I->op_begin(), I->op_end(), this) != I->op_end())
// This can be computed either by scanning the instructions in BB, or by
// scanning the use list of this Value. Both lists can be very long, but
// usually one is quite short.
//
// Scan both lists simultaneously until one is exhausted. This limits the
// search to the shorter list.
BasicBlock::const_iterator BI = BB->begin(), BE = BB->end();
const_use_iterator UI = use_begin(), UE = use_end();
for (; BI != BE && UI != UE; ++BI, ++UI) {
// Scan basic block: Check if this Value is used by the instruction at BI.
if (std::find(BI->op_begin(), BI->op_end(), this) != BI->op_end())
return true;
if (--MaxBlockSize == 0) // If the block is larger fall back to use_iterator
break;
}
if (MaxBlockSize != 0) // We scanned the entire block and found no use.
return false;
for (const_use_iterator I = use_begin(), E = use_end(); I != E; ++I) {
const Instruction *User = dyn_cast<Instruction>(*I);
// Scan use list: Check if the use at UI is in BB.
const Instruction *User = dyn_cast<Instruction>(*UI);
if (User && User->getParent() == BB)
return true;
}