llvm/llvm/include/llvm/IR/PatternMatch.h

//===- PatternMatch.h - Match on the LLVM IR --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides a simple and efficient mechanism for performing general
// tree-based pattern matches on the LLVM IR. The power of these routines is
// that it allows you to write concise patterns that are expressive and easy to
// understand. The other major advantage of this is that it allows you to
// trivially capture/bind elements in the pattern to variables. For example,
// you can do something like this:
//
//  Value *Exp = ...
//  Value *X, *Y;  ConstantInt *C1, *C2;      // (X & C1) | (Y & C2)
//  if (match(Exp, m_Or(m_And(m_Value(X), m_ConstantInt(C1)),
//                      m_And(m_Value(Y), m_ConstantInt(C2))))) {
//    ... Pattern is matched and variables are bound ...
//  }
//
// This is primarily useful to things like the instruction combiner, but can
// also be useful for static analysis tools or code generators.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_IR_PATTERNMATCH_H
#define LLVM_IR_PATTERNMATCH_H

#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include <cstdint>

namespace llvm {
namespace PatternMatch {

template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {}

template <typename Pattern> bool match(ArrayRef<int> Mask, const Pattern &P) {}

template <typename SubPattern_t> struct OneUse_match {};

template <typename T> inline OneUse_match<T> m_OneUse(const T &SubPattern) {}

template <typename SubPattern_t> struct AllowReassoc_match {};

template <typename T>
inline AllowReassoc_match<T> m_AllowReassoc(const T &SubPattern) {}

template <typename Class> struct class_match {};

/// Match an arbitrary value and ignore it.
inline class_match<Value> m_Value() {}

/// Match an arbitrary unary operation and ignore it.
inline class_match<UnaryOperator> m_UnOp() {}

/// Match an arbitrary binary operation and ignore it.
inline class_match<BinaryOperator> m_BinOp() {}

/// Matches any compare instruction and ignore it.
inline class_match<CmpInst> m_Cmp() {}

struct undef_match {};

/// Match an arbitrary undef constant. This matches poison as well.
/// If this is an aggregate and contains a non-aggregate element that is
/// neither undef nor poison, the aggregate is not matched.
inline auto m_Undef() {}

/// Match an arbitrary UndefValue constant.
inline class_match<UndefValue> m_UndefValue() {}

/// Match an arbitrary poison constant.
inline class_match<PoisonValue> m_Poison() {}

/// Match an arbitrary Constant and ignore it.
inline class_match<Constant> m_Constant() {}

/// Match an arbitrary ConstantInt and ignore it.
inline class_match<ConstantInt> m_ConstantInt() {}

/// Match an arbitrary ConstantFP and ignore it.
inline class_match<ConstantFP> m_ConstantFP() {}

struct constantexpr_match {};

/// Match a constant expression or a constant that contains a constant
/// expression.
inline constantexpr_match m_ConstantExpr() {}

/// Match an arbitrary basic block value and ignore it.
inline class_match<BasicBlock> m_BasicBlock() {}

/// Inverting matcher
template <typename Ty> struct match_unless {};

/// Match if the inner matcher does *NOT* match.
template <typename Ty> inline match_unless<Ty> m_Unless(const Ty &M) {}

/// Matching combinators
template <typename LTy, typename RTy> struct match_combine_or {};

template <typename LTy, typename RTy> struct match_combine_and {};

/// Combine two pattern matchers matching L || R
template <typename LTy, typename RTy>
inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {}

/// Combine two pattern matchers matching L && R
template <typename LTy, typename RTy>
inline match_combine_and<LTy, RTy> m_CombineAnd(const LTy &L, const RTy &R) {}

struct apint_match {};
// Either constexpr if or renaming ConstantFP::getValueAPF to
// ConstantFP::getValue is needed to do it via single template
// function for both apint/apfloat.
struct apfloat_match {};

/// Match a ConstantInt or splatted ConstantVector, binding the
/// specified pointer to the contained APInt.
inline apint_match m_APInt(const APInt *&Res) {}

/// Match APInt while allowing poison in splat vector constants.
inline apint_match m_APIntAllowPoison(const APInt *&Res) {}

/// Match APInt while forbidding poison in splat vector constants.
inline apint_match m_APIntForbidPoison(const APInt *&Res) {}

/// Match a ConstantFP or splatted ConstantVector, binding the
/// specified pointer to the contained APFloat.
inline apfloat_match m_APFloat(const APFloat *&Res) {}

/// Match APFloat while allowing poison in splat vector constants.
inline apfloat_match m_APFloatAllowPoison(const APFloat *&Res) {}

/// Match APFloat while forbidding poison in splat vector constants.
inline apfloat_match m_APFloatForbidPoison(const APFloat *&Res) {}

template <int64_t Val> struct constantint_match {};

/// Match a ConstantInt with a specific value.
template <int64_t Val> inline constantint_match<Val> m_ConstantInt() {}

/// This helper class is used to match constant scalars, vector splats,
/// and fixed width vectors that satisfy a specified predicate.
/// For fixed width vector constants, poison elements are ignored if AllowPoison
/// is true.
template <typename Predicate, typename ConstantVal, bool AllowPoison>
struct cstval_pred_ty : public Predicate {};

/// specialization of cstval_pred_ty for ConstantInt
cst_pred_ty;

/// specialization of cstval_pred_ty for ConstantFP
cstfp_pred_ty;

/// This helper class is used to match scalar and vector constants that
/// satisfy a specified predicate, and bind them to an APInt.
template <typename Predicate> struct api_pred_ty : public Predicate {};

/// This helper class is used to match scalar and vector constants that
/// satisfy a specified predicate, and bind them to an APFloat.
/// Poison is allowed in splat vector constants.
template <typename Predicate> struct apf_pred_ty : public Predicate {};

///////////////////////////////////////////////////////////////////////////////
//
// Encapsulate constant value queries for use in templated predicate matchers.
// This allows checking if constants match using compound predicates and works
// with vector constants, possibly with relaxed constraints. For example, ignore
// undef values.
//
///////////////////////////////////////////////////////////////////////////////

template <typename APTy> struct custom_checkfn {};

/// Match an integer or vector where CheckFn(ele) for each element is true.
/// For vectors, poison elements are assumed to match.
inline cst_pred_ty<custom_checkfn<APInt>>
m_CheckedInt(function_ref<bool(const APInt &)> CheckFn) {}

inline cst_pred_ty<custom_checkfn<APInt>>
m_CheckedInt(const Constant *&V, function_ref<bool(const APInt &)> CheckFn) {}

/// Match a float or vector where CheckFn(ele) for each element is true.
/// For vectors, poison elements are assumed to match.
inline cstfp_pred_ty<custom_checkfn<APFloat>>
m_CheckedFp(function_ref<bool(const APFloat &)> CheckFn) {}

inline cstfp_pred_ty<custom_checkfn<APFloat>>
m_CheckedFp(const Constant *&V, function_ref<bool(const APFloat &)> CheckFn) {}

struct is_any_apint {};
/// Match an integer or vector with any integral constant.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_any_apint> m_AnyIntegralConstant() {}

struct is_shifted_mask {};

inline cst_pred_ty<is_shifted_mask> m_ShiftedMask() {}

struct is_all_ones {};
/// Match an integer or vector with all bits set.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_all_ones> m_AllOnes() {}

inline cst_pred_ty<is_all_ones, false> m_AllOnesForbidPoison() {}

struct is_maxsignedvalue {};
/// Match an integer or vector with values having all bits except for the high
/// bit set (0x7f...).
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_maxsignedvalue> m_MaxSignedValue() {}
inline api_pred_ty<is_maxsignedvalue> m_MaxSignedValue(const APInt *&V) {}

struct is_negative {};
/// Match an integer or vector of negative values.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_negative> m_Negative() {}
inline api_pred_ty<is_negative> m_Negative(const APInt *&V) {}

struct is_nonnegative {};
/// Match an integer or vector of non-negative values.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_nonnegative> m_NonNegative() {}
inline api_pred_ty<is_nonnegative> m_NonNegative(const APInt *&V) {}

struct is_strictlypositive {};
/// Match an integer or vector of strictly positive values.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_strictlypositive> m_StrictlyPositive() {}
inline api_pred_ty<is_strictlypositive> m_StrictlyPositive(const APInt *&V) {}

struct is_nonpositive {};
/// Match an integer or vector of non-positive values.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_nonpositive> m_NonPositive() {}
inline api_pred_ty<is_nonpositive> m_NonPositive(const APInt *&V) {}

struct is_one {};
/// Match an integer 1 or a vector with all elements equal to 1.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_one> m_One() {}

struct is_zero_int {};
/// Match an integer 0 or a vector with all elements equal to 0.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_zero_int> m_ZeroInt() {}

struct is_zero {};
/// Match any null constant or a vector with all elements equal to 0.
/// For vectors, this includes constants with undefined elements.
inline is_zero m_Zero() {}

struct is_power2 {};
/// Match an integer or vector power-of-2.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_power2> m_Power2() {}
inline api_pred_ty<is_power2> m_Power2(const APInt *&V) {}

struct is_negated_power2 {};
/// Match a integer or vector negated power-of-2.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_negated_power2> m_NegatedPower2() {}
inline api_pred_ty<is_negated_power2> m_NegatedPower2(const APInt *&V) {}

struct is_negated_power2_or_zero {};
/// Match a integer or vector negated power-of-2.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_negated_power2_or_zero> m_NegatedPower2OrZero() {}
inline api_pred_ty<is_negated_power2_or_zero>
m_NegatedPower2OrZero(const APInt *&V) {}

struct is_power2_or_zero {};
/// Match an integer or vector of 0 or power-of-2 values.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_power2_or_zero> m_Power2OrZero() {}
inline api_pred_ty<is_power2_or_zero> m_Power2OrZero(const APInt *&V) {}

struct is_sign_mask {};
/// Match an integer or vector with only the sign bit(s) set.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_sign_mask> m_SignMask() {}

struct is_lowbit_mask {};
/// Match an integer or vector with only the low bit(s) set.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_lowbit_mask> m_LowBitMask() {}
inline api_pred_ty<is_lowbit_mask> m_LowBitMask(const APInt *&V) {}

struct is_lowbit_mask_or_zero {};
/// Match an integer or vector with only the low bit(s) set.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_lowbit_mask_or_zero> m_LowBitMaskOrZero() {}
inline api_pred_ty<is_lowbit_mask_or_zero> m_LowBitMaskOrZero(const APInt *&V) {}

struct icmp_pred_with_threshold {};
/// Match an integer or vector with every element comparing 'pred' (eg/ne/...)
/// to Threshold. For vectors, this includes constants with undefined elements.
inline cst_pred_ty<icmp_pred_with_threshold>
m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {}

struct is_nan {};
/// Match an arbitrary NaN constant. This includes quiet and signalling nans.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_nan> m_NaN() {}

struct is_nonnan {};
/// Match a non-NaN FP constant.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_nonnan> m_NonNaN() {}

struct is_inf {};
/// Match a positive or negative infinity FP constant.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_inf> m_Inf() {}

struct is_noninf {};
/// Match a non-infinity FP constant, i.e. finite or NaN.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_noninf> m_NonInf() {}

struct is_finite {};
/// Match a finite FP constant, i.e. not infinity or NaN.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_finite> m_Finite() {}
inline apf_pred_ty<is_finite> m_Finite(const APFloat *&V) {}

struct is_finitenonzero {};
/// Match a finite non-zero FP constant.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_finitenonzero> m_FiniteNonZero() {}
inline apf_pred_ty<is_finitenonzero> m_FiniteNonZero(const APFloat *&V) {}

struct is_any_zero_fp {};
/// Match a floating-point negative zero or positive zero.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_any_zero_fp> m_AnyZeroFP() {}

struct is_pos_zero_fp {};
/// Match a floating-point positive zero.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_pos_zero_fp> m_PosZeroFP() {}

struct is_neg_zero_fp {};
/// Match a floating-point negative zero.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_neg_zero_fp> m_NegZeroFP() {}

struct is_non_zero_fp {};
/// Match a floating-point non-zero.
/// For vectors, this includes constants with undefined elements.
inline cstfp_pred_ty<is_non_zero_fp> m_NonZeroFP() {}

///////////////////////////////////////////////////////////////////////////////

template <typename Class> struct bind_ty {};

/// Match a value, capturing it if we match.
inline bind_ty<Value> m_Value(Value *&V) {}
inline bind_ty<const Value> m_Value(const Value *&V) {}

/// Match an instruction, capturing it if we match.
inline bind_ty<Instruction> m_Instruction(Instruction *&I) {}
/// Match a unary operator, capturing it if we match.
inline bind_ty<UnaryOperator> m_UnOp(UnaryOperator *&I) {}
/// Match a binary operator, capturing it if we match.
inline bind_ty<BinaryOperator> m_BinOp(BinaryOperator *&I) {}
/// Match a with overflow intrinsic, capturing it if we match.
inline bind_ty<WithOverflowInst> m_WithOverflowInst(WithOverflowInst *&I) {}
inline bind_ty<const WithOverflowInst>
m_WithOverflowInst(const WithOverflowInst *&I) {}

/// Match an UndefValue, capturing the value if we match.
inline bind_ty<UndefValue> m_UndefValue(UndefValue *&U) {}

/// Match a Constant, capturing the value if we match.
inline bind_ty<Constant> m_Constant(Constant *&C) {}

/// Match a ConstantInt, capturing the value if we match.
inline bind_ty<ConstantInt> m_ConstantInt(ConstantInt *&CI) {}

/// Match a ConstantFP, capturing the value if we match.
inline bind_ty<ConstantFP> m_ConstantFP(ConstantFP *&C) {}

/// Match a ConstantExpr, capturing the value if we match.
inline bind_ty<ConstantExpr> m_ConstantExpr(ConstantExpr *&C) {}

/// Match a basic block value, capturing it if we match.
inline bind_ty<BasicBlock> m_BasicBlock(BasicBlock *&V) {}
inline bind_ty<const BasicBlock> m_BasicBlock(const BasicBlock *&V) {}

/// Match an arbitrary immediate Constant and ignore it.
inline match_combine_and<class_match<Constant>,
                         match_unless<constantexpr_match>>
m_ImmConstant() {}

/// Match an immediate Constant, capturing the value if we match.
inline match_combine_and<bind_ty<Constant>,
                         match_unless<constantexpr_match>>
m_ImmConstant(Constant *&C) {}

/// Match a specified Value*.
struct specificval_ty {};

/// Match if we have a specific specified value.
inline specificval_ty m_Specific(const Value *V) {}

/// Stores a reference to the Value *, not the Value * itself,
/// thus can be used in commutative matchers.
template <typename Class> struct deferredval_ty {};

/// Like m_Specific(), but works if the specific value to match is determined
/// as part of the same match() expression. For example:
/// m_Add(m_Value(X), m_Specific(X)) is incorrect, because m_Specific() will
/// bind X before the pattern match starts.
/// m_Add(m_Value(X), m_Deferred(X)) is correct, and will check against
/// whichever value m_Value(X) populated.
inline deferredval_ty<Value> m_Deferred(Value *const &V) {}
inline deferredval_ty<const Value> m_Deferred(const Value *const &V) {}

/// Match a specified floating point value or vector of all elements of
/// that value.
struct specific_fpval {};

/// Match a specific floating point value or vector with all elements
/// equal to the value.
inline specific_fpval m_SpecificFP(double V) {}

/// Match a float 1.0 or vector with all elements equal to 1.0.
inline specific_fpval m_FPOne() {}

struct bind_const_intval_ty {};

/// Match a specified integer value or vector of all elements of that
/// value.
template <bool AllowPoison> struct specific_intval {};

template <bool AllowPoison> struct specific_intval64 {};

/// Match a specific integer value or vector with all elements equal to
/// the value.
inline specific_intval<false> m_SpecificInt(const APInt &V) {}

inline specific_intval64<false> m_SpecificInt(uint64_t V) {}

inline specific_intval<true> m_SpecificIntAllowPoison(const APInt &V) {}

inline specific_intval64<true> m_SpecificIntAllowPoison(uint64_t V) {}

/// Match a ConstantInt and bind to its value.  This does not match
/// ConstantInts wider than 64-bits.
inline bind_const_intval_ty m_ConstantInt(uint64_t &V) {}

/// Match a specified basic block value.
struct specific_bbval {};

/// Match a specific basic block value.
inline specific_bbval m_SpecificBB(BasicBlock *BB) {}

/// A commutative-friendly version of m_Specific().
inline deferredval_ty<BasicBlock> m_Deferred(BasicBlock *const &BB) {}
inline deferredval_ty<const BasicBlock>
m_Deferred(const BasicBlock *const &BB) {}

//===----------------------------------------------------------------------===//
// Matcher for any binary operator.
//
template <typename LHS_t, typename RHS_t, bool Commutable = false>
struct AnyBinaryOp_match {};

template <typename LHS, typename RHS>
inline AnyBinaryOp_match<LHS, RHS> m_BinOp(const LHS &L, const RHS &R) {}

//===----------------------------------------------------------------------===//
// Matcher for any unary operator.
// TODO fuse unary, binary matcher into n-ary matcher
//
template <typename OP_t> struct AnyUnaryOp_match {};

template <typename OP_t> inline AnyUnaryOp_match<OP_t> m_UnOp(const OP_t &X) {}

//===----------------------------------------------------------------------===//
// Matchers for specific binary operators.
//

template <typename LHS_t, typename RHS_t, unsigned Opcode,
          bool Commutable = false>
struct BinaryOp_match {};

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Add> m_Add(const LHS &L,
                                                        const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FAdd> m_FAdd(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Sub> m_Sub(const LHS &L,
                                                        const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FSub> m_FSub(const LHS &L,
                                                          const RHS &R) {}

template <typename Op_t> struct FNeg_match {};

/// Match 'fneg X' as 'fsub -0.0, X'.
template <typename OpTy> inline FNeg_match<OpTy> m_FNeg(const OpTy &X) {}

/// Match 'fneg X' as 'fsub +-0.0, X'.
template <typename RHS>
inline BinaryOp_match<cstfp_pred_ty<is_any_zero_fp>, RHS, Instruction::FSub>
m_FNegNSZ(const RHS &X) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Mul> m_Mul(const LHS &L,
                                                        const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FMul> m_FMul(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::UDiv> m_UDiv(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::SDiv> m_SDiv(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FDiv> m_FDiv(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::URem> m_URem(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::SRem> m_SRem(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FRem> m_FRem(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::And> m_And(const LHS &L,
                                                        const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Or> m_Or(const LHS &L,
                                                      const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Xor> m_Xor(const LHS &L,
                                                        const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Shl> m_Shl(const LHS &L,
                                                        const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::LShr> m_LShr(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::AShr> m_AShr(const LHS &L,
                                                          const RHS &R) {}

template <typename LHS_t, typename RHS_t, unsigned Opcode,
          unsigned WrapFlags = 0, bool Commutable = false>
struct OverflowingBinaryOp_match {};

template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
                                 OverflowingBinaryOperator::NoSignedWrap>
m_NSWAdd(const LHS &L, const RHS &R) {}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
                                 OverflowingBinaryOperator::NoSignedWrap>
m_NSWSub(const LHS &L, const RHS &R) {}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
                                 OverflowingBinaryOperator::NoSignedWrap>
m_NSWMul(const LHS &L, const RHS &R) {}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
                                 OverflowingBinaryOperator::NoSignedWrap>
m_NSWShl(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
                                 OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWAdd(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<
    LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoUnsignedWrap, true>
m_c_NUWAdd(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
                                 OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWSub(const LHS &L, const RHS &R) {}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
                                 OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWMul(const LHS &L, const RHS &R) {}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
                                 OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWShl(const LHS &L, const RHS &R) {}

template <typename LHS_t, typename RHS_t, bool Commutable = false>
struct SpecificBinaryOp_match
    : public BinaryOp_match<LHS_t, RHS_t, 0, Commutable> {};

/// Matches a specific opcode.
template <typename LHS, typename RHS>
inline SpecificBinaryOp_match<LHS, RHS> m_BinOp(unsigned Opcode, const LHS &L,
                                                const RHS &R) {}

template <typename LHS, typename RHS, bool Commutable = false>
struct DisjointOr_match {};

template <typename LHS, typename RHS>
inline DisjointOr_match<LHS, RHS> m_DisjointOr(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline DisjointOr_match<LHS, RHS, true> m_c_DisjointOr(const LHS &L,
                                                       const RHS &R) {}

/// Match either "add" or "or disjoint".
template <typename LHS, typename RHS>
inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Add>,
                        DisjointOr_match<LHS, RHS>>
m_AddLike(const LHS &L, const RHS &R) {}

/// Match either "add nsw" or "or disjoint"
template <typename LHS, typename RHS>
inline match_combine_or<
    OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
                              OverflowingBinaryOperator::NoSignedWrap>,
    DisjointOr_match<LHS, RHS>>
m_NSWAddLike(const LHS &L, const RHS &R) {}

/// Match either "add nuw" or "or disjoint"
template <typename LHS, typename RHS>
inline match_combine_or<
    OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
                              OverflowingBinaryOperator::NoUnsignedWrap>,
    DisjointOr_match<LHS, RHS>>
m_NUWAddLike(const LHS &L, const RHS &R) {}

//===----------------------------------------------------------------------===//
// Class that matches a group of binary opcodes.
//
template <typename LHS_t, typename RHS_t, typename Predicate,
          bool Commutable = false>
struct BinOpPred_match : Predicate {};

struct is_shift_op {};

struct is_right_shift_op {};

struct is_logical_shift_op {};

struct is_bitwiselogic_op {};

struct is_idiv_op {};

struct is_irem_op {};

/// Matches shift operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_shift_op> m_Shift(const LHS &L,
                                                      const RHS &R) {}

/// Matches logical shift operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_right_shift_op> m_Shr(const LHS &L,
                                                          const RHS &R) {}

/// Matches logical shift operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_logical_shift_op>
m_LogicalShift(const LHS &L, const RHS &R) {}

/// Matches bitwise logic operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_bitwiselogic_op>
m_BitwiseLogic(const LHS &L, const RHS &R) {}

/// Matches bitwise logic operations in either order.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_bitwiselogic_op, true>
m_c_BitwiseLogic(const LHS &L, const RHS &R) {}

/// Matches integer division operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_idiv_op> m_IDiv(const LHS &L,
                                                    const RHS &R) {}

/// Matches integer remainder operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_irem_op> m_IRem(const LHS &L,
                                                    const RHS &R) {}

//===----------------------------------------------------------------------===//
// Class that matches exact binary ops.
//
template <typename SubPattern_t> struct Exact_match {};

template <typename T> inline Exact_match<T> m_Exact(const T &SubPattern) {}

//===----------------------------------------------------------------------===//
// Matchers for CmpInst classes
//

template <typename LHS_t, typename RHS_t, typename Class, typename PredicateTy,
          bool Commutable = false>
struct CmpClass_match {};

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
m_Cmp(CmpInst::Predicate &Pred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
m_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
m_FCmp(FCmpInst::Predicate &Pred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
m_Cmp(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
m_ICmp(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
m_FCmp(const LHS &L, const RHS &R) {}

// Same as CmpClass, but instead of saving Pred as out output variable, match a
// specific input pred for equality.
template <typename LHS_t, typename RHS_t, typename Class, typename PredicateTy,
          bool Commutable = false>
struct SpecificCmpClass_match {};

template <typename LHS, typename RHS>
inline SpecificCmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
m_SpecificCmp(CmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline SpecificCmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
m_SpecificICmp(ICmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline SpecificCmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
m_c_SpecificICmp(ICmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline SpecificCmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
m_SpecificFCmp(FCmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {}

//===----------------------------------------------------------------------===//
// Matchers for instructions with a given opcode and number of operands.
//

/// Matches instructions with Opcode and three operands.
template <typename T0, unsigned Opcode> struct OneOps_match {};

/// Matches instructions with Opcode and three operands.
template <typename T0, typename T1, unsigned Opcode> struct TwoOps_match {};

/// Matches instructions with Opcode and three operands.
template <typename T0, typename T1, typename T2, unsigned Opcode>
struct ThreeOps_match {};

/// Matches instructions with Opcode and any number of operands
template <unsigned Opcode, typename... OperandTypes> struct AnyOps_match {};

/// Matches SelectInst.
template <typename Cond, typename LHS, typename RHS>
inline ThreeOps_match<Cond, LHS, RHS, Instruction::Select>
m_Select(const Cond &C, const LHS &L, const RHS &R) {}

/// This matches a select of two constants, e.g.:
/// m_SelectCst<-1, 0>(m_Value(V))
template <int64_t L, int64_t R, typename Cond>
inline ThreeOps_match<Cond, constantint_match<L>, constantint_match<R>,
                      Instruction::Select>
m_SelectCst(const Cond &C) {}

/// Matches FreezeInst.
template <typename OpTy>
inline OneOps_match<OpTy, Instruction::Freeze> m_Freeze(const OpTy &Op) {}

/// Matches InsertElementInst.
template <typename Val_t, typename Elt_t, typename Idx_t>
inline ThreeOps_match<Val_t, Elt_t, Idx_t, Instruction::InsertElement>
m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx) {}

/// Matches ExtractElementInst.
template <typename Val_t, typename Idx_t>
inline TwoOps_match<Val_t, Idx_t, Instruction::ExtractElement>
m_ExtractElt(const Val_t &Val, const Idx_t &Idx) {}

/// Matches shuffle.
template <typename T0, typename T1, typename T2> struct Shuffle_match {};

struct m_Mask {};

struct m_ZeroMask {};

struct m_SpecificMask {};

struct m_SplatOrPoisonMask {};

template <typename PointerOpTy, typename OffsetOpTy> struct PtrAdd_match {};

/// Matches ShuffleVectorInst independently of mask value.
template <typename V1_t, typename V2_t>
inline TwoOps_match<V1_t, V2_t, Instruction::ShuffleVector>
m_Shuffle(const V1_t &v1, const V2_t &v2) {}

template <typename V1_t, typename V2_t, typename Mask_t>
inline Shuffle_match<V1_t, V2_t, Mask_t>
m_Shuffle(const V1_t &v1, const V2_t &v2, const Mask_t &mask) {}

/// Matches LoadInst.
template <typename OpTy>
inline OneOps_match<OpTy, Instruction::Load> m_Load(const OpTy &Op) {}

/// Matches StoreInst.
template <typename ValueOpTy, typename PointerOpTy>
inline TwoOps_match<ValueOpTy, PointerOpTy, Instruction::Store>
m_Store(const ValueOpTy &ValueOp, const PointerOpTy &PointerOp) {}

/// Matches GetElementPtrInst.
template <typename... OperandTypes>
inline auto m_GEP(const OperandTypes &...Ops) {}

/// Matches GEP with i8 source element type
template <typename PointerOpTy, typename OffsetOpTy>
inline PtrAdd_match<PointerOpTy, OffsetOpTy>
m_PtrAdd(const PointerOpTy &PointerOp, const OffsetOpTy &OffsetOp) {}

//===----------------------------------------------------------------------===//
// Matchers for CastInst classes
//

template <typename Op_t, unsigned Opcode> struct CastOperator_match {};

template <typename Op_t, typename Class> struct CastInst_match {};

template <typename Op_t> struct PtrToIntSameSize_match {};

template <typename Op_t> struct NNegZExt_match {};

template <typename Op_t, unsigned WrapFlags = 0> struct NoWrapTrunc_match {};

/// Matches BitCast.
template <typename OpTy>
inline CastOperator_match<OpTy, Instruction::BitCast>
m_BitCast(const OpTy &Op) {}

template <typename Op_t> struct ElementWiseBitCast_match {};

template <typename OpTy>
inline ElementWiseBitCast_match<OpTy> m_ElementWiseBitCast(const OpTy &Op) {}

/// Matches PtrToInt.
template <typename OpTy>
inline CastOperator_match<OpTy, Instruction::PtrToInt>
m_PtrToInt(const OpTy &Op) {}

template <typename OpTy>
inline PtrToIntSameSize_match<OpTy> m_PtrToIntSameSize(const DataLayout &DL,
                                                       const OpTy &Op) {}

/// Matches IntToPtr.
template <typename OpTy>
inline CastOperator_match<OpTy, Instruction::IntToPtr>
m_IntToPtr(const OpTy &Op) {}

/// Matches Trunc.
template <typename OpTy>
inline CastInst_match<OpTy, TruncInst> m_Trunc(const OpTy &Op) {}

/// Matches trunc nuw.
template <typename OpTy>
inline NoWrapTrunc_match<OpTy, TruncInst::NoUnsignedWrap>
m_NUWTrunc(const OpTy &Op) {}

/// Matches trunc nsw.
template <typename OpTy>
inline NoWrapTrunc_match<OpTy, TruncInst::NoSignedWrap>
m_NSWTrunc(const OpTy &Op) {}

template <typename OpTy>
inline match_combine_or<CastInst_match<OpTy, TruncInst>, OpTy>
m_TruncOrSelf(const OpTy &Op) {}

/// Matches SExt.
template <typename OpTy>
inline CastInst_match<OpTy, SExtInst> m_SExt(const OpTy &Op) {}

/// Matches ZExt.
template <typename OpTy>
inline CastInst_match<OpTy, ZExtInst> m_ZExt(const OpTy &Op) {}

template <typename OpTy>
inline NNegZExt_match<OpTy> m_NNegZExt(const OpTy &Op) {}

template <typename OpTy>
inline match_combine_or<CastInst_match<OpTy, ZExtInst>, OpTy>
m_ZExtOrSelf(const OpTy &Op) {}

template <typename OpTy>
inline match_combine_or<CastInst_match<OpTy, SExtInst>, OpTy>
m_SExtOrSelf(const OpTy &Op) {}

/// Match either "sext" or "zext nneg".
template <typename OpTy>
inline match_combine_or<CastInst_match<OpTy, SExtInst>, NNegZExt_match<OpTy>>
m_SExtLike(const OpTy &Op) {}

template <typename OpTy>
inline match_combine_or<CastInst_match<OpTy, ZExtInst>,
                        CastInst_match<OpTy, SExtInst>>
m_ZExtOrSExt(const OpTy &Op) {}

template <typename OpTy>
inline match_combine_or<match_combine_or<CastInst_match<OpTy, ZExtInst>,
                                         CastInst_match<OpTy, SExtInst>>,
                        OpTy>
m_ZExtOrSExtOrSelf(const OpTy &Op) {}

template <typename OpTy>
inline CastInst_match<OpTy, UIToFPInst> m_UIToFP(const OpTy &Op) {}

template <typename OpTy>
inline CastInst_match<OpTy, SIToFPInst> m_SIToFP(const OpTy &Op) {}

template <typename OpTy>
inline CastInst_match<OpTy, FPToUIInst> m_FPToUI(const OpTy &Op) {}

template <typename OpTy>
inline CastInst_match<OpTy, FPToSIInst> m_FPToSI(const OpTy &Op) {}

template <typename OpTy>
inline CastInst_match<OpTy, FPTruncInst> m_FPTrunc(const OpTy &Op) {}

template <typename OpTy>
inline CastInst_match<OpTy, FPExtInst> m_FPExt(const OpTy &Op) {}

//===----------------------------------------------------------------------===//
// Matchers for control flow.
//

struct br_match {};

inline br_match m_UnconditionalBr(BasicBlock *&Succ) {}

template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
struct brc_match {};

template <typename Cond_t>
inline brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>
m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {}

template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
inline brc_match<Cond_t, TrueBlock_t, FalseBlock_t>
m_Br(const Cond_t &C, const TrueBlock_t &T, const FalseBlock_t &F) {}

//===----------------------------------------------------------------------===//
// Matchers for max/min idioms, eg: "select (sgt x, y), x, y" -> smax(x,y).
//

template <typename CmpInst_t, typename LHS_t, typename RHS_t, typename Pred_t,
          bool Commutable = false>
struct MaxMin_match {};

/// Helper class for identifying signed max predicates.
struct smax_pred_ty {};

/// Helper class for identifying signed min predicates.
struct smin_pred_ty {};

/// Helper class for identifying unsigned max predicates.
struct umax_pred_ty {};

/// Helper class for identifying unsigned min predicates.
struct umin_pred_ty {};

/// Helper class for identifying ordered max predicates.
struct ofmax_pred_ty {};

/// Helper class for identifying ordered min predicates.
struct ofmin_pred_ty {};

/// Helper class for identifying unordered max predicates.
struct ufmax_pred_ty {};

/// Helper class for identifying unordered min predicates.
struct ufmin_pred_ty {};

template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty> m_SMax(const LHS &L,
                                                             const RHS &R) {}

template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty> m_SMin(const LHS &L,
                                                             const RHS &R) {}

template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty> m_UMax(const LHS &L,
                                                             const RHS &R) {}

template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty> m_UMin(const LHS &L,
                                                             const RHS &R) {}

template <typename LHS, typename RHS>
inline match_combine_or<
    match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>,
                     MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>>,
    match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty>,
                     MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>>>
m_MaxOrMin(const LHS &L, const RHS &R) {}

/// 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) {}

/// 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.
///
///                         min(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) {}

/// 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_UnordFMax(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) {}

/// 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.
///
///                          min(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) {}

/// Matches a 'Not' as 'xor V, -1' or 'xor -1, V'.
/// NOTE: we first match the 'Not' (by matching '-1'),
/// and only then match the inner matcher!
template <typename ValTy>
inline BinaryOp_match<cst_pred_ty<is_all_ones>, ValTy, Instruction::Xor, true>
m_Not(const ValTy &V) {}

template <typename ValTy>
inline BinaryOp_match<cst_pred_ty<is_all_ones, false>, ValTy, Instruction::Xor,
                      true>
m_NotForbidPoison(const ValTy &V) {}

//===----------------------------------------------------------------------===//
// Matchers for overflow check patterns: e.g. (a + b) u< a, (a ^ -1) <u b
// Note that S might be matched to other instructions than AddInst.
//

template <typename LHS_t, typename RHS_t, typename Sum_t>
struct UAddWithOverflow_match {};

/// Match an icmp instruction checking for unsigned overflow on addition.
///
/// S is matched to the addition whose result is being checked for overflow, and
/// L and R are matched to the LHS and RHS of S.
template <typename LHS_t, typename RHS_t, typename Sum_t>
UAddWithOverflow_match<LHS_t, RHS_t, Sum_t>
m_UAddWithOverflow(const LHS_t &L, const RHS_t &R, const Sum_t &S) {}

template <typename Opnd_t> struct Argument_match {};

/// Match an argument.
template <unsigned OpI, typename Opnd_t>
inline Argument_match<Opnd_t> m_Argument(const Opnd_t &Op) {}

/// Intrinsic matchers.
struct IntrinsicID_match {};

/// Intrinsic matches are combinations of ID matchers, and argument
/// matchers. Higher arity matcher are defined recursively in terms of and-ing
/// them with lower arity matchers. Here's some convenient typedefs for up to
/// several arguments, and more can be added as needed
template <typename T0 = void, typename T1 = void, typename T2 = void,
          typename T3 = void, typename T4 = void, typename T5 = void,
          typename T6 = void, typename T7 = void, typename T8 = void,
          typename T9 = void, typename T10 = void>
struct m_Intrinsic_Ty;
m_Intrinsic_Ty<T0>;
m_Intrinsic_Ty<T0, T1>;
m_Intrinsic_Ty<T0, T1, T2>;
m_Intrinsic_Ty<T0, T1, T2, T3>;

m_Intrinsic_Ty<T0, T1, T2, T3, T4>;

m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5>;

/// Match intrinsic calls like this:
/// m_Intrinsic<Intrinsic::fabs>(m_Value(X))
template <Intrinsic::ID IntrID> inline IntrinsicID_match m_Intrinsic() {}

/// Matches MaskedLoad Intrinsic.
template <typename Opnd0, typename Opnd1, typename Opnd2, typename Opnd3>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2, Opnd3>::Ty
m_MaskedLoad(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2,
             const Opnd3 &Op3) {}

/// Matches MaskedGather Intrinsic.
template <typename Opnd0, typename Opnd1, typename Opnd2, typename Opnd3>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2, Opnd3>::Ty
m_MaskedGather(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2,
               const Opnd3 &Op3) {}

template <Intrinsic::ID IntrID, typename T0>
inline typename m_Intrinsic_Ty<T0>::Ty m_Intrinsic(const T0 &Op0) {}

template <Intrinsic::ID IntrID, typename T0, typename T1>
inline typename m_Intrinsic_Ty<T0, T1>::Ty m_Intrinsic(const T0 &Op0,
                                                       const T1 &Op1) {}

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) {}

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) {}

template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
          typename T3, typename T4>
inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty
m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
            const T4 &Op4) {}

template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
          typename T3, typename T4, typename T5>
inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5>::Ty
m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
            const T4 &Op4, const T5 &Op5) {}

// Helper intrinsic matching specializations.
template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_BitReverse(const Opnd0 &Op0) {}

template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_BSwap(const Opnd0 &Op0) {}

template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_FAbs(const Opnd0 &Op0) {}

template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_FCanonicalize(const Opnd0 &Op0) {}

template <typename Opnd0, typename Opnd1>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_FMin(const Opnd0 &Op0,
                                                        const Opnd1 &Op1) {}

template <typename Opnd0, typename Opnd1>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_FMax(const Opnd0 &Op0,
                                                        const Opnd1 &Op1) {}

template <typename Opnd0, typename Opnd1, typename Opnd2>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
m_FShl(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2) {}

template <typename Opnd0, typename Opnd1, typename Opnd2>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
m_FShr(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2) {}

template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_Sqrt(const Opnd0 &Op0) {}

template <typename Opnd0, typename Opnd1>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_CopySign(const Opnd0 &Op0,
                                                            const Opnd1 &Op1) {}

template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_VecReverse(const Opnd0 &Op0) {}

//===----------------------------------------------------------------------===//
// Matchers for two-operands operators with the operators in either order
//

/// Matches a BinaryOperator with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline AnyBinaryOp_match<LHS, RHS, true> m_c_BinOp(const LHS &L, const RHS &R) {}

/// Matches an ICmp with a predicate over LHS and RHS in either order.
/// Swaps the predicate if operands are commuted.
template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
m_c_ICmp(const LHS &L, const RHS &R) {}

/// Matches a specific opcode with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline SpecificBinaryOp_match<LHS, RHS, true>
m_c_BinOp(unsigned Opcode, const LHS &L, const RHS &R) {}

/// Matches a Add with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Add, true> m_c_Add(const LHS &L,
                                                                const RHS &R) {}

/// Matches a Mul with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Mul, true> m_c_Mul(const LHS &L,
                                                                const RHS &R) {}

/// Matches an And with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::And, true> m_c_And(const LHS &L,
                                                                const RHS &R) {}

/// Matches an Or with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Or, true> m_c_Or(const LHS &L,
                                                              const RHS &R) {}

/// Matches an Xor with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::Xor, true> m_c_Xor(const LHS &L,
                                                                const RHS &R) {}

/// Matches a 'Neg' as 'sub 0, V'.
template <typename ValTy>
inline BinaryOp_match<cst_pred_ty<is_zero_int>, ValTy, Instruction::Sub>
m_Neg(const ValTy &V) {}

/// Matches a 'Neg' as 'sub nsw 0, V'.
template <typename ValTy>
inline OverflowingBinaryOp_match<cst_pred_ty<is_zero_int>, ValTy,
                                 Instruction::Sub,
                                 OverflowingBinaryOperator::NoSignedWrap>
m_NSWNeg(const ValTy &V) {}

/// Matches an SMin with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>
m_c_SMin(const LHS &L, const RHS &R) {}
/// Matches an SMax with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty, true>
m_c_SMax(const LHS &L, const RHS &R) {}
/// Matches a UMin with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty, true>
m_c_UMin(const LHS &L, const RHS &R) {}
/// Matches a UMax with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>
m_c_UMax(const LHS &L, const RHS &R) {}

template <typename LHS, typename RHS>
inline match_combine_or<
    match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty, true>,
                     MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>>,
    match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>,
                     MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty, true>>>
m_c_MaxOrMin(const LHS &L, const RHS &R) {}

template <Intrinsic::ID IntrID, typename T0, typename T1>
inline match_combine_or<typename m_Intrinsic_Ty<T0, T1>::Ty,
                        typename m_Intrinsic_Ty<T1, T0>::Ty>
m_c_Intrinsic(const T0 &Op0, const T1 &Op1) {}

/// Matches FAdd with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FAdd, true>
m_c_FAdd(const LHS &L, const RHS &R) {}

/// Matches FMul with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FMul, true>
m_c_FMul(const LHS &L, const RHS &R) {}

template <typename Opnd_t> struct Signum_match {};

/// Matches a signum pattern.
///
/// signum(x) =
///      x >  0  ->  1
///      x == 0  ->  0
///      x <  0  -> -1
template <typename Val_t> inline Signum_match<Val_t> m_Signum(const Val_t &V) {}

template <int Ind, typename Opnd_t> struct ExtractValue_match {};

/// Match a single index ExtractValue instruction.
/// For example m_ExtractValue<1>(...)
template <int Ind, typename Val_t>
inline ExtractValue_match<Ind, Val_t> m_ExtractValue(const Val_t &V) {}

/// Match an ExtractValue instruction with any index.
/// For example m_ExtractValue(...)
template <typename Val_t>
inline ExtractValue_match<-1, Val_t> m_ExtractValue(const Val_t &V) {}

/// Matcher for a single index InsertValue instruction.
template <int Ind, typename T0, typename T1> struct InsertValue_match {};

/// Matches a single index InsertValue instruction.
template <int Ind, typename Val_t, typename Elt_t>
inline InsertValue_match<Ind, Val_t, Elt_t> m_InsertValue(const Val_t &Val,
                                                          const Elt_t &Elt) {}

/// Matches patterns for `vscale`. This can either be a call to `llvm.vscale` or
/// the constant expression
///  `ptrtoint(gep <vscale x 1 x i8>, <vscale x 1 x i8>* null, i32 1>`
/// under the right conditions determined by DataLayout.
struct VScaleVal_match {};

inline VScaleVal_match m_VScale() {}

template <typename Opnd0, typename Opnd1>
inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty
m_Interleave2(const Opnd0 &Op0, const Opnd1 &Op1) {}

template <typename Opnd>
inline typename m_Intrinsic_Ty<Opnd>::Ty m_Deinterleave2(const Opnd &Op) {}

template <typename LHS, typename RHS, unsigned Opcode, bool Commutable = false>
struct LogicalOp_match {};

/// Matches L && R either in the form of L & R or L ? R : false.
/// Note that the latter form is poison-blocking.
template <typename LHS, typename RHS>
inline LogicalOp_match<LHS, RHS, Instruction::And> m_LogicalAnd(const LHS &L,
                                                                const RHS &R) {}

/// Matches L && R where L and R are arbitrary values.
inline auto m_LogicalAnd() {}

/// Matches L && R with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline LogicalOp_match<LHS, RHS, Instruction::And, true>
m_c_LogicalAnd(const LHS &L, const RHS &R) {}

/// Matches L || R either in the form of L | R or L ? true : R.
/// Note that the latter form is poison-blocking.
template <typename LHS, typename RHS>
inline LogicalOp_match<LHS, RHS, Instruction::Or> m_LogicalOr(const LHS &L,
                                                              const RHS &R) {}

/// Matches L || R where L and R are arbitrary values.
inline auto m_LogicalOr() {}

/// Matches L || R with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline LogicalOp_match<LHS, RHS, Instruction::Or, true>
m_c_LogicalOr(const LHS &L, const RHS &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) {}

/// Matches either L && R or L || R where L and R are arbitrary values.
inline auto m_LogicalOp() {}

/// 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) {}

} // end namespace PatternMatch
} // end namespace llvm

#endif // LLVM_IR_PATTERNMATCH_H