return BinaryOp_match<LHS, RHS, Instruction::AShr>(L, R);
}
+template<typename LHS_t, typename RHS_t, unsigned Opcode, unsigned WrapFlags = 0>
+struct OverflowingBinaryOp_match {
+ LHS_t L;
+ RHS_t R;
+
+ OverflowingBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {}
+
+ template<typename OpTy>
+ bool match(OpTy *V) {
+ if (OverflowingBinaryOperator *Op = dyn_cast<OverflowingBinaryOperator>(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 <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
+ OverflowingBinaryOperator::NoSignedWrap>
+m_NSWAdd(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
+ OverflowingBinaryOperator::NoSignedWrap>(
+ L, R);
+}
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
+ OverflowingBinaryOperator::NoSignedWrap>
+m_NSWSub(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
+ OverflowingBinaryOperator::NoSignedWrap>(
+ L, R);
+}
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
+ OverflowingBinaryOperator::NoSignedWrap>
+m_NSWMul(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
+ OverflowingBinaryOperator::NoSignedWrap>(
+ L, R);
+}
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
+ OverflowingBinaryOperator::NoSignedWrap>
+m_NSWShl(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
+ OverflowingBinaryOperator::NoSignedWrap>(
+ L, R);
+}
+
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
+ OverflowingBinaryOperator::NoUnsignedWrap>
+m_NUWAdd(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
+ OverflowingBinaryOperator::NoUnsignedWrap>(
+ L, R);
+}
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
+ OverflowingBinaryOperator::NoUnsignedWrap>
+m_NUWSub(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
+ OverflowingBinaryOperator::NoUnsignedWrap>(
+ L, R);
+}
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
+ OverflowingBinaryOperator::NoUnsignedWrap>
+m_NUWMul(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
+ OverflowingBinaryOperator::NoUnsignedWrap>(
+ L, R);
+}
+template <typename LHS, typename RHS>
+inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
+ OverflowingBinaryOperator::NoUnsignedWrap>
+m_NUWShl(const LHS &L, const RHS &R) {
+ return OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
+ OverflowingBinaryOperator::NoUnsignedWrap>(
+ L, R);
+}
+
//===----------------------------------------------------------------------===//
// Class that matches two different binary ops.
//
return CastClass_match<OpTy, Instruction::ZExt>(Op);
}
+/// m_UIToFP
+template<typename OpTy>
+inline CastClass_match<OpTy, Instruction::UIToFP>
+m_UIToFP(const OpTy &Op) {
+ return CastClass_match<OpTy, Instruction::UIToFP>(Op);
+}
+
+/// m_SIToFP
+template<typename OpTy>
+inline CastClass_match<OpTy, Instruction::SIToFP>
+m_SIToFP(const OpTy &Op) {
+ return CastClass_match<OpTy, Instruction::SIToFP>(Op);
+}
//===----------------------------------------------------------------------===//
// Matchers for unary operators
// Matchers for control flow.
//
+struct br_match {
+ BasicBlock *&Succ;
+ br_match(BasicBlock *&Succ)
+ : Succ(Succ) {
+ }
+
+ template<typename OpTy>
+ bool match(OpTy *V) {
+ if (BranchInst *BI = dyn_cast<BranchInst>(V))
+ if (BI->isUnconditional()) {
+ Succ = BI->getSuccessor(0);
+ return true;
+ }
+ return false;
+ }
+};
+
+inline br_match m_UnconditionalBr(BasicBlock *&Succ) { return br_match(Succ); }
+
template<typename Cond_t>
struct brc_match {
Cond_t Cond;
// Matchers for max/min idioms, eg: "select (sgt x, y), x, y" -> smax(x,y).
//
-template<typename LHS_t, typename RHS_t, typename Pred_t>
+template<typename CmpInst_t, typename LHS_t, typename RHS_t, typename Pred_t>
struct MaxMin_match {
LHS_t L;
RHS_t R;
SelectInst *SI = dyn_cast<SelectInst>(V);
if (!SI)
return false;
- ICmpInst *Cmp = dyn_cast<ICmpInst>(SI->getCondition());
+ CmpInst_t *Cmp = dyn_cast<CmpInst_t>(SI->getCondition());
if (!Cmp)
return false;
// At this point we have a select conditioned on a comparison. Check that
if ((TrueVal != LHS || FalseVal != RHS) &&
(TrueVal != RHS || FalseVal != LHS))
return false;
- ICmpInst::Predicate Pred = LHS == TrueVal ?
+ typename CmpInst_t::Predicate Pred = LHS == TrueVal ?
Cmp->getPredicate() : Cmp->getSwappedPredicate();
// Does "(x pred y) ? x : y" represent the desired max/min operation?
if (!Pred_t::match(Pred))
}
};
+/// ofmax_pred_ty - Helper class for identifying ordered max predicates.
+struct ofmax_pred_ty {
+ static bool match(FCmpInst::Predicate Pred) {
+ return Pred == CmpInst::FCMP_OGT || Pred == CmpInst::FCMP_OGE;
+ }
+};
+
+/// ofmin_pred_ty - Helper class for identifying ordered min predicates.
+struct ofmin_pred_ty {
+ static bool match(FCmpInst::Predicate Pred) {
+ return Pred == CmpInst::FCMP_OLT || Pred == CmpInst::FCMP_OLE;
+ }
+};
+
+/// ufmax_pred_ty - Helper class for identifying unordered max predicates.
+struct ufmax_pred_ty {
+ static bool match(FCmpInst::Predicate Pred) {
+ return Pred == CmpInst::FCMP_UGT || Pred == CmpInst::FCMP_UGE;
+ }
+};
+
+/// ufmin_pred_ty - Helper class for identifying unordered min predicates.
+struct ufmin_pred_ty {
+ static bool match(FCmpInst::Predicate Pred) {
+ return Pred == CmpInst::FCMP_ULT || Pred == CmpInst::FCMP_ULE;
+ }
+};
+
template<typename LHS, typename RHS>
-inline MaxMin_match<LHS, RHS, smax_pred_ty>
+inline MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>
m_SMax(const LHS &L, const RHS &R) {
- return MaxMin_match<LHS, RHS, smax_pred_ty>(L, R);
+ return MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>(L, R);
}
template<typename LHS, typename RHS>
-inline MaxMin_match<LHS, RHS, smin_pred_ty>
+inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>
m_SMin(const LHS &L, const RHS &R) {
- return MaxMin_match<LHS, RHS, smin_pred_ty>(L, R);
+ return MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>(L, R);
}
template<typename LHS, typename RHS>
-inline MaxMin_match<LHS, RHS, umax_pred_ty>
+inline MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty>
m_UMax(const LHS &L, const RHS &R) {
- return MaxMin_match<LHS, RHS, umax_pred_ty>(L, R);
+ return MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty>(L, R);
}
template<typename LHS, typename RHS>
-inline MaxMin_match<LHS, RHS, umin_pred_ty>
+inline MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>
m_UMin(const LHS &L, const RHS &R) {
- return MaxMin_match<LHS, RHS, umin_pred_ty>(L, R);
+ return MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>(L, R);
+}
+
+/// \brief Match an 'ordered' floating point maximum function.
+/// Floating point has one special value 'NaN'. Therefore, there is no total
+/// order. However, if we can ignore the 'NaN' value (for example, because of a
+/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'maximum'
+/// semantics. In the presence of 'NaN' we have to preserve the original
+/// select(fcmp(ogt/ge, L, R), L, R) semantics matched by this predicate.
+///
+/// max(L, R) iff L and R are not NaN
+/// m_OrdFMax(L, R) = R iff L or R are NaN
+template<typename LHS, typename RHS>
+inline MaxMin_match<FCmpInst, LHS, RHS, ofmax_pred_ty>
+m_OrdFMax(const LHS &L, const RHS &R) {
+ return MaxMin_match<FCmpInst, LHS, RHS, ofmax_pred_ty>(L, R);
+}
+
+/// \brief Match an 'ordered' floating point minimum function.
+/// Floating point has one special value 'NaN'. Therefore, there is no total
+/// order. However, if we can ignore the 'NaN' value (for example, because of a
+/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum'
+/// semantics. In the presence of 'NaN' we have to preserve the original
+/// select(fcmp(olt/le, L, R), L, R) semantics matched by this predicate.
+///
+/// max(L, R) iff L and R are not NaN
+/// m_OrdFMin(L, R) = R iff L or R are NaN
+template<typename LHS, typename RHS>
+inline MaxMin_match<FCmpInst, LHS, RHS, ofmin_pred_ty>
+m_OrdFMin(const LHS &L, const RHS &R) {
+ return MaxMin_match<FCmpInst, LHS, RHS, ofmin_pred_ty>(L, R);
+}
+
+/// \brief Match an 'unordered' floating point maximum function.
+/// Floating point has one special value 'NaN'. Therefore, there is no total
+/// order. However, if we can ignore the 'NaN' value (for example, because of a
+/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'maximum'
+/// semantics. In the presence of 'NaN' we have to preserve the original
+/// select(fcmp(ugt/ge, L, R), L, R) semantics matched by this predicate.
+///
+/// max(L, R) iff L and R are not NaN
+/// m_UnordFMin(L, R) = L iff L or R are NaN
+template<typename LHS, typename RHS>
+inline MaxMin_match<FCmpInst, LHS, RHS, ufmax_pred_ty>
+m_UnordFMax(const LHS &L, const RHS &R) {
+ return MaxMin_match<FCmpInst, LHS, RHS, ufmax_pred_ty>(L, R);
+}
+
+/// \brief Match an 'unordered' floating point minimum function.
+/// Floating point has one special value 'NaN'. Therefore, there is no total
+/// order. However, if we can ignore the 'NaN' value (for example, because of a
+/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum'
+/// semantics. In the presence of 'NaN' we have to preserve the original
+/// select(fcmp(ult/le, L, R), L, R) semantics matched by this predicate.
+///
+/// max(L, R) iff L and R are not NaN
+/// m_UnordFMin(L, R) = L iff L or R are NaN
+template<typename LHS, typename RHS>
+inline MaxMin_match<FCmpInst, LHS, RHS, ufmin_pred_ty>
+m_UnordFMin(const LHS &L, const RHS &R) {
+ return MaxMin_match<FCmpInst, LHS, RHS, ufmin_pred_ty>(L, R);
}
template<typename Opnd_t>
/// Intrinsic matchers.
struct IntrinsicID_match {
unsigned ID;
- IntrinsicID_match(unsigned IntrID) : ID(IntrID) { }
+ IntrinsicID_match(Intrinsic::ID IntrID) : ID(IntrID) { }
template<typename OpTy>
bool match(OpTy *V) {
/// Match intrinsic calls like this:
/// m_Intrinsic<Intrinsic::fabs>(m_Value(X))
-template <unsigned IntrID>
+template <Intrinsic::ID IntrID>
inline IntrinsicID_match
m_Intrinsic() { return IntrinsicID_match(IntrID); }
-template<unsigned IntrID, typename T0>
+template<Intrinsic::ID IntrID, typename T0>
inline typename m_Intrinsic_Ty<T0>::Ty
m_Intrinsic(const T0 &Op0) {
return m_CombineAnd(m_Intrinsic<IntrID>(), m_Argument<0>(Op0));
}
-template<unsigned IntrID, typename T0, typename T1>
+template<Intrinsic::ID IntrID, typename T0, typename T1>
inline typename m_Intrinsic_Ty<T0, T1>::Ty
m_Intrinsic(const T0 &Op0, const T1 &Op1) {
return m_CombineAnd(m_Intrinsic<IntrID>(Op0), m_Argument<1>(Op1));
}
-template<unsigned IntrID, typename T0, typename T1, typename T2>
+template<Intrinsic::ID IntrID, typename T0, typename T1, typename T2>
inline typename m_Intrinsic_Ty<T0, T1, T2>::Ty
m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2) {
return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1), m_Argument<2>(Op2));
}
-template<unsigned IntrID, typename T0, typename T1, typename T2, typename T3>
+template<Intrinsic::ID IntrID, typename T0, typename T1, typename T2, typename T3>
inline typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty
m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3) {
return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2), m_Argument<3>(Op3));