[JumpThreading] Simplify getPredicateAt() based folding

It's sufficient to just fold the icmp to true/false here, and then
let constant terminator folding take care of the rest.

It should be noted that while replaceFoldableUses() may not replace
all uses of the icmp, at least the use in the terminator we're
working on is always replaceable, so terminator constant folding
should be reliably enabled as a subsequent step.
This commit is contained in:
Nikita Popov 2022-05-18 11:16:08 +02:00
parent 3eb2281bc0
commit 18c70a7bd9
1 changed files with 14 additions and 38 deletions

View File

@ -489,14 +489,15 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
// at the end of block. RAUW unconditionally replaces all uses
// including the guards/assumes themselves and the uses before the
// guard/assume.
static void replaceFoldableUses(Instruction *Cond, Value *ToVal) {
static void replaceFoldableUses(Instruction *Cond, Value *ToVal,
BasicBlock *KnownAtEndOfBB) {
assert(Cond->getType() == ToVal->getType());
auto *BB = Cond->getParent();
// We can unconditionally replace all uses in non-local blocks (i.e. uses
// strictly dominated by BB), since LVI information is true from the
// terminator of BB.
replaceNonLocalUsesWith(Cond, ToVal);
for (Instruction &I : reverse(*BB)) {
if (Cond->getParent() == KnownAtEndOfBB)
replaceNonLocalUsesWith(Cond, ToVal);
for (Instruction &I : reverse(*KnownAtEndOfBB)) {
// Reached the Cond whose uses we are trying to replace, so there are no
// more uses.
if (&I == Cond)
@ -1142,30 +1143,12 @@ bool JumpThreadingPass::processBlock(BasicBlock *BB) {
// If we're branching on a conditional, LVI might be able to determine
// it's value at the branch instruction. We only handle comparisons
// against a constant at this time.
// TODO: This should be extended to handle switches as well.
BranchInst *CondBr = dyn_cast<BranchInst>(BB->getTerminator());
Constant *CondConst = dyn_cast<Constant>(CondCmp->getOperand(1));
if (CondBr && CondConst) {
// We should have returned as soon as we turn a conditional branch to
// unconditional. Because its no longer interesting as far as jump
// threading is concerned.
assert(CondBr->isConditional() && "Threading on unconditional terminator");
if (Constant *CondConst = dyn_cast<Constant>(CondCmp->getOperand(1))) {
LazyValueInfo::Tristate Ret =
LVI->getPredicateAt(CondCmp->getPredicate(), CondCmp->getOperand(0),
CondConst, CondBr, /*UseBlockValue=*/false);
CondConst, BB->getTerminator(),
/*UseBlockValue=*/false);
if (Ret != LazyValueInfo::Unknown) {
unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0;
unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1;
BasicBlock *ToRemoveSucc = CondBr->getSuccessor(ToRemove);
ToRemoveSucc->removePredecessor(BB, true);
BranchInst *UncondBr =
BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr);
UncondBr->setDebugLoc(CondBr->getDebugLoc());
++NumFolds;
CondBr->eraseFromParent();
if (CondCmp->use_empty())
CondCmp->eraseFromParent();
// We can safely replace *some* uses of the CondInst if it has
// exactly one value as returned by LVI. RAUW is incorrect in the
// presence of guards and assumes, that have the `Cond` as the use. This
@ -1173,16 +1156,10 @@ bool JumpThreadingPass::processBlock(BasicBlock *BB) {
// at the end of block, but RAUW unconditionally replaces all uses
// including the guards/assumes themselves and the uses before the
// guard/assume.
else if (CondCmp->getParent() == BB) {
auto *CI = Ret == LazyValueInfo::True ?
ConstantInt::getTrue(CondCmp->getType()) :
ConstantInt::getFalse(CondCmp->getType());
replaceFoldableUses(CondCmp, CI);
}
DTU->applyUpdatesPermissive(
{{DominatorTree::Delete, BB, ToRemoveSucc}});
if (HasProfileData)
BPI->eraseBlock(BB);
auto *CI = Ret == LazyValueInfo::True ?
ConstantInt::getTrue(CondCmp->getType()) :
ConstantInt::getFalse(CondCmp->getType());
replaceFoldableUses(CondCmp, CI, BB);
return true;
}
@ -1761,9 +1738,8 @@ bool JumpThreadingPass::processThreadableEdges(Value *Cond, BasicBlock *BB,
// at the end of block, but RAUW unconditionally replaces all uses
// including the guards/assumes themselves and the uses before the
// guard/assume.
else if (OnlyVal && OnlyVal != MultipleVal &&
CondInst->getParent() == BB)
replaceFoldableUses(CondInst, OnlyVal);
else if (OnlyVal && OnlyVal != MultipleVal)
replaceFoldableUses(CondInst, OnlyVal, BB);
}
return true;
}