diff --git a/llvm/include/llvm/Support/PatternMatch.h b/llvm/include/llvm/Support/PatternMatch.h index 240bb81d31a7..97739b08694d 100644 --- a/llvm/include/llvm/Support/PatternMatch.h +++ b/llvm/include/llvm/Support/PatternMatch.h @@ -498,6 +498,96 @@ m_AShr(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } +template +struct OverflowingBinaryOp_match { + LHS_t L; + RHS_t R; + + OverflowingBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} + + template + bool match(OpTy *V) { + if (OverflowingBinaryOperator *Op = dyn_cast(V)) { + if (Op->getOpcode() != Opcode) + return false; + if (WrapFlags & OverflowingBinaryOperator::NoUnsignedWrap && + !Op->hasNoUnsignedWrap()) + return false; + if (WrapFlags & OverflowingBinaryOperator::NoSignedWrap && + !Op->hasNoSignedWrap()) + return false; + return L.match(Op->getOperand(0)) && R.match(Op->getOperand(1)); + } + return false; + } +}; + +template +inline OverflowingBinaryOp_match +m_NSWAdd(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} +template +inline OverflowingBinaryOp_match +m_NSWSub(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} +template +inline OverflowingBinaryOp_match +m_NSWMul(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} +template +inline OverflowingBinaryOp_match +m_NSWShl(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} + +template +inline OverflowingBinaryOp_match +m_NUWAdd(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} +template +inline OverflowingBinaryOp_match +m_NUWSub(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} +template +inline OverflowingBinaryOp_match +m_NUWMul(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} +template +inline OverflowingBinaryOp_match +m_NUWShl(const LHS &L, const RHS &R) { + return OverflowingBinaryOp_match( + L, R); +} + //===----------------------------------------------------------------------===// // Class that matches two different binary ops. // diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp index b593648bb32a..150f1657b9c2 100644 --- a/llvm/unittests/IR/PatternMatch.cpp +++ b/llvm/unittests/IR/PatternMatch.cpp @@ -201,4 +201,78 @@ TEST_F(PatternMatchTest, FloatingPointUnorderedMax) { EXPECT_EQ(R, MatchR); } +TEST_F(PatternMatchTest, OverflowingBinOps) { + Value *L = IRB.getInt32(1); + Value *R = IRB.getInt32(2); + Value *MatchL, *MatchR; + + EXPECT_TRUE( + m_NSWAdd(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNSWAdd(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = 0; + EXPECT_TRUE( + m_NSWSub(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNSWSub(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = 0; + EXPECT_TRUE( + m_NSWMul(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNSWMul(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = 0; + EXPECT_TRUE(m_NSWShl(m_Value(MatchL), m_Value(MatchR)).match( + IRB.CreateShl(L, R, "", /* NUW */ false, /* NSW */ true))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_TRUE( + m_NUWAdd(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNUWAdd(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = 0; + EXPECT_TRUE( + m_NUWSub(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNUWSub(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = 0; + EXPECT_TRUE( + m_NUWMul(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNUWMul(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = 0; + EXPECT_TRUE(m_NUWShl(m_Value(MatchL), m_Value(MatchR)).match( + IRB.CreateShl(L, R, "", /* NUW */ true, /* NSW */ false))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_FALSE(m_NSWAdd(m_Value(), m_Value()).match(IRB.CreateAdd(L, R))); + EXPECT_FALSE(m_NSWAdd(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); + EXPECT_FALSE(m_NSWAdd(m_Value(), m_Value()).match(IRB.CreateNSWSub(L, R))); + EXPECT_FALSE(m_NSWSub(m_Value(), m_Value()).match(IRB.CreateSub(L, R))); + EXPECT_FALSE(m_NSWSub(m_Value(), m_Value()).match(IRB.CreateNUWSub(L, R))); + EXPECT_FALSE(m_NSWSub(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + EXPECT_FALSE(m_NSWMul(m_Value(), m_Value()).match(IRB.CreateMul(L, R))); + EXPECT_FALSE(m_NSWMul(m_Value(), m_Value()).match(IRB.CreateNUWMul(L, R))); + EXPECT_FALSE(m_NSWMul(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + EXPECT_FALSE(m_NSWShl(m_Value(), m_Value()).match(IRB.CreateShl(L, R))); + EXPECT_FALSE(m_NSWShl(m_Value(), m_Value()).match( + IRB.CreateShl(L, R, "", /* NUW */ true, /* NSW */ false))); + EXPECT_FALSE(m_NSWShl(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + + EXPECT_FALSE(m_NUWAdd(m_Value(), m_Value()).match(IRB.CreateAdd(L, R))); + EXPECT_FALSE(m_NUWAdd(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + EXPECT_FALSE(m_NUWAdd(m_Value(), m_Value()).match(IRB.CreateNUWSub(L, R))); + EXPECT_FALSE(m_NUWSub(m_Value(), m_Value()).match(IRB.CreateSub(L, R))); + EXPECT_FALSE(m_NUWSub(m_Value(), m_Value()).match(IRB.CreateNSWSub(L, R))); + EXPECT_FALSE(m_NUWSub(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); + EXPECT_FALSE(m_NUWMul(m_Value(), m_Value()).match(IRB.CreateMul(L, R))); + EXPECT_FALSE(m_NUWMul(m_Value(), m_Value()).match(IRB.CreateNSWMul(L, R))); + EXPECT_FALSE(m_NUWMul(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); + EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match(IRB.CreateShl(L, R))); + EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match( + IRB.CreateShl(L, R, "", /* NUW */ false, /* NSW */ true))); + EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); +} + } // anonymous namespace.