Skip to content

Commit

Permalink
[PatternMatch] Make m_Br more flexible, add matchers for BB values.
Browse files Browse the repository at this point in the history
Currently m_Br only takes references to BasicBlock*, which limits its
flexibility. For example, you have to declare a variable, even if you
ignore the result or you have to have additional checks to make sure the
matched BB matches an expected one.

This patch adds m_BasicBlock and m_SpecificBB matchers, which can be
used like the existing matchers for constants or values.

I also had a look at the existing uses and updated a few. IMO it makes
the code a bit more explicit.

Reviewers: spatel, craig.topper, RKSimon, majnemer, lebedev.ri

Reviewed By: lebedev.ri

Differential Revision: https://reviews.llvm.org/D68013

llvm-svn: 372885
  • Loading branch information
fhahn committed Sep 25, 2019
1 parent ae834ba commit 5c3bc3c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 19 deletions.
55 changes: 48 additions & 7 deletions llvm/include/llvm/IR/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ inline class_match<UndefValue> m_Undef() { return class_match<UndefValue>(); }
/// Match an arbitrary Constant and ignore it.
inline class_match<Constant> m_Constant() { return class_match<Constant>(); }

/// Match an arbitrary basic block value and ignore it.
inline class_match<BasicBlock> m_BasicBlock() {
return class_match<BasicBlock>();
}

/// Inverting matcher
template <typename Ty> struct match_unless {
Ty M;
Expand Down Expand Up @@ -563,6 +568,12 @@ inline bind_ty<Constant> m_Constant(Constant *&C) { return C; }
/// Match a ConstantFP, capturing the value if we match.
inline bind_ty<ConstantFP> m_ConstantFP(ConstantFP *&C) { return C; }

/// Match a basic block value, capturing it if we match.
inline bind_ty<BasicBlock> m_BasicBlock(BasicBlock *&V) { return V; }
inline bind_ty<const BasicBlock> m_BasicBlock(const BasicBlock *&V) {
return V;
}

/// Match a specified Value*.
struct specificval_ty {
const Value *Val;
Expand Down Expand Up @@ -656,6 +667,32 @@ inline specific_intval m_SpecificInt(uint64_t V) { return specific_intval(V); }
/// ConstantInts wider than 64-bits.
inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; }

/// Match a specified basic block value.
struct specific_bbval {
BasicBlock *Val;

specific_bbval(BasicBlock *Val) : Val(Val) {}

template <typename ITy> bool match(ITy *V) {
const auto *BB = dyn_cast<BasicBlock>(V);
return BB && BB == Val;
}
};

/// Match a specific basic block value.
inline specific_bbval m_SpecificBB(BasicBlock *BB) {
return specific_bbval(BB);
}

/// A commutative-friendly version of m_Specific().
inline deferredval_ty<BasicBlock> m_Deferred(BasicBlock *const &BB) {
return BB;
}
inline deferredval_ty<const BasicBlock>
m_Deferred(const BasicBlock *const &BB) {
return BB;
}

//===----------------------------------------------------------------------===//
// Matcher for any binary operator.
//
Expand Down Expand Up @@ -1345,19 +1382,23 @@ struct brc_match {

template <typename OpTy> bool match(OpTy *V) {
if (auto *BI = dyn_cast<BranchInst>(V))
if (BI->isConditional() && Cond.match(BI->getCondition())) {
T = BI->getSuccessor(0);
F = BI->getSuccessor(1);
return true;
}
if (BI->isConditional() && Cond.match(BI->getCondition()))
return T.match(BI->getSuccessor(0)) && F.match(BI->getSuccessor(1));
return false;
}
};

template <typename Cond_t>
inline brc_match<Cond_t, BasicBlock *&, BasicBlock *&>
inline brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>
m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {
return brc_match<Cond_t, BasicBlock *&, BasicBlock *&>(C, T, F);
return brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>(
C, m_BasicBlock(T), m_BasicBlock(F));
}

template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
inline brc_match<Cond_t, TrueBlock_t, FalseBlock_t>
m_Br(const Cond_t &C, const TrueBlock_t &T, const FalseBlock_t &F) {
return brc_match<Cond_t, TrueBlock_t, FalseBlock_t>(C, T, F);
}

//===----------------------------------------------------------------------===//
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/Analysis/ScalarEvolutionExpander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2105,11 +2105,10 @@ SCEVExpander::getRelatedExistingExpansion(const SCEV *S, const Instruction *At,
for (BasicBlock *BB : ExitingBlocks) {
ICmpInst::Predicate Pred;
Instruction *LHS, *RHS;
BasicBlock *TrueBB, *FalseBB;

if (!match(BB->getTerminator(),
m_Br(m_ICmp(Pred, m_Instruction(LHS), m_Instruction(RHS)),
TrueBB, FalseBB)))
m_BasicBlock(), m_BasicBlock())))
continue;

if (SE.getSCEV(LHS) == S && SE.DT.dominates(LHS, At))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,13 @@ static bool foldGuardedRotateToFunnelShift(Instruction &I) {
BasicBlock *GuardBB = Phi.getIncomingBlock(RotSrc == P1);
BasicBlock *RotBB = Phi.getIncomingBlock(RotSrc != P1);
Instruction *TermI = GuardBB->getTerminator();
BasicBlock *TrueBB, *FalseBB;
ICmpInst::Predicate Pred;
if (!match(TermI, m_Br(m_ICmp(Pred, m_Specific(RotAmt), m_ZeroInt()), TrueBB,
FalseBB)))
BasicBlock *PhiBB = Phi.getParent();
if (!match(TermI, m_Br(m_ICmp(Pred, m_Specific(RotAmt), m_ZeroInt()),
m_SpecificBB(PhiBB), m_SpecificBB(RotBB))))
return false;

BasicBlock *PhiBB = Phi.getParent();
if (Pred != CmpInst::ICMP_EQ || TrueBB != PhiBB || FalseBB != RotBB)
if (Pred != CmpInst::ICMP_EQ)
return false;

// We matched a variation of this IR pattern:
Expand Down
8 changes: 3 additions & 5 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2557,9 +2557,7 @@ Instruction *InstCombiner::visitReturnInst(ReturnInst &RI) {
Instruction *InstCombiner::visitBranchInst(BranchInst &BI) {
// Change br (not X), label True, label False to: br X, label False, True
Value *X = nullptr;
BasicBlock *TrueDest;
BasicBlock *FalseDest;
if (match(&BI, m_Br(m_Not(m_Value(X)), TrueDest, FalseDest)) &&
if (match(&BI, m_Br(m_Not(m_Value(X)), m_BasicBlock(), m_BasicBlock())) &&
!isa<Constant>(X)) {
// Swap Destinations and condition...
BI.setCondition(X);
Expand All @@ -2577,8 +2575,8 @@ Instruction *InstCombiner::visitBranchInst(BranchInst &BI) {

// Canonicalize, for example, icmp_ne -> icmp_eq or fcmp_one -> fcmp_oeq.
CmpInst::Predicate Pred;
if (match(&BI, m_Br(m_OneUse(m_Cmp(Pred, m_Value(), m_Value())), TrueDest,
FalseDest)) &&
if (match(&BI, m_Br(m_OneUse(m_Cmp(Pred, m_Value(), m_Value())),
m_BasicBlock(), m_BasicBlock())) &&
!isCanonicalPredicate(Pred)) {
// Swap destinations and condition.
CmpInst *Cond = cast<CmpInst>(BI.getCondition());
Expand Down
28 changes: 28 additions & 0 deletions llvm/unittests/IR/PatternMatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,34 @@ TEST_F(PatternMatchTest, FloatingPointFNeg) {
EXPECT_FALSE(match(V3, m_FNeg(m_Value(Match))));
}

TEST_F(PatternMatchTest, CondBranchTest) {
BasicBlock *TrueBB = BasicBlock::Create(Ctx, "TrueBB", F);
BasicBlock *FalseBB = BasicBlock::Create(Ctx, "FalseBB", F);
Value *Br1 = IRB.CreateCondBr(IRB.getTrue(), TrueBB, FalseBB);

EXPECT_TRUE(match(Br1, m_Br(m_Value(), m_BasicBlock(), m_BasicBlock())));

BasicBlock *A, *B;
EXPECT_TRUE(match(Br1, m_Br(m_Value(), m_BasicBlock(A), m_BasicBlock(B))));
EXPECT_EQ(TrueBB, A);
EXPECT_EQ(FalseBB, B);

EXPECT_FALSE(
match(Br1, m_Br(m_Value(), m_SpecificBB(FalseBB), m_BasicBlock())));
EXPECT_FALSE(
match(Br1, m_Br(m_Value(), m_BasicBlock(), m_SpecificBB(TrueBB))));
EXPECT_FALSE(
match(Br1, m_Br(m_Value(), m_SpecificBB(FalseBB), m_BasicBlock(TrueBB))));
EXPECT_TRUE(
match(Br1, m_Br(m_Value(), m_SpecificBB(TrueBB), m_BasicBlock(FalseBB))));

// Check we can use m_Deferred with branches.
EXPECT_FALSE(match(Br1, m_Br(m_Value(), m_BasicBlock(A), m_Deferred(A))));
Value *Br2 = IRB.CreateCondBr(IRB.getTrue(), TrueBB, TrueBB);
A = nullptr;
EXPECT_TRUE(match(Br2, m_Br(m_Value(), m_BasicBlock(A), m_Deferred(A))));
}

template <typename T> struct MutableConstTest : PatternMatchTest { };

typedef ::testing::Types<std::tuple<Value*, Instruction*>,
Expand Down

0 comments on commit 5c3bc3c

Please sign in to comment.