Index: include/llvm/IR/PatternMatch.h =================================================================== --- include/llvm/IR/PatternMatch.h +++ include/llvm/IR/PatternMatch.h @@ -480,6 +480,20 @@ /// Match if we have a specific specified value. inline specificval_ty m_Specific(const Value *V) { return V; } +/// Stores a pointer to the Value *, not the Value * itself, +/// thus can be used in commutative matchers. +struct specificvalc_ty { + using ValTy = const Value *const; + const ValTy *const Val; + + specificvalc_ty(const ValTy *const V) : Val(V) {} + + template bool match(ITy *V) { return V == *Val; } +}; + +/// A commutative-friendly version of m_Specific(). +inline specificvalc_ty m_c_Specific(specificvalc_ty::ValTy *V) { return V; } + /// Match a specified floating point value or vector of all elements of /// that value. struct specific_fpval { @@ -553,13 +567,15 @@ LHS_t L; RHS_t R; + // The evaluation order is always stable, regardless of Commutability. + // The LHS is always matched first. AnyBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template bool match(OpTy *V) { if (auto *I = dyn_cast(V)) return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || - (Commutable && R.match(I->getOperand(0)) && - L.match(I->getOperand(1))); + (Commutable && L.match(I->getOperand(1)) && + R.match(I->getOperand(0))); return false; } }; @@ -579,20 +595,22 @@ LHS_t L; RHS_t R; + // The evaluation order is always stable, regardless of Commutability. + // The LHS is always matched first. BinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template bool match(OpTy *V) { if (V->getValueID() == Value::InstructionVal + Opcode) { auto *I = cast(V); return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || - (Commutable && R.match(I->getOperand(0)) && - L.match(I->getOperand(1))); + (Commutable && L.match(I->getOperand(1)) && + R.match(I->getOperand(0))); } if (auto *CE = dyn_cast(V)) return CE->getOpcode() == Opcode && ((L.match(CE->getOperand(0)) && R.match(CE->getOperand(1))) || - (Commutable && R.match(CE->getOperand(0)) && - L.match(CE->getOperand(1)))); + (Commutable && L.match(CE->getOperand(1)) && + R.match(CE->getOperand(0)))); return false; } }; @@ -917,14 +935,16 @@ LHS_t L; RHS_t R; + // The evaluation order is always stable, regardless of Commutability. + // The LHS is always matched first. CmpClass_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)) if ((L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || - (Commutable && R.match(I->getOperand(0)) && - L.match(I->getOperand(1)))) { + (Commutable && L.match(I->getOperand(1)) && + R.match(I->getOperand(0)))) { Predicate = I->getPredicate(); return true; } @@ -1242,6 +1262,8 @@ LHS_t L; RHS_t R; + // The evaluation order is always stable, regardless of Commutability. + // The LHS is always matched first. MaxMin_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template bool match(OpTy *V) { @@ -1268,7 +1290,7 @@ return false; // It does! Bind the operands. return (L.match(LHS) && R.match(RHS)) || - (Commutable && R.match(LHS) && L.match(RHS)); + (Commutable && L.match(RHS) && R.match(LHS)); } }; Index: unittests/IR/PatternMatch.cpp =================================================================== --- unittests/IR/PatternMatch.cpp +++ unittests/IR/PatternMatch.cpp @@ -65,6 +65,28 @@ EXPECT_FALSE(m_OneUse(m_Value()).match(Leaf)); } +TEST_F(PatternMatchTest, CommutativeSpecificValue) { + Value *X = IRB.getInt32(1); + Value *Y = IRB.getInt32(2); + Value *M = IRB.getInt32(3); + + // | A | |B| + // ((x ^ y) & ~M) ^ y + // | D | + Value *D = IRB.CreateXor(X, Y); + Value *iM = IRB.CreateXor(M, IRB.getInt32(-1)); + Value *A = IRB.CreateAnd(D, iM); + Value *MM = IRB.CreateXor(A, Y); // The masked merge + + Value *tB, *tX, *tM; + EXPECT_TRUE(match( + MM, m_c_Xor(m_Value(tB), m_c_And(m_c_Xor(m_c_Specific(&tB), m_Value(tX)), + m_Not(m_Value(tM)))))); + EXPECT_EQ(tB, Y); + EXPECT_EQ(tX, X); + EXPECT_EQ(tM, M); +} + TEST_F(PatternMatchTest, FloatingPointOrderedMin) { Type *FltTy = IRB.getFloatTy(); Value *L = ConstantFP::get(FltTy, 1.0);