return LogicalOp_match<LHS, RHS, Instruction::Or, true>(L, R);
}
+/// Matches either L && R or L || R,
+/// either one being in the either binary or logical form.
+/// Note that the latter form is poison-blocking.
+template <typename LHS, typename RHS, bool Commutable = false>
+inline auto m_LogicalOp(const LHS &L, const RHS &R) {
+ return m_CombineOr(
+ LogicalOp_match<LHS, RHS, Instruction::And, Commutable>(L, R),
+ LogicalOp_match<LHS, RHS, Instruction::Or, Commutable>(L, R));
+}
+
+/// Matches either L && R or L || R where L and R are arbitrary values.
+inline auto m_LogicalOp() { return m_LogicalOp(m_Value(), m_Value()); }
+
+/// Matches either L && R or L || R with LHS and RHS in either order.
+template <typename LHS, typename RHS>
+inline auto m_c_LogicalOp(const LHS &L, const RHS &R) {
+ return m_LogicalOp<LHS, RHS, /*Commutable=*/true>(L, R);
+}
+
} // end namespace PatternMatch
} // end namespace llvm
if (match(OuterSel.Cond, m_Not(m_Value(OuterSel.Cond))))
std::swap(OuterSel.TrueVal, OuterSel.FalseVal);
- auto m_c_LogicalOp = [](auto L, auto R) {
- return m_CombineOr(m_c_LogicalAnd(L, R), m_c_LogicalOr(L, R));
- };
-
// The condition of the outermost select must be an `and`/`or`.
if (!match(OuterSel.Cond, m_c_LogicalOp(m_Value(), m_Value())))
return nullptr;
std::swap(InnerSel.TrueVal, InnerSel.FalseVal);
Value *AltCond = nullptr;
- auto matchOuterCond = [OuterSel, m_c_LogicalOp, &AltCond](auto m_InnerCond) {
+ auto matchOuterCond = [OuterSel, &AltCond](auto m_InnerCond) {
return match(OuterSel.Cond, m_c_LogicalOp(m_InnerCond, m_Value(AltCond)));
};