//===- llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h -----------*- 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
//
//===----------------------------------------------------------------------===//
//
/// \file This file declares the GIMatchTableExecutor API, the opcodes supported
/// by the match table, and some associated data structures used by the
/// executor's implementation (see `GIMatchTableExecutorImpl.h`).
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTOR_H
#define LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTOR_H

#include "llvm/ADT/Bitset.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/LowLevelType.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/Function.h"
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <optional>
#include <vector>

namespace llvm {

class BlockFrequencyInfo;
class CodeGenCoverage;
class MachineBasicBlock;
class ProfileSummaryInfo;
class APInt;
class APFloat;
class GISelKnownBits;
class MachineInstr;
class MachineIRBuilder;
class MachineInstrBuilder;
class MachineFunction;
class MachineOperand;
class MachineRegisterInfo;
class RegisterBankInfo;
class TargetInstrInfo;
class TargetRegisterInfo;

enum {
  GICXXPred_Invalid = 0,
  GICXXCustomAction_Invalid = 0,
};

/// The MatchTable is encoded as an array of bytes.
/// Thus, opcodes are expected to be <255.
///
/// Operands can be variable-sized, their size is always after their name
/// in the docs, e.g. "Foo(4)" means that "Foo" takes 4 entries in the table,
/// so 4 bytes. "Foo()"
///
/// As a general rule of thumb:
///   - Instruction & Operand IDs are ULEB128
///   - LLT IDs are 1 byte
///   - Predicates and target opcodes, register and register class IDs are 2
///     bytes.
///   - Indexes into the table are 4 bytes.
///   - Inline constants are 8 bytes
///
/// Design notes:
///   - Inst/Op IDs have to be LEB128 because some targets generate
///     extremely long patterns which need more than 255 temporaries.
///     We could just use 2 bytes everytime, but then some targets like
///     X86/AMDGPU that have no need for it will pay the price all the time.
enum {
  /// Begin a try-block to attempt a match and jump to OnFail if it is
  /// unsuccessful.
  /// - OnFail(4) - The MatchTable entry at which to resume if the match fails.
  ///
  /// FIXME: This ought to take an argument indicating the number of try-blocks
  ///        to exit on failure. It's usually one but the last match attempt of
  ///        a block will need more. The (implemented) alternative is to tack a
  ///        GIM_Reject on the end of each try-block which is simpler but
  ///        requires an extra opcode and iteration in the interpreter on each
  ///        failed match.
  GIM_Try,

  /// Switch over the opcode on the specified instruction
  /// - InsnID(ULEB128) - Instruction ID
  /// - LowerBound(2) - numerically minimum opcode supported
  /// - UpperBound(2) - numerically maximum + 1 opcode supported
  /// - Default(4) - failure jump target
  /// - JumpTable(4)... - (UpperBound - LowerBound) (at least 2) jump targets
  GIM_SwitchOpcode,

  /// Switch over the LLT on the specified instruction operand
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - LowerBound(2) - numerically minimum Type ID supported
  /// - UpperBound(2) - numerically maximum + 1 Type ID supported
  /// - Default(4) - failure jump target
  /// - JumpTable(4)... - (UpperBound - LowerBound) (at least 2) jump targets
  GIM_SwitchType,

  /// Record the specified instruction.
  /// The IgnoreCopies variant ignores COPY instructions.
  /// - NewInsnID(ULEB128) - Instruction ID to define
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  GIM_RecordInsn,
  GIM_RecordInsnIgnoreCopies,

  /// Check the feature bits
  ///   Feature(2) - Expected features
  GIM_CheckFeatures,

  /// Check the opcode on the specified instruction
  /// - InsnID(ULEB128) - Instruction ID
  /// - Opc(2) - Expected opcode
  GIM_CheckOpcode,

  /// Check the opcode on the specified instruction, checking 2 acceptable
  /// alternatives.
  /// - InsnID(ULEB128) - Instruction ID
  /// - Opc(2) - Expected opcode
  /// - Opc(2) - Alternative expected opcode
  GIM_CheckOpcodeIsEither,

  /// Check the instruction has the right number of operands
  /// - InsnID(ULEB128) - Instruction ID
  /// - Ops(ULEB128) - Expected number of operands
  GIM_CheckNumOperands,

  /// Check an immediate predicate on the specified instruction
  /// - InsnID(ULEB128) - Instruction ID
  /// - Pred(2) - The predicate to test
  GIM_CheckI64ImmPredicate,
  /// Check an immediate predicate on the specified instruction via an APInt.
  /// - InsnID(ULEB128) - Instruction ID
  /// - Pred(2) - The predicate to test
  GIM_CheckAPIntImmPredicate,
  /// Check a floating point immediate predicate on the specified instruction.
  /// - InsnID(ULEB128) - Instruction ID
  /// - Pred(2) - The predicate to test
  GIM_CheckAPFloatImmPredicate,
  /// Check an immediate predicate on the specified instruction
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - Pred(2) - The predicate to test
  GIM_CheckImmOperandPredicate,

  /// Check a memory operation has the specified atomic ordering.
  /// - InsnID(ULEB128) - Instruction ID
  /// - Ordering(ULEB128) - The AtomicOrdering value
  GIM_CheckAtomicOrdering,
  GIM_CheckAtomicOrderingOrStrongerThan,
  GIM_CheckAtomicOrderingWeakerThan,

  /// Check the size of the memory access for the given machine memory operand.
  /// - InsnID(ULEB128) - Instruction ID
  /// - MMOIdx(ULEB128) - MMO index
  /// - Size(4) - The size in bytes of the memory access
  GIM_CheckMemorySizeEqualTo,

  /// Check the address space of the memory access for the given machine memory
  /// operand.
  /// - InsnID(ULEB128) - Instruction ID
  /// - MMOIdx(ULEB128) - MMO index
  /// - NumAddrSpace(ULEB128) - Number of valid address spaces
  /// - AddrSpaceN(ULEB128) - An allowed space of the memory access
  /// - AddrSpaceN+1 ...
  GIM_CheckMemoryAddressSpace,

  /// Check the minimum alignment of the memory access for the given machine
  /// memory operand.
  /// - InsnID(ULEB128) - Instruction ID
  /// - MMOIdx(ULEB128) - MMO index
  /// - MinAlign(ULEB128) - Minimum acceptable alignment
  GIM_CheckMemoryAlignment,

  /// Check the size of the memory access for the given machine memory operand
  /// against the size of an operand.
  /// - InsnID(ULEB128) - Instruction ID
  /// - MMOIdx(ULEB128) - MMO index
  /// - OpIdx(ULEB128) - The operand index to compare the MMO against
  GIM_CheckMemorySizeEqualToLLT,
  GIM_CheckMemorySizeLessThanLLT,
  GIM_CheckMemorySizeGreaterThanLLT,

  /// Check if this is a vector that can be treated as a vector splat
  /// constant. This is valid for both G_BUILD_VECTOR as well as
  /// G_BUILD_VECTOR_TRUNC. For AllOnes refers to individual bits, so a -1
  /// element.
  /// - InsnID(ULEB128) - Instruction ID
  GIM_CheckIsBuildVectorAllOnes,
  GIM_CheckIsBuildVectorAllZeros,

  /// Check a trivial predicate which takes no arguments.
  /// This can be used by executors to implement custom flags that don't fit in
  /// target features.
  /// - Pred(2) - Predicate ID to check.
  GIM_CheckSimplePredicate,

  /// Check a generic C++ instruction predicate
  /// - InsnID(ULEB128) - Instruction ID
  /// - PredicateID(2) - The ID of the predicate function to call
  GIM_CheckCxxInsnPredicate,

  /// Check if there's no use of the first result.
  /// - InsnID(ULEB128) - Instruction ID
  GIM_CheckHasNoUse,

  /// Check the type for the specified operand
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - Ty(1) - Expected type
  GIM_CheckType,

  /// Check the type of a pointer to any address space.
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - SizeInBits(ULEB128) - The size of the pointer value in bits.
  GIM_CheckPointerToAny,

  /// Check the register bank for the specified operand
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - RC(2) - Expected register bank (specified as a register class)
  GIM_CheckRegBankForClass,

  /// Check the operand matches a complex predicate
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - RendererID(2) - The renderer to hold the result
  /// - Pred(2) - Complex predicate ID
  GIM_CheckComplexPattern,

  /// Check the operand is a specific integer
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - Val(8) Expected integer
  GIM_CheckConstantInt,

  /// Check the operand is a specific 8-bit signed integer
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - Val(1) Expected integer
  GIM_CheckConstantInt8,

  /// Check the operand is a specific literal integer (i.e. MO.isImm() or
  /// MO.isCImm() is true).
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - Val(8) - Expected integer
  GIM_CheckLiteralInt,

  /// Check the operand is a specific intrinsic ID
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - IID(2) - Expected Intrinsic ID
  GIM_CheckIntrinsicID,

  /// Check the operand is a specific predicate
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - Pred(2) - Expected predicate
  GIM_CheckCmpPredicate,

  /// Check the specified operand is an MBB
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  GIM_CheckIsMBB,

  /// Check the specified operand is an Imm
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  GIM_CheckIsImm,

  /// Check if the specified operand is safe to fold into the current
  /// instruction.
  /// - InsnID(ULEB128) - Instruction ID
  GIM_CheckIsSafeToFold,

  /// Check the specified operands are identical.
  /// The IgnoreCopies variant looks through COPY instructions before
  /// comparing the operands.
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - OtherInsnID(ULEB128) - Other instruction ID
  /// - OtherOpIdx(ULEB128) - Other operand index
  GIM_CheckIsSameOperand,
  GIM_CheckIsSameOperandIgnoreCopies,

  /// Check we can replace all uses of a register with another.
  /// - OldInsnID(ULEB128)
  /// - OldOpIdx(ULEB128)
  /// - NewInsnID(ULEB128)
  /// - NewOpIdx(ULEB128)
  GIM_CheckCanReplaceReg,

  /// Check that a matched instruction has, or doesn't have a MIFlag.
  ///
  /// - InsnID(ULEB128) - Instruction to check.
  /// - Flags(4) - (can be one or more flags OR'd together)
  GIM_MIFlags,
  GIM_MIFlagsNot,

  /// Predicates with 'let PredicateCodeUsesOperands = 1' need to examine some
  /// named operands that will be recorded in RecordedOperands. Names of these
  /// operands are referenced in predicate argument list. Emitter determines
  /// StoreIdx(corresponds to the order in which names appear in argument list).
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - StoreIdx(ULEB128) - Store location in RecordedOperands.
  GIM_RecordNamedOperand,

  /// Records an operand's register type into the set of temporary types.
  /// - InsnID(ULEB128) - Instruction ID
  /// - OpIdx(ULEB128) - Operand index
  /// - TempTypeIdx(1) - Temp Type Index, always negative.
  GIM_RecordRegType,

  /// Fail the current try-block, or completely fail to match if there is no
  /// current try-block.
  GIM_Reject,

  //=== Renderers ===

  /// Mutate an instruction
  /// - NewInsnID(ULEB128) - Instruction ID to define
  /// - OldInsnID(ULEB128) - Instruction ID to mutate
  /// - NewOpcode(2) - The new opcode to use
  GIR_MutateOpcode,

  /// Build a new instruction
  /// - InsnID(ULEB128) - Instruction ID to define
  /// - Opcode(2) - The new opcode to use
  GIR_BuildMI,

  /// Builds a constant and stores its result in a TempReg.
  /// - TempRegID(ULEB128) - Temp Register to define.
  /// - Imm(8) - The immediate to add
  GIR_BuildConstant,

  /// Copy an operand to the specified instruction
  /// - NewInsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to copy from
  /// - OpIdx(ULEB128) - The operand to copy
  GIR_Copy,

  /// Copy an operand to the specified instruction or add a zero register if the
  /// operand is a zero immediate.
  /// - NewInsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to copy from
  /// - OpIdx(ULEB128) - The operand to copy
  /// - ZeroReg(2) - The zero register to use
  GIR_CopyOrAddZeroReg,
  /// Copy an operand to the specified instruction
  /// - NewInsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to copy from
  /// - OpIdx(ULEB128) - The operand to copy
  /// - SubRegIdx(2) - The subregister to copy
  GIR_CopySubReg,

  /// Add an implicit register def to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - RegNum(2) - The register to add
  /// - Flags(2) - Register Flags
  GIR_AddImplicitDef,
  /// Add an implicit register use to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - RegNum(2) - The register to add
  GIR_AddImplicitUse,
  /// Add an register to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - RegNum(2) - The register to add
  /// - Flags(2) - Register Flags
  GIR_AddRegister,

  /// Marks the implicit def of a register as dead.
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - OpIdx(ULEB128) - The implicit def operand index
  ///
  /// OpIdx starts at 0 for the first implicit def.
  GIR_SetImplicitDefDead,

  /// Set or unset a MIFlag on an instruction.
  ///
  /// - InsnID(ULEB128)  - Instruction to modify.
  /// - Flags(4) - (can be one or more flags OR'd together)
  GIR_SetMIFlags,
  GIR_UnsetMIFlags,

  /// Copy the MIFlags of a matched instruction into an
  /// output instruction. The flags are OR'd together.
  ///
  /// - InsnID(ULEB128)     - Instruction to modify.
  /// - OldInsnID(ULEB128)  - Matched instruction to copy flags from.
  GIR_CopyMIFlags,

  /// Add a temporary register to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - TempRegID(ULEB128) - The temporary register ID to add
  /// - TempRegFlags(2) - The register flags to set
  GIR_AddTempRegister,

  /// Add a temporary register to the specified instruction without
  /// setting any flags.
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - TempRegID(ULEB128) - The temporary register ID to add
  GIR_AddSimpleTempRegister,

  /// Add a temporary register to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - TempRegID(ULEB128) - The temporary register ID to add
  /// - TempRegFlags(2) - The register flags to set
  /// - SubRegIndex(2) - The subregister index to set
  GIR_AddTempSubRegister,

  /// Add an immediate to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - Imm(8) - The immediate to add
  GIR_AddImm,

  /// Add signed 8 bit immediate to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - Imm(1) - The immediate to add
  GIR_AddImm8,

  /// Add an CImm to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - Ty(1) - Type of the constant immediate.
  /// - Imm(8) - The immediate to add
  GIR_AddCImm,

  /// Render complex operands to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - RendererID(2) - The renderer to call
  GIR_ComplexRenderer,
  /// Render sub-operands of complex operands to the specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - RendererID(2) - The renderer to call
  /// - RenderOpID(ULEB128) - The suboperand to render.
  GIR_ComplexSubOperandRenderer,
  /// Render subregisters of suboperands of complex operands to the
  /// specified instruction
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - RendererID(2) - The renderer to call
  /// - RenderOpID(ULEB128) - The suboperand to render
  /// - SubRegIdx(2) - The subregister to extract
  GIR_ComplexSubOperandSubRegRenderer,

  /// Render operands to the specified instruction using a custom function
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to get the matched operand from
  /// - RendererFnID(2) - Custom renderer function to call
  GIR_CustomRenderer,

  /// Calls a C++ function to perform an action when a match is complete.
  /// The MatcherState is passed to the function to allow it to modify
  /// instructions.
  /// This is less constrained than a custom renderer and can update
  /// instructions
  /// in the state.
  /// - FnID(2) - The function to call.
  /// TODO: Remove this at some point when combiners aren't reliant on it. It's
  /// a bit of a hack.
  GIR_CustomAction,

  /// Render operands to the specified instruction using a custom function,
  /// reading from a specific operand.
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to get the matched operand from
  /// - OpIdx(ULEB128) - Operand index in OldInsnID the render function should
  /// read
  /// from..
  /// - RendererFnID(2) - Custom renderer function to call
  GIR_CustomOperandRenderer,

  /// Render a G_CONSTANT operator as a sign-extended immediate.
  /// - NewInsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to copy from
  /// The operand index is implicitly 1.
  GIR_CopyConstantAsSImm,

  /// Render a G_FCONSTANT operator as a sign-extended immediate.
  /// - NewInsnID(ULEB128) - Instruction ID to modify
  /// - OldInsnID(ULEB128) - Instruction ID to copy from
  /// The operand index is implicitly 1.
  GIR_CopyFConstantAsFPImm,

  /// Constrain an instruction operand to a register class.
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - OpIdx(ULEB128) - Operand index
  /// - RCEnum(2) - Register class enumeration value
  GIR_ConstrainOperandRC,

  /// Constrain an instructions operands according to the instruction
  /// description.
  /// - InsnID(ULEB128) - Instruction ID to modify
  GIR_ConstrainSelectedInstOperands,

  /// Merge all memory operands into instruction.
  /// - InsnID(ULEB128) - Instruction ID to modify
  /// - NumInsnID(1) - Number of instruction IDs following this argument
  /// - MergeInsnID(ULEB128)... - One or more Instruction ID to merge into the
  /// result.
  GIR_MergeMemOperands,

  /// Erase from parent.
  /// - InsnID(ULEB128) - Instruction ID to erase
  GIR_EraseFromParent,

  /// Create a new temporary register that's not constrained.
  /// - TempRegID(ULEB128) - The temporary register ID to initialize.
  /// - Ty(1) - Expected type
  GIR_MakeTempReg,

  /// Replaces all references to a register from an instruction
  /// with another register from another instruction.
  /// - OldInsnID(ULEB128)
  /// - OldOpIdx(ULEB128)
  /// - NewInsnID(ULEB128)
  /// - NewOpIdx(ULEB128)
  GIR_ReplaceReg,

  /// Replaces all references to a register with a temporary register.
  /// - OldInsnID(ULEB128)
  /// - OldOpIdx(ULEB128)
  /// - TempRegIdx(ULEB128)
  GIR_ReplaceRegWithTempReg,

  /// A successful emission
  GIR_Done,

  /// Increment the rule coverage counter.
  /// - RuleID(4) - The ID of the rule that was covered.
  GIR_Coverage,

  /// Keeping track of the number of the GI opcodes. Must be the last entry.
  GIU_NumOpcodes,
};

/// Provides the logic to execute GlobalISel match tables, which are used by the
/// instruction selector and instruction combiners as their engine to match and
/// apply MIR patterns.
class GIMatchTableExecutor {
public:
  virtual ~GIMatchTableExecutor() = default;

  CodeGenCoverage *CoverageInfo = nullptr;
  GISelKnownBits *KB = nullptr;
  MachineFunction *MF = nullptr;
  ProfileSummaryInfo *PSI = nullptr;
  BlockFrequencyInfo *BFI = nullptr;
  // For some predicates, we need to track the current MBB.
  MachineBasicBlock *CurMBB = nullptr;

  virtual void setupGeneratedPerFunctionState(MachineFunction &MF) = 0;

  /// Setup per-MF executor state.
  virtual void setupMF(MachineFunction &mf, GISelKnownBits *kb,
                       CodeGenCoverage *covinfo = nullptr,
                       ProfileSummaryInfo *psi = nullptr,
                       BlockFrequencyInfo *bfi = nullptr) {
    CoverageInfo = covinfo;
    KB = kb;
    MF = &mf;
    PSI = psi;
    BFI = bfi;
    CurMBB = nullptr;
    setupGeneratedPerFunctionState(mf);
  }

protected:
  using ComplexRendererFns =
      std::optional<SmallVector<std::function<void(MachineInstrBuilder &)>, 4>>;
  using RecordedMIVector = SmallVector<MachineInstr *, 4>;
  using NewMIVector = SmallVector<MachineInstrBuilder, 4>;

  struct MatcherState {
    std::vector<ComplexRendererFns::value_type> Renderers;
    RecordedMIVector MIs;
    DenseMap<unsigned, unsigned> TempRegisters;
    /// Named operands that predicate with 'let PredicateCodeUsesOperands = 1'
    /// referenced in its argument list. Operands are inserted at index set by
    /// emitter, it corresponds to the order in which names appear in argument
    /// list. Currently such predicates don't have more then 3 arguments.
    std::array<const MachineOperand *, 3> RecordedOperands;

    /// Types extracted from an instruction's operand.
    /// Whenever a type index is negative, we look here instead.
    SmallVector<LLT, 4> RecordedTypes;

    MatcherState(unsigned MaxRenderers);
  };

  bool shouldOptForSize(const MachineFunction *MF) const {
    const auto &F = MF->getFunction();
    return F.hasOptSize() || F.hasMinSize() ||
           (PSI && BFI && CurMBB && llvm::shouldOptForSize(*CurMBB, PSI, BFI));
  }

public:
  template <class PredicateBitset, class ComplexMatcherMemFn,
            class CustomRendererFn>
  struct ExecInfoTy {
    ExecInfoTy(const LLT *TypeObjects, size_t NumTypeObjects,
               const PredicateBitset *FeatureBitsets,
               const ComplexMatcherMemFn *ComplexPredicates,
               const CustomRendererFn *CustomRenderers)
        : TypeObjects(TypeObjects), FeatureBitsets(FeatureBitsets),
          ComplexPredicates(ComplexPredicates),
          CustomRenderers(CustomRenderers) {

      for (size_t I = 0; I < NumTypeObjects; ++I)
        TypeIDMap[TypeObjects[I]] = I;
    }
    const LLT *TypeObjects;
    const PredicateBitset *FeatureBitsets;
    const ComplexMatcherMemFn *ComplexPredicates;
    const CustomRendererFn *CustomRenderers;

    SmallDenseMap<LLT, unsigned, 64> TypeIDMap;
  };

protected:
  GIMatchTableExecutor();

  /// Execute a given matcher table and return true if the match was successful
  /// and false otherwise.
  template <class TgtExecutor, class PredicateBitset, class ComplexMatcherMemFn,
            class CustomRendererFn>
  bool executeMatchTable(TgtExecutor &Exec, MatcherState &State,
                         const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn,
                                          CustomRendererFn> &ExecInfo,
                         MachineIRBuilder &Builder, const uint8_t *MatchTable,
                         const TargetInstrInfo &TII, MachineRegisterInfo &MRI,
                         const TargetRegisterInfo &TRI,
                         const RegisterBankInfo &RBI,
                         const PredicateBitset &AvailableFeatures,
                         CodeGenCoverage *CoverageInfo) const;

  virtual const uint8_t *getMatchTable() const {
    llvm_unreachable("Should have been overridden by tablegen if used");
  }

  virtual bool testImmPredicate_I64(unsigned, int64_t) const {
    llvm_unreachable(
        "Subclasses must override this with a tablegen-erated function");
  }
  virtual bool testImmPredicate_APInt(unsigned, const APInt &) const {
    llvm_unreachable(
        "Subclasses must override this with a tablegen-erated function");
  }
  virtual bool testImmPredicate_APFloat(unsigned, const APFloat &) const {
    llvm_unreachable(
        "Subclasses must override this with a tablegen-erated function");
  }
  virtual bool testMIPredicate_MI(unsigned, const MachineInstr &,
                                  const MatcherState &State) const {
    llvm_unreachable(
        "Subclasses must override this with a tablegen-erated function");
  }

  virtual bool testSimplePredicate(unsigned) const {
    llvm_unreachable("Subclass does not implement testSimplePredicate!");
  }

  virtual void runCustomAction(unsigned, const MatcherState &State,
                               NewMIVector &OutMIs) const {
    llvm_unreachable("Subclass does not implement runCustomAction!");
  }

  bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
                         const MachineRegisterInfo &MRI,
                         bool Splat = false) const;

  /// Return true if the specified operand is a G_PTR_ADD with a G_CONSTANT on
  /// the right-hand side. GlobalISel's separation of pointer and integer types
  /// means that we don't need to worry about G_OR with equivalent semantics.
  bool isBaseWithConstantOffset(const MachineOperand &Root,
                                const MachineRegisterInfo &MRI) const;

  /// Return true if MI can obviously be folded into IntoMI.
  /// MI and IntoMI do not need to be in the same basic blocks, but MI must
  /// preceed IntoMI.
  bool isObviouslySafeToFold(MachineInstr &MI, MachineInstr &IntoMI) const;

  template <typename Ty> static Ty readBytesAs(const uint8_t *MatchTable) {
    Ty Ret;
    memcpy(&Ret, MatchTable, sizeof(Ret));
    return Ret;
  }
};

} // end namespace llvm

#endif // LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTOR_H
