diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index d4e355431a27a..8ae47fb556b25 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -1592,6 +1592,67 @@ m_FCmp(FCmpInst::Predicate &Pred, const LHS &L, const RHS &R) { return CmpClass_match(Pred, L, R); } +template +inline CmpClass_match +m_Cmp(const LHS &L, const RHS &R) { + CmpInst::Predicate Unused; + return CmpClass_match(Unused, L, R); +} + +template +inline CmpClass_match +m_ICmp(const LHS &L, const RHS &R) { + ICmpInst::Predicate Unused; + return CmpClass_match(Unused, L, R); +} + +template +inline CmpClass_match +m_FCmp(const LHS &L, const RHS &R) { + FCmpInst::Predicate Unused; + return CmpClass_match(Unused, L, R); +} + +// Same as CmpClass, but instead of saving Pred as out output variable, match a +// specific input pred for equality. +template +struct SpecificCmpClass_match { + const PredicateTy Predicate; + LHS_t L; + RHS_t R; + + SpecificCmpClass_match(PredicateTy Pred, const LHS_t &LHS, const RHS_t &RHS) + : Predicate(Pred), L(LHS), R(RHS) {} + + template bool match(OpTy *V) { + if (auto *I = dyn_cast(V)) + return I->getPredicate() == Predicate && L.match(I->getOperand(0)) && + R.match(I->getOperand(1)); + return false; + } +}; + +template +inline SpecificCmpClass_match +m_SpecificCmp(CmpInst::Predicate MatchPred, const LHS &L, const RHS &R) { + return SpecificCmpClass_match( + MatchPred, L, R); +} + +template +inline SpecificCmpClass_match +m_SpecificICmp(ICmpInst::Predicate MatchPred, const LHS &L, const RHS &R) { + return SpecificCmpClass_match( + MatchPred, L, R); +} + +template +inline SpecificCmpClass_match +m_SpecificFCmp(FCmpInst::Predicate MatchPred, const LHS &L, const RHS &R) { + return SpecificCmpClass_match( + MatchPred, L, R); +} + //===----------------------------------------------------------------------===// // Matchers for instructions with a given opcode and number of operands. // @@ -2617,6 +2678,14 @@ m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) { R); } +template +inline CmpClass_match +m_c_ICmp(const LHS &L, const RHS &R) { + ICmpInst::Predicate Unused; + return CmpClass_match(Unused, + L, R); +} + /// Matches a specific opcode with LHS and RHS in either order. template inline SpecificBinaryOp_match diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp index 9f91b4f3f9939..309fcc93996bc 100644 --- a/llvm/unittests/IR/PatternMatch.cpp +++ b/llvm/unittests/IR/PatternMatch.cpp @@ -2250,9 +2250,151 @@ TYPED_TEST(MutableConstTest, ICmp) { ICmpInst::Predicate MatchPred; EXPECT_TRUE(m_ICmp(MatchPred, m_Value(MatchL), m_Value(MatchR)) - .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); EXPECT_EQ(L, MatchL); EXPECT_EQ(R, MatchR); + + EXPECT_TRUE(m_Cmp(MatchPred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_TRUE(m_ICmp(m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_TRUE(m_Cmp(m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_FALSE(m_ICmp(m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_FALSE(m_Cmp(m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_TRUE(m_c_ICmp(m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_FALSE(m_c_ICmp(m_Specific(R), m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_TRUE(m_SpecificICmp(Pred, m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_TRUE(m_SpecificCmp(Pred, m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_FALSE(m_SpecificICmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + MatchL = nullptr; + MatchR = nullptr; + EXPECT_TRUE(m_SpecificICmp(Pred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = nullptr; + MatchR = nullptr; + EXPECT_TRUE(m_SpecificCmp(Pred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_FALSE(m_SpecificICmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_FALSE(m_SpecificICmp(ICmpInst::getInversePredicate(Pred), + m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(ICmpInst::getInversePredicate(Pred), m_Specific(L), + m_Specific(R)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + + EXPECT_FALSE(m_SpecificICmp(ICmpInst::getInversePredicate(Pred), + m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(ICmpInst::getInversePredicate(Pred), + m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateICmp(Pred, L, R))); +} + +TYPED_TEST(MutableConstTest, FCmp) { + auto &IRB = PatternMatchTest::IRB; + + typedef std::tuple_element_t<0, TypeParam> ValueType; + typedef std::tuple_element_t<1, TypeParam> InstructionType; + + Value *L = Constant::getNullValue(IRB.getFloatTy()); + Value *R = ConstantFP::getInfinity(IRB.getFloatTy(), true); + FCmpInst::Predicate Pred = FCmpInst::FCMP_OGT; + + ValueType MatchL; + ValueType MatchR; + FCmpInst::Predicate MatchPred; + + EXPECT_TRUE(m_FCmp(MatchPred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_TRUE(m_Cmp(MatchPred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_TRUE(m_FCmp(m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + EXPECT_TRUE(m_Cmp(m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + EXPECT_FALSE(m_FCmp(m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_FALSE(m_Cmp(m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + EXPECT_TRUE(m_SpecificFCmp(Pred, m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_TRUE(m_SpecificCmp(Pred, m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + EXPECT_FALSE(m_SpecificFCmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + MatchL = nullptr; + MatchR = nullptr; + EXPECT_TRUE(m_SpecificFCmp(Pred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = nullptr; + MatchR = nullptr; + EXPECT_TRUE(m_SpecificCmp(Pred, m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_FALSE(m_SpecificFCmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + EXPECT_FALSE(m_SpecificFCmp(FCmpInst::getInversePredicate(Pred), + m_Specific(L), m_Specific(R)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(FCmpInst::getInversePredicate(Pred), m_Specific(L), + m_Specific(R)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + + EXPECT_FALSE(m_SpecificFCmp(FCmpInst::getInversePredicate(Pred), + m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); + EXPECT_FALSE(m_SpecificCmp(FCmpInst::getInversePredicate(Pred), + m_Value(MatchL), m_Value(MatchR)) + .match((InstructionType)IRB.CreateFCmp(Pred, L, R))); } TEST_F(PatternMatchTest, ConstExpr) {