//===- llvm/CodeGen/GlobalISel/InstructionSelector.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 API for the instruction selector.
 
/// This class is responsible for selecting machine instructions.
 
/// It's implemented by the target. It's used by the InstructionSelect pass.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
 
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
 
 
 
#include "llvm/ADT/DenseMap.h"
 
#include "llvm/ADT/SmallVector.h"
 
#include "llvm/CodeGen/GlobalISel/Utils.h"
 
#include "llvm/CodeGen/MachineFunction.h"
 
#include "llvm/IR/Function.h"
 
#include "llvm/Support/LowLevelTypeImpl.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 MachineInstrBuilder;
 
class MachineFunction;
 
class MachineOperand;
 
class MachineRegisterInfo;
 
class RegisterBankInfo;
 
class TargetInstrInfo;
 
class TargetRegisterInfo;
 
 
 
/// Container class for CodeGen predicate results.
 
/// This is convenient because std::bitset does not have a constructor
 
/// with an initializer list of set bits.
 
///
 
/// Each InstructionSelector subclass should define a PredicateBitset class
 
/// with:
 
///   const unsigned MAX_SUBTARGET_PREDICATES = 192;
 
///   using PredicateBitset = PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
 
/// and updating the constant to suit the target. Tablegen provides a suitable
 
/// definition for the predicates in use in <Target>GenGlobalISel.inc when
 
/// GET_GLOBALISEL_PREDICATE_BITSET is defined.
 
template <std::size_t MaxPredicates>
 
class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
 
public:
 
  // Cannot inherit constructors because it's not supported by VC++..
 
  PredicateBitsetImpl() = default;
 
 
 
  PredicateBitsetImpl(const std::bitset<MaxPredicates> &B)
 
      : std::bitset<MaxPredicates>(B) {}
 
 
 
  PredicateBitsetImpl(std::initializer_list<unsigned> Init) {
 
    for (auto I : Init)
 
      std::bitset<MaxPredicates>::set(I);
 
  }
 
};
 
 
 
enum {
 
  /// Begin a try-block to attempt a match and jump to OnFail if it is
 
  /// unsuccessful.
 
  /// - OnFail - 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 - Instruction ID
 
  /// - LowerBound - numerically minimum opcode supported
 
  /// - UpperBound - numerically maximum + 1 opcode supported
 
  /// - Default - failure jump target
 
  /// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
 
  GIM_SwitchOpcode,
 
 
 
  /// Switch over the LLT on the specified instruction operand
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - LowerBound - numerically minimum Type ID supported
 
  /// - UpperBound - numerically maximum + 1 Type ID supported
 
  /// - Default - failure jump target
 
  /// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
 
  GIM_SwitchType,
 
 
 
  /// Record the specified instruction
 
  /// - NewInsnID - Instruction ID to define
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  GIM_RecordInsn,
 
 
 
  /// Check the feature bits
 
  /// - Expected features
 
  GIM_CheckFeatures,
 
 
 
  /// Check the opcode on the specified instruction
 
  /// - InsnID - Instruction ID
 
  /// - Expected opcode
 
  GIM_CheckOpcode,
 
 
 
  /// Check the opcode on the specified instruction, checking 2 acceptable
 
  /// alternatives.
 
  /// - InsnID - Instruction ID
 
  /// - Expected opcode
 
  /// - Alternative expected opcode
 
  GIM_CheckOpcodeIsEither,
 
 
 
  /// Check the instruction has the right number of operands
 
  /// - InsnID - Instruction ID
 
  /// - Expected number of operands
 
  GIM_CheckNumOperands,
 
  /// Check an immediate predicate on the specified instruction
 
  /// - InsnID - Instruction ID
 
  /// - The predicate to test
 
  GIM_CheckI64ImmPredicate,
 
  /// Check an immediate predicate on the specified instruction via an APInt.
 
  /// - InsnID - Instruction ID
 
  /// - The predicate to test
 
  GIM_CheckAPIntImmPredicate,
 
  /// Check a floating point immediate predicate on the specified instruction.
 
  /// - InsnID - Instruction ID
 
  /// - The predicate to test
 
  GIM_CheckAPFloatImmPredicate,
 
  /// Check an immediate predicate on the specified instruction
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - The predicate to test
 
  GIM_CheckImmOperandPredicate,
 
  /// Check a memory operation has the specified atomic ordering.
 
  /// - InsnID - Instruction ID
 
  /// - Ordering - The AtomicOrdering value
 
  GIM_CheckAtomicOrdering,
 
  GIM_CheckAtomicOrderingOrStrongerThan,
 
  GIM_CheckAtomicOrderingWeakerThan,
 
  /// Check the size of the memory access for the given machine memory operand.
 
  /// - InsnID - Instruction ID
 
  /// - MMOIdx - MMO index
 
  /// - Size - 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 - Instruction ID
 
  /// - MMOIdx - MMO index
 
  /// - NumAddrSpace - Number of valid address spaces
 
  /// - AddrSpaceN - 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 - Instruction ID
 
  /// - MMOIdx - MMO index
 
  /// - MinAlign - 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 - Instruction ID
 
  /// - MMOIdx - MMO index
 
  /// - OpIdx - 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 - Instruction ID
 
  GIM_CheckIsBuildVectorAllOnes,
 
  GIM_CheckIsBuildVectorAllZeros,
 
 
 
  /// Check a generic C++ instruction predicate
 
  /// - InsnID - Instruction ID
 
  /// - PredicateID - The ID of the predicate function to call
 
  GIM_CheckCxxInsnPredicate,
 
 
 
  /// Check if there's no use of the first result.
 
  /// - InsnID - Instruction ID
 
  GIM_CheckHasNoUse,
 
 
 
  /// Check the type for the specified operand
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - Expected type
 
  GIM_CheckType,
 
  /// Check the type of a pointer to any address space.
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - SizeInBits - The size of the pointer value in bits.
 
  GIM_CheckPointerToAny,
 
  /// Check the register bank for the specified operand
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - Expected register bank (specified as a register class)
 
  GIM_CheckRegBankForClass,
 
 
 
  /// Check the operand matches a complex predicate
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - RendererID - The renderer to hold the result
 
  /// - Complex predicate ID
 
  GIM_CheckComplexPattern,
 
 
 
  /// Check the operand is a specific integer
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - Expected integer
 
  GIM_CheckConstantInt,
 
  /// Check the operand is a specific literal integer (i.e. MO.isImm() or
 
  /// MO.isCImm() is true).
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - Expected integer
 
  GIM_CheckLiteralInt,
 
  /// Check the operand is a specific intrinsic ID
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - Expected Intrinsic ID
 
  GIM_CheckIntrinsicID,
 
 
 
  /// Check the operand is a specific predicate
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - Expected predicate
 
  GIM_CheckCmpPredicate,
 
 
 
  /// Check the specified operand is an MBB
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  GIM_CheckIsMBB,
 
 
 
  /// Check the specified operand is an Imm
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  GIM_CheckIsImm,
 
 
 
  /// Check if the specified operand is safe to fold into the current
 
  /// instruction.
 
  /// - InsnID - Instruction ID
 
  GIM_CheckIsSafeToFold,
 
 
 
  /// Check the specified operands are identical.
 
  /// - InsnID - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - OtherInsnID - Other instruction ID
 
  /// - OtherOpIdx - Other operand index
 
  GIM_CheckIsSameOperand,
 
 
 
  /// 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 - Instruction ID
 
  /// - OpIdx - Operand index
 
  /// - StoreIdx - Store location in RecordedOperands.
 
  GIM_RecordNamedOperand,
 
 
 
  /// Fail the current try-block, or completely fail to match if there is no
 
  /// current try-block.
 
  GIM_Reject,
 
 
 
  //=== Renderers ===
 
 
 
  /// Mutate an instruction
 
  /// - NewInsnID - Instruction ID to define
 
  /// - OldInsnID - Instruction ID to mutate
 
  /// - NewOpcode - The new opcode to use
 
  GIR_MutateOpcode,
 
 
 
  /// Build a new instruction
 
  /// - InsnID - Instruction ID to define
 
  /// - Opcode - The new opcode to use
 
  GIR_BuildMI,
 
 
 
  /// Copy an operand to the specified instruction
 
  /// - NewInsnID - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to copy from
 
  /// - OpIdx - 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 - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to copy from
 
  /// - OpIdx - The operand to copy
 
  /// - ZeroReg - The zero register to use
 
  GIR_CopyOrAddZeroReg,
 
  /// Copy an operand to the specified instruction
 
  /// - NewInsnID - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to copy from
 
  /// - OpIdx - The operand to copy
 
  /// - SubRegIdx - The subregister to copy
 
  GIR_CopySubReg,
 
 
 
  /// Add an implicit register def to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - RegNum - The register to add
 
  GIR_AddImplicitDef,
 
  /// Add an implicit register use to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - RegNum - The register to add
 
  GIR_AddImplicitUse,
 
  /// Add an register to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - RegNum - The register to add
 
  GIR_AddRegister,
 
 
 
  /// Add a temporary register to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - TempRegID - The temporary register ID to add
 
  /// - TempRegFlags - The register flags to set
 
  GIR_AddTempRegister,
 
 
 
  /// Add a temporary register to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - TempRegID - The temporary register ID to add
 
  /// - TempRegFlags - The register flags to set
 
  /// - SubRegIndex - The subregister index to set
 
  GIR_AddTempSubRegister,
 
 
 
  /// Add an immediate to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - Imm - The immediate to add
 
  GIR_AddImm,
 
  /// Render complex operands to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - RendererID - The renderer to call
 
  GIR_ComplexRenderer,
 
 
 
  /// Render sub-operands of complex operands to the specified instruction
 
  /// - InsnID - Instruction ID to modify
 
  /// - RendererID - The renderer to call
 
  /// - RenderOpID - The suboperand to render.
 
  GIR_ComplexSubOperandRenderer,
 
  /// Render operands to the specified instruction using a custom function
 
  /// - InsnID - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to get the matched operand from
 
  /// - RendererFnID - Custom renderer function to call
 
  GIR_CustomRenderer,
 
 
 
  /// Render operands to the specified instruction using a custom function,
 
  /// reading from a specific operand.
 
  /// - InsnID - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to get the matched operand from
 
  /// - OpIdx - Operand index in OldInsnID the render function should read from..
 
  /// - RendererFnID - Custom renderer function to call
 
  GIR_CustomOperandRenderer,
 
 
 
  /// Render a G_CONSTANT operator as a sign-extended immediate.
 
  /// - NewInsnID - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to copy from
 
  /// The operand index is implicitly 1.
 
  GIR_CopyConstantAsSImm,
 
 
 
  /// Render a G_FCONSTANT operator as a sign-extended immediate.
 
  /// - NewInsnID - Instruction ID to modify
 
  /// - OldInsnID - Instruction ID to copy from
 
  /// The operand index is implicitly 1.
 
  GIR_CopyFConstantAsFPImm,
 
 
 
  /// Constrain an instruction operand to a register class.
 
  /// - InsnID - Instruction ID to modify
 
  /// - OpIdx - Operand index
 
  /// - RCEnum - Register class enumeration value
 
  GIR_ConstrainOperandRC,
 
 
 
  /// Constrain an instructions operands according to the instruction
 
  /// description.
 
  /// - InsnID - Instruction ID to modify
 
  GIR_ConstrainSelectedInstOperands,
 
 
 
  /// Merge all memory operands into instruction.
 
  /// - InsnID - Instruction ID to modify
 
  /// - MergeInsnID... - One or more Instruction ID to merge into the result.
 
  /// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to
 
  ///                                    merge.
 
  GIR_MergeMemOperands,
 
 
 
  /// Erase from parent.
 
  /// - InsnID - Instruction ID to erase
 
  GIR_EraseFromParent,
 
 
 
  /// Create a new temporary register that's not constrained.
 
  /// - TempRegID - The temporary register ID to initialize.
 
  /// - Expected type
 
  GIR_MakeTempReg,
 
 
 
  /// A successful emission
 
  GIR_Done,
 
 
 
  /// Increment the rule coverage counter.
 
  /// - RuleID - 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,
 
};
 
 
 
enum {
 
  /// Indicates the end of the variable-length MergeInsnID list in a
 
  /// GIR_MergeMemOperands opcode.
 
  GIU_MergeMemOperands_EndOfList = -1,
 
};
 
 
 
/// Provides the logic to select generic machine instructions.
 
class InstructionSelector {
 
public:
 
  virtual ~InstructionSelector() = default;
 
 
 
  /// Select the (possibly generic) instruction \p I to only use target-specific
 
  /// opcodes. It is OK to insert multiple instructions, but they cannot be
 
  /// generic pre-isel instructions.
 
  ///
 
  /// \returns whether selection succeeded.
 
  /// \pre  I.getParent() && I.getParent()->getParent()
 
  /// \post
 
  ///   if returns true:
 
  ///     for I in all mutated/inserted instructions:
 
  ///       !isPreISelGenericOpcode(I.getOpcode())
 
  virtual bool select(MachineInstr &I) = 0;
 
 
 
  CodeGenCoverage *CoverageInfo = nullptr;
 
  GISelKnownBits *KnownBits = 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) {
 
    llvm_unreachable("TableGen should have emitted implementation");
 
  }
 
 
 
  /// Setup per-MF selector state.
 
  virtual void setupMF(MachineFunction &mf, GISelKnownBits *KB,
 
                       CodeGenCoverage &covinfo, ProfileSummaryInfo *psi,
 
                       BlockFrequencyInfo *bfi) {
 
    CoverageInfo = &covinfo;
 
    KnownBits = 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;
 
 
 
    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 ISelInfoTy {
 
    ISelInfoTy(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:
 
  InstructionSelector();
 
 
 
  /// Execute a given matcher table and return true if the match was successful
 
  /// and false otherwise.
 
  template <class TgtInstructionSelector, class PredicateBitset,
 
            class ComplexMatcherMemFn, class CustomRendererFn>
 
  bool executeMatchTable(
 
      TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
 
      const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
 
          &ISelInfo,
 
      const int64_t *MatchTable, const TargetInstrInfo &TII,
 
      MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
 
      const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
 
      CodeGenCoverage &CoverageInfo) const;
 
 
 
  virtual const int64_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 std::array<const MachineOperand *, 3> &Operands) const {
 
    llvm_unreachable(
 
        "Subclasses must override this with a tablegen-erated function");
 
  }
 
 
 
  bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
 
                         const MachineRegisterInfo &MRI) 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;
 
};
 
 
 
} // end namespace llvm
 
 
 
#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H