Further cleanup manipulation of widenable branches [NFC]

This is a follow on to aaea24802b.  In post commit discussion, Artur and I realized we could cleanup the code using Uses; this patch does so.
This commit is contained in:
Philip Reames
2019-11-21 15:06:01 -08:00
parent f471eb8e99
commit 8293f74345
3 changed files with 70 additions and 40 deletions

View File

@@ -15,6 +15,7 @@
namespace llvm {
class BasicBlock;
class Use;
class User;
class Value;
@@ -43,6 +44,11 @@ bool parseWidenableBranch(const User *U, Value *&Condition,
Value *&WidenableCondition, BasicBlock *&IfTrueBB,
BasicBlock *&IfFalseBB);
/// Analgous to the above, but return the Uses so that that they can be
/// modified. Unlike previous version, Condition is optional and may be null.
bool parseWidenableBranch(User *U, Use *&Cond, Use *&WC, BasicBlock *&IfTrueBB,
BasicBlock *&IfFalseBB);
} // llvm
#endif // LLVM_ANALYSIS_GUARDUTILS_H

View File

@@ -44,11 +44,35 @@ bool llvm::isGuardAsWidenableBranch(const User *U) {
bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
Value *&WidenableCondition,
BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
if (match(U, m_Br(m_Intrinsic<Intrinsic::experimental_widenable_condition>(),
IfTrueBB, IfFalseBB)) &&
cast<BranchInst>(U)->getCondition()->hasOneUse()) {
WidenableCondition = cast<BranchInst>(U)->getCondition();
Condition = ConstantInt::getTrue(IfTrueBB->getContext());
Use *C, *WC;
if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
if (C)
Condition = C->get();
else
Condition = ConstantInt::getTrue(IfTrueBB->getContext());
WidenableCondition = WC->get();
return true;
}
return false;
}
bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
auto *BI = dyn_cast<BranchInst>(U);
if (!BI || !BI->isConditional())
return false;
auto *Cond = BI->getCondition();
if (!Cond->hasOneUse())
return false;
IfTrueBB = BI->getSuccessor(0);
IfFalseBB = BI->getSuccessor(1);
if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
WC = &BI->getOperandUse(0);
C = nullptr;
return true;
}
@@ -57,19 +81,23 @@ bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
// 2) br (i1 (and WC(), B)), label %IfTrue, label %IfFalse
// We do not check for more generalized and trees as we should canonicalize
// to the form above in instcombine. (TODO)
if (!match(U, m_Br(m_And(m_Value(Condition), m_Value(WidenableCondition)),
IfTrueBB, IfFalseBB)))
Value *A, *B;
if (!match(Cond, m_And(m_Value(A), m_Value(B))))
return false;
if (!match(WidenableCondition,
m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
if (!match(Condition,
m_Intrinsic<Intrinsic::experimental_widenable_condition>()))
return false;
std::swap(Condition, WidenableCondition);
auto *And = cast<Instruction>(Cond);
if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
A->hasOneUse()) {
WC = &And->getOperandUse(0);
C = &And->getOperandUse(1);
return true;
}
// For the branch to be (easily) widenable, it must not correlate with other
// branches. Thus, the widenable condition must have a single use.
return (WidenableCondition->hasOneUse() &&
cast<BranchInst>(U)->getCondition()->hasOneUse());
if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
B->hasOneUse()) {
WC = &And->getOperandUse(1);
C = &And->getOperandUse(0);
return true;
}
return false;
}

View File

@@ -87,23 +87,20 @@ void llvm::widenWidenableBranch(BranchInst *WidenableBR, Value *NewCond) {
// condition, but that doesn't match the pattern parseWidenableBranch expects
// so we have to be more sophisticated.
if (match(WidenableBR->getCondition(),
m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
Use *C, *WC;
BasicBlock *IfTrueBB, *IfFalseBB;
parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);
if (!C) {
// br (wc()), ... form
IRBuilder<> B(WidenableBR);
WidenableBR->setCondition(B.CreateAnd(NewCond,
WidenableBR->getCondition()));
WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));
} else {
// br (wc & C), ... form
IRBuilder<> B(WidenableBR);
C->set(B.CreateAnd(NewCond, C->get()));
Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());
// Condition is only guaranteed to dominate branch
WCAnd->moveBefore(WidenableBR);
IRBuilder<> B(WCAnd);
const bool Op0IsWC =
match(WCAnd->getOperand(0),
m_Intrinsic<Intrinsic::experimental_widenable_condition>());
const unsigned CondOpIdx = Op0IsWC ? 1 : 0;
Value *OldCond = WCAnd->getOperand(CondOpIdx);
NewCond = B.CreateAnd(NewCond, OldCond);
WCAnd->setOperand(CondOpIdx, NewCond);
WCAnd->moveBefore(WidenableBR);
}
assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");
}
@@ -111,20 +108,19 @@ void llvm::widenWidenableBranch(BranchInst *WidenableBR, Value *NewCond) {
void llvm::setWidenableBranchCond(BranchInst *WidenableBR, Value *NewCond) {
assert(isWidenableBranch(WidenableBR) && "precondition");
if (match(WidenableBR->getCondition(),
m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
Use *C, *WC;
BasicBlock *IfTrueBB, *IfFalseBB;
parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);
if (!C) {
// br (wc()), ... form
IRBuilder<> B(WidenableBR);
WidenableBR->setCondition(B.CreateAnd(NewCond,
WidenableBR->getCondition()));
WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));
} else {
// br (wc & C), ... form
Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());
// Condition is only guaranteed to dominate branch
WCAnd->moveBefore(WidenableBR);
const bool Op0IsWC =
match(WCAnd->getOperand(0),
m_Intrinsic<Intrinsic::experimental_widenable_condition>());
const unsigned CondOpIdx = Op0IsWC ? 1 : 0;
WCAnd->setOperand(CondOpIdx, NewCond);
C->set(NewCond);
}
assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");
}