[GlobalISel] Generalize InstructionSelector Match Tables

Makes `InstructionSelector.h`/`InstructionSelectorImpl.h` generic so the match tables can also be used for the combiner.

Some notes:
 - Coverage was made an optional parameter of `executeMatchTable`, combines won't use it for now.
 - `GIPFP_` -> `GICXXPred_` so it's more generic. Those are just C++ predicates and aren't PatFrag-specific.
 - Pass the MatcherState directly to testMIPredicate_MI, the combiner will need it.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D153755
This commit is contained in:
pvanhout 2023-06-26 11:21:18 +02:00
parent dae9d1b524
commit 1fe7d9c799
25 changed files with 886 additions and 845 deletions

View File

@ -0,0 +1,583 @@
//===- 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/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 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 GIMatchTableExecutor 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 {
GICXXPred_I64_Invalid = 0,
GICXXPred_APInt_Invalid = 0,
GICXXPred_APFloat_Invalid = 0,
GICXXPred_MI_Invalid = 0,
};
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.
/// The IgnoreCopies variant ignores COPY instructions.
/// - NewInsnID - Instruction ID to define
/// - InsnID - Instruction ID
/// - OpIdx - Operand index
GIM_RecordInsn,
GIM_RecordInsnIgnoreCopies,
/// 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.
/// The IgnoreCopies variant looks through COPY instructions before
/// comparing the operands.
/// - InsnID - Instruction ID
/// - OpIdx - Operand index
/// - OtherInsnID - Other instruction ID
/// - OtherOpIdx - Other operand index
GIM_CheckIsSameOperand,
GIM_CheckIsSameOperandIgnoreCopies,
/// 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 subregisters of suboperands of complex operands to the
/// specified instruction
/// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call
/// - RenderOpID - The suboperand to render
/// - SubRegIdx - The subregister to extract
GIR_ComplexSubOperandSubRegRenderer,
/// 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 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 *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 executor 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 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, NewMIVector &OutMIs, MatcherState &State,
const ExecInfoTy<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 MatcherState &State) 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_GIMATCHTABLEEXECUTOR_H

View File

@ -1,4 +1,4 @@
//===- llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h --------*- C++ -*-===//
//===- llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.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.
@ -6,17 +6,17 @@
//
//===----------------------------------------------------------------------===//
//
/// \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.
/// \file This file implements GIMatchTableExecutor's `executeMatchTable`
/// function. This is implemented in a separate file because the function is
/// quite large.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H
#ifndef LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTORIMPL_H
#define LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTORIMPL_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineOperand.h"
@ -37,24 +37,16 @@
namespace llvm {
/// GlobalISel PatFrag Predicates
enum {
GIPFP_I64_Invalid = 0,
GIPFP_APInt_Invalid = 0,
GIPFP_APFloat_Invalid = 0,
GIPFP_MI_Invalid = 0,
};
template <class TgtInstructionSelector, class PredicateBitset,
class ComplexMatcherMemFn, class CustomRendererFn>
bool InstructionSelector::executeMatchTable(
TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
&ISelInfo,
template <class TgtExecutor, class PredicateBitset, class ComplexMatcherMemFn,
class CustomRendererFn>
bool GIMatchTableExecutor::executeMatchTable(
TgtExecutor &Exec, NewMIVector &OutMIs, MatcherState &State,
const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
&ExecInfo,
const int64_t *MatchTable, const TargetInstrInfo &TII,
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
CodeGenCoverage &CoverageInfo) const {
CodeGenCoverage *CoverageInfo) const {
uint64_t CurrentIdx = 0;
SmallVector<uint64_t, 4> OnFailResumeAt;
@ -66,12 +58,12 @@ bool InstructionSelector::executeMatchTable(
enum RejectAction { RejectAndGiveUp, RejectAndResume };
auto handleReject = [&]() -> RejectAction {
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Rejected\n");
if (OnFailResumeAt.empty())
return RejectAndGiveUp;
CurrentIdx = OnFailResumeAt.pop_back_val();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Resume at " << CurrentIdx << " ("
<< OnFailResumeAt.size() << " try-blocks remain)\n");
return RejectAndResume;
@ -95,7 +87,7 @@ bool InstructionSelector::executeMatchTable(
int64_t MatcherOpcode = MatchTable[CurrentIdx++];
switch (MatcherOpcode) {
case GIM_Try: {
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Begin try-block\n");
OnFailResumeAt.push_back(MatchTable[CurrentIdx++]);
break;
@ -113,14 +105,14 @@ bool InstructionSelector::executeMatchTable(
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (!MO.isReg()) {
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Not a register\n");
if (handleReject() == RejectAndGiveUp)
return false;
break;
}
if (MO.getReg().isPhysical()) {
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Is a physical register\n");
if (handleReject() == RejectAndGiveUp)
return false;
@ -140,7 +132,7 @@ bool InstructionSelector::executeMatchTable(
"Expected to store MIs in order");
State.MIs.push_back(NewMI);
}
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": MIs[" << NewInsnID
<< "] = GIM_RecordInsn(" << InsnID << ", " << OpIdx
<< ")\n");
@ -149,18 +141,17 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckFeatures: {
int64_t ExpectedBitsetID = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckFeatures(ExpectedBitsetID="
<< ExpectedBitsetID << ")\n");
if ((AvailableFeatures & ISelInfo.FeatureBitsets[ExpectedBitsetID]) !=
ISelInfo.FeatureBitsets[ExpectedBitsetID]) {
if ((AvailableFeatures & ExecInfo.FeatureBitsets[ExpectedBitsetID]) !=
ExecInfo.FeatureBitsets[ExpectedBitsetID]) {
if (handleReject() == RejectAndGiveUp)
return false;
}
break;
}
case GIM_CheckOpcode:
case GIM_CheckOpcodeIsEither: {
int64_t InsnID = MatchTable[CurrentIdx++];
@ -172,13 +163,12 @@ bool InstructionSelector::executeMatchTable(
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
unsigned Opcode = State.MIs[InsnID]->getOpcode();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIM_CheckOpcode(MIs[" << InsnID
<< "], ExpectedOpcode=" << Expected0;
if (MatcherOpcode == GIM_CheckOpcodeIsEither)
dbgs() << " || " << Expected1;
dbgs() << ") // Got=" << Opcode << "\n";
);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckOpcode(MIs[" << InsnID
<< "], ExpectedOpcode=" << Expected0;
if (MatcherOpcode == GIM_CheckOpcodeIsEither) dbgs()
<< " || " << Expected1;
dbgs() << ") // Got=" << Opcode << "\n";);
if (Opcode != Expected0 && Opcode != Expected1) {
if (handleReject() == RejectAndGiveUp)
@ -195,7 +185,7 @@ bool InstructionSelector::executeMatchTable(
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
const int64_t Opcode = State.MIs[InsnID]->getOpcode();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), {
DEBUG_WITH_TYPE(TgtExecutor::getName(), {
dbgs() << CurrentIdx << ": GIM_SwitchOpcode(MIs[" << InsnID << "], ["
<< LowerBound << ", " << UpperBound << "), Default=" << Default
<< ", JumpTable...) // Got=" << Opcode << "\n";
@ -223,7 +213,7 @@ bool InstructionSelector::executeMatchTable(
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), {
DEBUG_WITH_TYPE(TgtExecutor::getName(), {
dbgs() << CurrentIdx << ": GIM_SwitchType(MIs[" << InsnID
<< "]->getOperand(" << OpIdx << "), [" << LowerBound << ", "
<< UpperBound << "), Default=" << Default
@ -238,8 +228,8 @@ bool InstructionSelector::executeMatchTable(
break;
}
const LLT Ty = MRI.getType(MO.getReg());
const auto TyI = ISelInfo.TypeIDMap.find(Ty);
if (TyI == ISelInfo.TypeIDMap.end()) {
const auto TyI = ExecInfo.TypeIDMap.find(Ty);
if (TyI == ExecInfo.TypeIDMap.end()) {
CurrentIdx = Default;
break;
}
@ -260,7 +250,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckNumOperands: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Expected = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckNumOperands(MIs["
<< InsnID << "], Expected=" << Expected << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@ -277,7 +267,7 @@ bool InstructionSelector::executeMatchTable(
? MatchTable[CurrentIdx++]
: 1;
int64_t Predicate = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckImmPredicate(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), Predicate=" << Predicate << ")\n");
@ -285,7 +275,7 @@ bool InstructionSelector::executeMatchTable(
assert((State.MIs[InsnID]->getOperand(OpIdx).isImm() ||
State.MIs[InsnID]->getOperand(OpIdx).isCImm()) &&
"Expected immediate operand");
assert(Predicate > GIPFP_I64_Invalid && "Expected a valid predicate");
assert(Predicate > GICXXPred_I64_Invalid && "Expected a valid predicate");
int64_t Value = 0;
if (State.MIs[InsnID]->getOperand(OpIdx).isCImm())
Value = State.MIs[InsnID]->getOperand(OpIdx).getCImm()->getSExtValue();
@ -302,20 +292,20 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckAPIntImmPredicate: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Predicate = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIM_CheckAPIntImmPredicate(MIs["
<< InsnID << "], Predicate=" << Predicate << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT &&
"Expected G_CONSTANT");
assert(Predicate > GIPFP_APInt_Invalid && "Expected a valid predicate");
APInt Value;
if (State.MIs[InsnID]->getOperand(1).isCImm())
Value = State.MIs[InsnID]->getOperand(1).getCImm()->getValue();
else
assert(Predicate > GICXXPred_APInt_Invalid &&
"Expected a valid predicate");
if (!State.MIs[InsnID]->getOperand(1).isCImm())
llvm_unreachable("Expected Imm or CImm operand");
const APInt &Value =
State.MIs[InsnID]->getOperand(1).getCImm()->getValue();
if (!testImmPredicate_APInt(Predicate, Value))
if (handleReject() == RejectAndGiveUp)
return false;
@ -324,16 +314,19 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckAPFloatImmPredicate: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Predicate = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIM_CheckAPFloatImmPredicate(MIs["
<< InsnID << "], Predicate=" << Predicate << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_FCONSTANT &&
"Expected G_FCONSTANT");
assert(State.MIs[InsnID]->getOperand(1).isFPImm() && "Expected FPImm operand");
assert(Predicate > GIPFP_APFloat_Invalid && "Expected a valid predicate");
APFloat Value = State.MIs[InsnID]->getOperand(1).getFPImm()->getValueAPF();
assert(State.MIs[InsnID]->getOperand(1).isFPImm() &&
"Expected FPImm operand");
assert(Predicate > GICXXPred_APFloat_Invalid &&
"Expected a valid predicate");
const APFloat &Value =
State.MIs[InsnID]->getOperand(1).getFPImm()->getValueAPF();
if (!testImmPredicate_APFloat(Predicate, Value))
if (handleReject() == RejectAndGiveUp)
@ -344,7 +337,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckIsBuildVectorAllZeros: {
int64_t InsnID = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckBuildVectorAll{Zeros|Ones}(MIs["
<< InsnID << "])\n");
@ -372,15 +365,14 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckCxxInsnPredicate: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Predicate = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIM_CheckCxxPredicate(MIs["
<< InsnID << "], Predicate=" << Predicate << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
assert(Predicate > GIPFP_MI_Invalid && "Expected a valid predicate");
assert(Predicate > GICXXPred_MI_Invalid && "Expected a valid predicate");
if (!testMIPredicate_MI(Predicate, *State.MIs[InsnID],
State.RecordedOperands))
if (!testMIPredicate_MI(Predicate, *State.MIs[InsnID], State))
if (handleReject() == RejectAndGiveUp)
return false;
break;
@ -388,7 +380,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckHasNoUse: {
int64_t InsnID = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckHasNoUse(MIs["
<< InsnID << "]\n");
@ -407,7 +399,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckAtomicOrdering: {
int64_t InsnID = MatchTable[CurrentIdx++];
AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckAtomicOrdering(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@ -424,7 +416,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckAtomicOrderingOrStrongerThan: {
int64_t InsnID = MatchTable[CurrentIdx++];
AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckAtomicOrderingOrStrongerThan(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
@ -442,7 +434,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckAtomicOrderingWeakerThan: {
int64_t InsnID = MatchTable[CurrentIdx++];
AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckAtomicOrderingWeakerThan(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
@ -473,17 +465,16 @@ bool InstructionSelector::executeMatchTable(
// a match earlier.
const uint64_t LastIdx = CurrentIdx + NumAddrSpace;
const MachineMemOperand *MMO
= *(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
const MachineMemOperand *MMO =
*(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
const unsigned MMOAddrSpace = MMO->getAddrSpace();
bool Success = false;
for (int I = 0; I != NumAddrSpace; ++I) {
unsigned AddrSpace = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(
TgtInstructionSelector::getName(),
dbgs() << "addrspace(" << MMOAddrSpace << ") vs "
<< AddrSpace << '\n');
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << "addrspace(" << MMOAddrSpace << ") vs "
<< AddrSpace << '\n');
if (AddrSpace == MMOAddrSpace) {
Success = true;
@ -509,12 +500,13 @@ bool InstructionSelector::executeMatchTable(
break;
}
MachineMemOperand *MMO
= *(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
MachineMemOperand *MMO =
*(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckMemoryAlignment"
<< "(MIs[" << InsnID << "]->memoperands() + " << MMOIdx
<< ")->getAlignment() >= " << MinAlign << ")\n");
<< "(MIs[" << InsnID << "]->memoperands() + "
<< MMOIdx << ")->getAlignment() >= " << MinAlign
<< ")\n");
if (MMO->getAlign() < MinAlign && handleReject() == RejectAndGiveUp)
return false;
@ -525,10 +517,9 @@ bool InstructionSelector::executeMatchTable(
int64_t MMOIdx = MatchTable[CurrentIdx++];
uint64_t Size = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx
<< ": GIM_CheckMemorySizeEqual(MIs[" << InsnID
<< "]->memoperands() + " << MMOIdx
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckMemorySizeEqual(MIs["
<< InsnID << "]->memoperands() + " << MMOIdx
<< ", Size=" << Size << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@ -538,11 +529,12 @@ bool InstructionSelector::executeMatchTable(
break;
}
MachineMemOperand *MMO = *(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
MachineMemOperand *MMO =
*(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << MMO->getSize() << " bytes vs " << Size
<< " bytes\n");
DEBUG_WITH_TYPE(TgtExecutor::getName(), dbgs() << MMO->getSize()
<< " bytes vs " << Size
<< " bytes\n");
if (MMO->getSize() != Size)
if (handleReject() == RejectAndGiveUp)
return false;
@ -557,20 +549,19 @@ bool InstructionSelector::executeMatchTable(
int64_t OpIdx = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(
TgtInstructionSelector::getName(),
TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckMemorySize"
<< (MatcherOpcode == GIM_CheckMemorySizeEqualToLLT
? "EqualTo"
: MatcherOpcode == GIM_CheckMemorySizeGreaterThanLLT
? "GreaterThan"
: "LessThan")
<< (MatcherOpcode == GIM_CheckMemorySizeEqualToLLT ? "EqualTo"
: MatcherOpcode == GIM_CheckMemorySizeGreaterThanLLT
? "GreaterThan"
: "LessThan")
<< "LLT(MIs[" << InsnID << "]->memoperands() + " << MMOIdx
<< ", OpIdx=" << OpIdx << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (!MO.isReg()) {
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": Not a register\n");
if (handleReject() == RejectAndGiveUp)
return false;
@ -583,7 +574,8 @@ bool InstructionSelector::executeMatchTable(
break;
}
MachineMemOperand *MMO = *(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
MachineMemOperand *MMO =
*(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
unsigned Size = MRI.getType(MO.getReg()).getSizeInBits();
if (MatcherOpcode == GIM_CheckMemorySizeEqualToLLT &&
@ -605,14 +597,14 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t TypeID = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckType(MIs[" << InsnID
<< "]->getOperand(" << OpIdx
<< "), TypeID=" << TypeID << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (!MO.isReg() ||
MRI.getType(MO.getReg()) != ISelInfo.TypeObjects[TypeID]) {
MRI.getType(MO.getReg()) != ExecInfo.TypeObjects[TypeID]) {
if (handleReject() == RejectAndGiveUp)
return false;
}
@ -623,7 +615,7 @@ bool InstructionSelector::executeMatchTable(
int64_t OpIdx = MatchTable[CurrentIdx++];
uint64_t SizeInBits = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckPointerToAny(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), SizeInBits=" << SizeInBits << ")\n");
@ -654,7 +646,7 @@ bool InstructionSelector::executeMatchTable(
int64_t OpIdx = MatchTable[CurrentIdx++];
uint64_t StoreIdx = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_RecordNamedOperand(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), StoreIdx=" << StoreIdx << ")\n");
@ -667,7 +659,7 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t RCEnum = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckRegBankForClass(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), RCEnum=" << RCEnum << ")\n");
@ -688,7 +680,7 @@ bool InstructionSelector::executeMatchTable(
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t RendererID = MatchTable[CurrentIdx++];
int64_t ComplexPredicateID = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": State.Renderers[" << RendererID
<< "] = GIM_CheckComplexPattern(MIs[" << InsnID
<< "]->getOperand(" << OpIdx
@ -697,13 +689,12 @@ bool InstructionSelector::executeMatchTable(
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
// FIXME: Use std::invoke() when it's available.
ComplexRendererFns Renderer =
(ISel.*ISelInfo.ComplexPredicates[ComplexPredicateID])(
(Exec.*ExecInfo.ComplexPredicates[ComplexPredicateID])(
State.MIs[InsnID]->getOperand(OpIdx));
if (Renderer)
State.Renderers[RendererID] = *Renderer;
else
if (handleReject() == RejectAndGiveUp)
return false;
else if (handleReject() == RejectAndGiveUp)
return false;
break;
}
@ -711,7 +702,7 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t Value = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckConstantInt(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n");
@ -736,7 +727,7 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t Value = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckLiteralInt(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n");
@ -758,7 +749,7 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t Value = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIntrinsicID(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n");
@ -773,7 +764,7 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t Value = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckCmpPredicate(MIs["
<< InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n");
@ -787,7 +778,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckIsMBB: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsMBB(MIs[" << InsnID
<< "]->getOperand(" << OpIdx << "))\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@ -800,7 +791,7 @@ bool InstructionSelector::executeMatchTable(
case GIM_CheckIsImm: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsImm(MIs[" << InsnID
<< "]->getOperand(" << OpIdx << "))\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@ -812,7 +803,7 @@ bool InstructionSelector::executeMatchTable(
}
case GIM_CheckIsSafeToFold: {
int64_t InsnID = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsSafeToFold(MIs["
<< InsnID << "])\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
@ -828,7 +819,7 @@ bool InstructionSelector::executeMatchTable(
int64_t OpIdx = MatchTable[CurrentIdx++];
int64_t OtherInsnID = MatchTable[CurrentIdx++];
int64_t OtherOpIdx = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_CheckIsSameOperand(MIs["
<< InsnID << "][" << OpIdx << "], MIs["
<< OtherInsnID << "][" << OtherOpIdx << "])\n");
@ -854,12 +845,11 @@ bool InstructionSelector::executeMatchTable(
break;
}
case GIM_Reject:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_Reject\n");
if (handleReject() == RejectAndGiveUp)
return false;
break;
case GIR_MutateOpcode: {
int64_t OldInsnID = MatchTable[CurrentIdx++];
uint64_t NewInsnID = MatchTable[CurrentIdx++];
@ -870,7 +860,7 @@ bool InstructionSelector::executeMatchTable(
OutMIs[NewInsnID] = MachineInstrBuilder(*State.MIs[OldInsnID]->getMF(),
State.MIs[OldInsnID]);
OutMIs[NewInsnID]->setDesc(TII.get(NewOpcode));
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_MutateOpcode(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "], "
<< NewOpcode << ")\n");
@ -885,7 +875,7 @@ bool InstructionSelector::executeMatchTable(
OutMIs[NewInsnID] = BuildMI(*State.MIs[0]->getParent(), State.MIs[0],
MIMetadata(*State.MIs[0]), TII.get(Opcode));
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_BuildMI(OutMIs["
<< NewInsnID << "], " << Opcode << ")\n");
break;
@ -897,7 +887,7 @@ bool InstructionSelector::executeMatchTable(
int64_t OpIdx = MatchTable[CurrentIdx++];
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
OutMIs[NewInsnID].add(State.MIs[OldInsnID]->getOperand(OpIdx));
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIR_Copy(OutMIs[" << NewInsnID
<< "], MIs[" << OldInsnID << "], " << OpIdx << ")\n");
@ -915,7 +905,7 @@ bool InstructionSelector::executeMatchTable(
OutMIs[NewInsnID].addReg(ZeroReg);
else
OutMIs[NewInsnID].add(MO);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CopyOrAddZeroReg(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "], "
<< OpIdx << ", " << ZeroReg << ")\n");
@ -930,7 +920,7 @@ bool InstructionSelector::executeMatchTable(
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
OutMIs[NewInsnID].addReg(State.MIs[OldInsnID]->getOperand(OpIdx).getReg(),
0, SubRegIdx);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CopySubReg(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "], "
<< OpIdx << ", " << SubRegIdx << ")\n");
@ -942,7 +932,7 @@ bool InstructionSelector::executeMatchTable(
int64_t RegNum = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addDef(RegNum, RegState::Implicit);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_AddImplicitDef(OutMIs["
<< InsnID << "], " << RegNum << ")\n");
break;
@ -953,7 +943,7 @@ bool InstructionSelector::executeMatchTable(
int64_t RegNum = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addUse(RegNum, RegState::Implicit);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_AddImplicitUse(OutMIs["
<< InsnID << "], " << RegNum << ")\n");
break;
@ -965,10 +955,10 @@ bool InstructionSelector::executeMatchTable(
uint64_t RegFlags = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addReg(RegNum, RegFlags);
DEBUG_WITH_TYPE(
TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_AddRegister(OutMIs["
<< InsnID << "], " << RegNum << ", " << RegFlags << ")\n");
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIR_AddRegister(OutMIs[" << InsnID
<< "], " << RegNum << ", " << RegFlags << ")\n");
break;
}
@ -983,14 +973,14 @@ bool InstructionSelector::executeMatchTable(
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addReg(State.TempRegisters[TempRegID], TempRegFlags, SubReg);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_AddTempRegister(OutMIs["
<< InsnID << "], TempRegisters[" << TempRegID
<< "]";
if (SubReg)
dbgs() << '.' << TRI.getSubRegIndexName(SubReg);
dbgs() << ", " << TempRegFlags << ")\n");
OutMIs[InsnID].addReg(State.TempRegisters[TempRegID], TempRegFlags,
SubReg);
DEBUG_WITH_TYPE(
TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_AddTempRegister(OutMIs[" << InsnID
<< "], TempRegisters[" << TempRegID << "]";
if (SubReg) dbgs() << '.' << TRI.getSubRegIndexName(SubReg);
dbgs() << ", " << TempRegFlags << ")\n");
break;
}
@ -999,7 +989,7 @@ bool InstructionSelector::executeMatchTable(
int64_t Imm = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addImm(Imm);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_AddImm(OutMIs[" << InsnID
<< "], " << Imm << ")\n");
break;
@ -1011,7 +1001,7 @@ bool InstructionSelector::executeMatchTable(
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
for (const auto &RenderOpFn : State.Renderers[RendererID])
RenderOpFn(OutMIs[InsnID]);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_ComplexRenderer(OutMIs["
<< InsnID << "], " << RendererID << ")\n");
break;
@ -1022,7 +1012,7 @@ bool InstructionSelector::executeMatchTable(
int64_t RenderOpID = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
State.Renderers[RendererID][RenderOpID](OutMIs[InsnID]);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIR_ComplexSubOperandRenderer(OutMIs["
<< InsnID << "], " << RendererID << ", "
@ -1038,7 +1028,7 @@ bool InstructionSelector::executeMatchTable(
assert(MI && "Attempted to add to undefined instruction");
State.Renderers[RendererID][RenderOpID](MI);
MI->getOperand(MI->getNumOperands() - 1).setSubReg(SubRegIdx);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIR_ComplexSubOperandSubRegRenderer(OutMIs["
<< InsnID << "], " << RendererID << ", "
@ -1050,7 +1040,8 @@ bool InstructionSelector::executeMatchTable(
int64_t NewInsnID = MatchTable[CurrentIdx++];
int64_t OldInsnID = MatchTable[CurrentIdx++];
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
assert(State.MIs[OldInsnID]->getOpcode() == TargetOpcode::G_CONSTANT && "Expected G_CONSTANT");
assert(State.MIs[OldInsnID]->getOpcode() == TargetOpcode::G_CONSTANT &&
"Expected G_CONSTANT");
if (State.MIs[OldInsnID]->getOperand(1).isCImm()) {
OutMIs[NewInsnID].addImm(
State.MIs[OldInsnID]->getOperand(1).getCImm()->getSExtValue());
@ -1058,7 +1049,7 @@ bool InstructionSelector::executeMatchTable(
OutMIs[NewInsnID].add(State.MIs[OldInsnID]->getOperand(1));
else
llvm_unreachable("Expected Imm or CImm operand");
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CopyConstantAsSImm(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "])\n");
break;
@ -1069,15 +1060,17 @@ bool InstructionSelector::executeMatchTable(
int64_t NewInsnID = MatchTable[CurrentIdx++];
int64_t OldInsnID = MatchTable[CurrentIdx++];
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
assert(State.MIs[OldInsnID]->getOpcode() == TargetOpcode::G_FCONSTANT && "Expected G_FCONSTANT");
assert(State.MIs[OldInsnID]->getOpcode() == TargetOpcode::G_FCONSTANT &&
"Expected G_FCONSTANT");
if (State.MIs[OldInsnID]->getOperand(1).isFPImm())
OutMIs[NewInsnID].addFPImm(
State.MIs[OldInsnID]->getOperand(1).getFPImm());
else
llvm_unreachable("Expected FPImm operand");
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_CopyFPConstantAsFPImm(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "])\n");
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs()
<< CurrentIdx << ": GIR_CopyFPConstantAsFPImm(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "])\n");
break;
}
@ -1086,13 +1079,13 @@ bool InstructionSelector::executeMatchTable(
int64_t OldInsnID = MatchTable[CurrentIdx++];
int64_t RendererFnID = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_CustomRenderer(OutMIs["
<< InsnID << "], MIs[" << OldInsnID << "], "
<< RendererFnID << ")\n");
(ISel.*ISelInfo.CustomRenderers[RendererFnID])(
OutMIs[InsnID], *State.MIs[OldInsnID],
-1); // Not a source operand of the old instruction.
(Exec.*ExecInfo.CustomRenderers[RendererFnID])(
OutMIs[InsnID], *State.MIs[OldInsnID],
-1); // Not a source operand of the old instruction.
break;
}
case GIR_CustomOperandRenderer: {
@ -1102,15 +1095,13 @@ bool InstructionSelector::executeMatchTable(
int64_t RendererFnID = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
DEBUG_WITH_TYPE(
TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_CustomOperandRenderer(OutMIs["
<< InsnID << "], MIs[" << OldInsnID << "]->getOperand("
<< OpIdx << "), "
<< RendererFnID << ")\n");
(ISel.*ISelInfo.CustomRenderers[RendererFnID])(OutMIs[InsnID],
*State.MIs[OldInsnID],
OpIdx);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIR_CustomOperandRenderer(OutMIs[" << InsnID
<< "], MIs[" << OldInsnID << "]->getOperand("
<< OpIdx << "), " << RendererFnID << ")\n");
(Exec.*ExecInfo.CustomRenderers[RendererFnID])(
OutMIs[InsnID], *State.MIs[OldInsnID], OpIdx);
break;
}
case GIR_ConstrainOperandRC: {
@ -1124,7 +1115,7 @@ bool InstructionSelector::executeMatchTable(
const TargetRegisterClass &RC = *TRI.getRegClass(RCEnum);
MachineOperand &MO = I.getOperand(OpIdx);
constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, RC, MO);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_ConstrainOperandRC(OutMIs["
<< InsnID << "], " << OpIdx << ", " << RCEnum
<< ")\n");
@ -1136,7 +1127,7 @@ bool InstructionSelector::executeMatchTable(
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
constrainSelectedInstRegOperands(*OutMIs[InsnID].getInstr(), TII, TRI,
RBI);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx
<< ": GIR_ConstrainSelectedInstOperands(OutMIs["
<< InsnID << "])\n");
@ -1147,18 +1138,18 @@ bool InstructionSelector::executeMatchTable(
int64_t InsnID = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_MergeMemOperands(OutMIs["
<< InsnID << "]");
int64_t MergeInsnID = GIU_MergeMemOperands_EndOfList;
while ((MergeInsnID = MatchTable[CurrentIdx++]) !=
GIU_MergeMemOperands_EndOfList) {
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << ", MIs[" << MergeInsnID << "]");
for (const auto &MMO : State.MIs[MergeInsnID]->memoperands())
OutMIs[InsnID].addMemOperand(MMO);
}
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), dbgs() << ")\n");
DEBUG_WITH_TYPE(TgtExecutor::getName(), dbgs() << ")\n");
break;
}
@ -1167,7 +1158,7 @@ bool InstructionSelector::executeMatchTable(
assert(State.MIs[InsnID] &&
"Attempted to erase an undefined instruction");
State.MIs[InsnID]->eraseFromParent();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_EraseFromParent(MIs["
<< InsnID << "])\n");
break;
@ -1178,8 +1169,8 @@ bool InstructionSelector::executeMatchTable(
int64_t TypeID = MatchTable[CurrentIdx++];
State.TempRegisters[TempRegID] =
MRI.createGenericVirtualRegister(ISelInfo.TypeObjects[TypeID]);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
MRI.createGenericVirtualRegister(ExecInfo.TypeObjects[TypeID]);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": TempRegs[" << TempRegID
<< "] = GIR_MakeTempReg(" << TypeID << ")\n");
break;
@ -1187,20 +1178,20 @@ bool InstructionSelector::executeMatchTable(
case GIR_Coverage: {
int64_t RuleID = MatchTable[CurrentIdx++];
CoverageInfo.setCovered(RuleID);
assert(CoverageInfo);
CoverageInfo->setCovered(RuleID);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs()
<< CurrentIdx << ": GIR_Coverage(" << RuleID << ")");
DEBUG_WITH_TYPE(TgtExecutor::getName(), dbgs() << CurrentIdx
<< ": GIR_Coverage("
<< RuleID << ")");
break;
}
case GIR_Done:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_Done\n");
propagateFlags(OutMIs);
return true;
default:
llvm_unreachable("Unexpected command");
}
@ -1209,4 +1200,4 @@ bool InstructionSelector::executeMatchTable(
} // end namespace llvm
#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H
#endif // LLVM_CODEGEN_GLOBALISEL_GIMATCHTABLEEXECUTORIMPL_H

View File

@ -7,441 +7,18 @@
//===----------------------------------------------------------------------===//
//
/// \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/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>
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
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> {
class InstructionSelector : public GIMatchTableExecutor {
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.
/// The IgnoreCopies variant ignores COPY instructions.
/// - NewInsnID - Instruction ID to define
/// - InsnID - Instruction ID
/// - OpIdx - Operand index
GIM_RecordInsn,
GIM_RecordInsnIgnoreCopies,
/// 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.
/// The IgnoreCopies variant looks through COPY instructions before
/// comparing the operands.
/// - InsnID - Instruction ID
/// - OpIdx - Operand index
/// - OtherInsnID - Other instruction ID
/// - OtherOpIdx - Other operand index
GIM_CheckIsSameOperand,
GIM_CheckIsSameOperandIgnoreCopies,
/// 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 subregisters of suboperands of complex operands to the
/// specified instruction
/// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call
/// - RenderOpID - The suboperand to render
/// - SubRegIdx - The subregister to extract
GIR_ComplexSubOperandSubRegRenderer,
/// 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;
virtual ~InstructionSelector();
/// Select the (possibly generic) instruction \p I to only use target-specific
/// opcodes. It is OK to insert multiple instructions, but they cannot be
@ -454,135 +31,7 @@ public:
/// 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;
};
} // namespace llvm
} // end namespace llvm
#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
#endif

View File

@ -6,6 +6,7 @@ add_llvm_component_library(LLVMGlobalISel
GlobalISel.cpp
Combiner.cpp
CombinerHelper.cpp
GIMatchTableExecutor.cpp
GISelChangeObserver.cpp
IRTranslator.cpp
InlineAsmLowering.cpp

View File

@ -0,0 +1,68 @@
//===- llvm/CodeGen/GlobalISel/GIMatchTableExecutor.cpp -------------------===//
//
// 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 implements the GIMatchTableExecutor class.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#define DEBUG_TYPE "gi-match-table-executor"
using namespace llvm;
GIMatchTableExecutor::MatcherState::MatcherState(unsigned MaxRenderers)
: Renderers(MaxRenderers) {}
GIMatchTableExecutor::GIMatchTableExecutor() = default;
bool GIMatchTableExecutor::isOperandImmEqual(
const MachineOperand &MO, int64_t Value,
const MachineRegisterInfo &MRI) const {
if (MO.isReg() && MO.getReg())
if (auto VRegVal = getIConstantVRegValWithLookThrough(MO.getReg(), MRI))
return VRegVal->Value.getSExtValue() == Value;
return false;
}
bool GIMatchTableExecutor::isBaseWithConstantOffset(
const MachineOperand &Root, const MachineRegisterInfo &MRI) const {
if (!Root.isReg())
return false;
MachineInstr *RootI = MRI.getVRegDef(Root.getReg());
if (RootI->getOpcode() != TargetOpcode::G_PTR_ADD)
return false;
MachineOperand &RHS = RootI->getOperand(2);
MachineInstr *RHSI = MRI.getVRegDef(RHS.getReg());
if (RHSI->getOpcode() != TargetOpcode::G_CONSTANT)
return false;
return true;
}
bool GIMatchTableExecutor::isObviouslySafeToFold(MachineInstr &MI,
MachineInstr &IntoMI) const {
// Immediate neighbours are already folded.
if (MI.getParent() == IntoMI.getParent() &&
std::next(MI.getIterator()) == IntoMI.getIterator())
return true;
// Convergent instructions cannot be moved in the CFG.
if (MI.isConvergent() && MI.getParent() != IntoMI.getParent())
return false;
return !MI.mayLoadOrStore() && !MI.mayRaiseFPException() &&
!MI.hasUnmodeledSideEffects() && MI.implicit_operands().empty();
}

View File

@ -5,64 +5,12 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file implements the InstructionSelector class.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#define DEBUG_TYPE "instructionselector"
namespace llvm {
using namespace llvm;
// vtable anchor
InstructionSelector::~InstructionSelector() = default;
InstructionSelector::MatcherState::MatcherState(unsigned MaxRenderers)
: Renderers(MaxRenderers) {}
InstructionSelector::InstructionSelector() = default;
bool InstructionSelector::isOperandImmEqual(
const MachineOperand &MO, int64_t Value,
const MachineRegisterInfo &MRI) const {
if (MO.isReg() && MO.getReg())
if (auto VRegVal = getIConstantVRegValWithLookThrough(MO.getReg(), MRI))
return VRegVal->Value.getSExtValue() == Value;
return false;
}
bool InstructionSelector::isBaseWithConstantOffset(
const MachineOperand &Root, const MachineRegisterInfo &MRI) const {
if (!Root.isReg())
return false;
MachineInstr *RootI = MRI.getVRegDef(Root.getReg());
if (RootI->getOpcode() != TargetOpcode::G_PTR_ADD)
return false;
MachineOperand &RHS = RootI->getOperand(2);
MachineInstr *RHSI = MRI.getVRegDef(RHS.getReg());
if (RHSI->getOpcode() != TargetOpcode::G_CONSTANT)
return false;
return true;
}
bool InstructionSelector::isObviouslySafeToFold(MachineInstr &MI,
MachineInstr &IntoMI) const {
// Immediate neighbours are already folded.
if (MI.getParent() == IntoMI.getParent() &&
std::next(MI.getIterator()) == IntoMI.getIterator())
return true;
// Convergent instructions cannot be moved in the CFG.
if (MI.isConvergent() && MI.getParent() != IntoMI.getParent())
return false;
return !MI.mayLoadOrStore() && !MI.mayRaiseFPException() &&
!MI.hasUnmodeledSideEffects() && MI.implicit_operands().empty();
}
} // namespace llvm

View File

@ -21,9 +21,9 @@
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"

View File

@ -19,8 +19,8 @@
#include "AMDGPUTargetMachine.h"
#include "SIMachineFunctionInfo.h"
#include "Utils/AMDGPUBaseInfo.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineFrameInfo.h"

View File

@ -13,8 +13,8 @@
#include "ARMRegisterBankInfo.h"
#include "ARMSubtarget.h"
#include "ARMTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/IntrinsicsARM.h"

View File

@ -9,8 +9,8 @@
#include "M68kRegisterBankInfo.h"
#include "M68kSubtarget.h"
#include "M68kTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "m68k-isel"

View File

@ -15,7 +15,7 @@
#include "MipsMachineFunction.h"
#include "MipsRegisterBankInfo.h"
#include "MipsTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/IR/IntrinsicsMips.h"

View File

@ -16,9 +16,9 @@
#include "PPCRegisterBankInfo.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"

View File

@ -14,8 +14,8 @@
#include "RISCVRegisterBankInfo.h"
#include "RISCVSubtarget.h"
#include "RISCVTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/IR/IntrinsicsRISCV.h"
#include "llvm/Support/Debug.h"

View File

@ -20,8 +20,8 @@
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/IntrinsicsSPIRV.h"

View File

@ -19,8 +19,8 @@
#include "X86RegisterInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/LowLevelType.h"
#include "llvm/CodeGen/MachineBasicBlock.h"

View File

@ -14,7 +14,7 @@ def test_atomic_op_frag : PatFrag<(ops node:$ptr, node:$val),
let IsAtomic = 1;
let MemoryVT = i32;
}
def INSN : I<(outs GPR32:$dst), (ins GPR32Op:$src1, GPR32Op:$src2), []>;
def : Pat<(test_atomic_op_frag GPR32:$ptr, GPR32:$val) ,
@ -35,7 +35,7 @@ def : Pat<(test_atomic_op_frag GPR32:$ptr, GPR32:$val) ,
// CHECK_NOPT-NEXT: // MIs[0] val
// CHECK_NOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK_NOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK_NOPT-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_test_atomic_op_frag,
// CHECK_NOPT-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_test_atomic_op_frag,
// CHECK_NOPT-NEXT: // (atomic_swap:{ *:[i32] } GPR32:{ *:[i32] }:$ptr, GPR32:{ *:[i32] }:$val)<<P:Predicate_test_atomic_op_frag>> => (INSN:{ *:[i32] } GPR32:{ *:[i32] }:$ptr, GPR32:{ *:[i32] }:$val)
// CHECK_NOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::INSN,
// CHECK_NOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
@ -61,7 +61,7 @@ def : Pat<(test_atomic_op_frag GPR32:$ptr, GPR32:$val) ,
// CHECK_OPT-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// CHECK_OPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
// CHECK_OPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK_OPT-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_test_atomic_op_frag,
// CHECK_OPT-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_test_atomic_op_frag,
// CHECK_OPT-NEXT: // (atomic_swap:{ *:[i32] } GPR32:{ *:[i32] }:$ptr, GPR32:{ *:[i32] }:$val)<<P:Predicate_test_atomic_op_frag>> => (INSN:{ *:[i32] } GPR32:{ *:[i32] }:$ptr, GPR32:{ *:[i32] }:$val)
// CHECK_OPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::INSN,
// CHECK_OPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,

View File

@ -2,8 +2,8 @@
// RUN: FileCheck %s < %t
// Both predicates should be tested
// CHECK-DAG: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_pat_frag_b,
// CHECK-DAG: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_pat_frag_a,
// CHECK-DAG: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_pat_frag_b,
// CHECK-DAG: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_pat_frag_a,
include "llvm/Target/Target.td"
include "GlobalISelEmitterCommon.td"
@ -37,4 +37,3 @@ def : Pat <
(pat_frag_b GPR32:$src),
(inst_b GPR32:$src)
>;

View File

@ -73,19 +73,19 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: mutable MatcherState State;
// CHECK-NEXT: typedef ComplexRendererFns(MyTargetInstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;
// CHECK-NEXT: typedef void(MyTargetInstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const MachineInstr &, int) const;
// CHECK-NEXT: const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn> ISelInfo;
// CHECK-NEXT: const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn> ExecInfo;
// CHECK-NEXT: static MyTargetInstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];
// CHECK-NEXT: static MyTargetInstructionSelector::CustomRendererFn CustomRenderers[];
// CHECK-NEXT: bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const override;
// CHECK-NEXT: bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) const override;
// CHECK-NEXT: bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat &Imm) const override;
// CHECK-NEXT: const int64_t *getMatchTable() const override;
// CHECK-NEXT: bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI, const std::array<const MachineOperand *, 3> &Operands) const override;
// CHECK-NEXT: bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI, const MatcherState &State) const override;
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
// CHECK-NEXT: , State(3),
// CHECK-NEXT: ISelInfo(TypeObjects, NumTypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers)
// CHECK-NEXT: ExecInfo(TypeObjects, NumTypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers)
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
@ -144,19 +144,19 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
// CHECK-NEXT: GIPFP_I64_Predicate_cimm8 = GIPFP_I64_Invalid + 1,
// CHECK-NEXT: GIPFP_I64_Predicate_simm8,
// CHECK-NEXT: GICXXPred_I64_Predicate_cimm8 = GICXXPred_I64_Invalid + 1,
// CHECK-NEXT: GICXXPred_I64_Predicate_simm8,
// CHECK-NEXT: };
// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const {
// CHECK-NEXT: switch (PredicateID) {
// CHECK-NEXT: case GIPFP_I64_Predicate_cimm8: {
// CHECK-NEXT: case GICXXPred_I64_Predicate_cimm8: {
// CHECK-NEXT: return isInt<8>(Imm);
// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
// CHECK-NEXT: return false;
// CHECK-NEXT: }
// CHECK-NEXT: case GIPFP_I64_Predicate_simm8: {
// CHECK-NEXT: case GICXXPred_I64_Predicate_simm8: {
// CHECK-NEXT: return isInt<8>(Imm);
// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
// CHECK-NEXT: return false;
@ -168,11 +168,11 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
// CHECK-NEXT: GIPFP_APFloat_Predicate_fpimmz = GIPFP_APFloat_Invalid + 1,
// CHECK-NEXT: GICXXPred_APFloat_Predicate_fpimmz = GICXXPred_APFloat_Invalid + 1,
// CHECK-NEXT: };
// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_APFloat(unsigned PredicateID, const APFloat & Imm) const {
// CHECK-NEXT: switch (PredicateID) {
// CHECK-NEXT: case GIPFP_APFloat_Predicate_fpimmz: {
// CHECK-NEXT: case GICXXPred_APFloat_Predicate_fpimmz: {
// CHECK-NEXT: return Imm->isExactlyValue(0.0);
// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
// CHECK-NEXT: return false;
@ -184,11 +184,11 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
// CHECK-NEXT: GIPFP_APInt_Predicate_simm9 = GIPFP_APInt_Invalid + 1,
// CHECK-NEXT: GICXXPred_APInt_Predicate_simm9 = GICXXPred_APInt_Invalid + 1,
// CHECK-NEXT: };
// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_APInt(unsigned PredicateID, const APInt & Imm) const {
// CHECK-NEXT: switch (PredicateID) {
// CHECK-NEXT: case GIPFP_APInt_Predicate_simm9: {
// CHECK-NEXT: case GICXXPred_APInt_Predicate_simm9: {
// CHECK-NEXT: return isInt<9>(Imm->getSExtValue());
// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
// CHECK-NEXT: return false;
@ -224,7 +224,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: State.MIs.clear();
// CHECK-NEXT: State.MIs.push_back(&I);
// CHECK: if (executeMatchTable(*this, OutMIs, State, ISelInfo, getMatchTable(), TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {
// CHECK: if (executeMatchTable(*this, OutMIs, State, ExecInfo, getMatchTable(), TII, MRI, TRI, RBI, AvailableFeatures, &CoverageInfo)) {
// CHECK-NEXT: return true;
// CHECK-NEXT: }
@ -354,12 +354,12 @@ def : Pat<(select GPR32:$src1, (complex_rr GPR32:$src2a, GPR32:$src2b),
// R21N-NEXT: // MIs[0] src2
// R21N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
//
// R21O-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_frag,
// R21O-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_frag,
// R21C-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
// R21N-NEXT: // MIs[0] src3
// R21N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
// R21C-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/3, /*Renderer*/1, GICP_gi_complex,
// R21N-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_frag,
// R21N-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_frag,
// R21C-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, complex:{ *:[i32] }:$src3)<<P:Predicate_frag>> => (INSN2:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src2)
// R21C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN2,
@ -851,7 +851,7 @@ def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>;
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
// NOOPT-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_simm8,
// NOOPT-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GICXXPred_I64_Predicate_simm8,
// NOOPT-NEXT: // MIs[0] dst
// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
@ -875,7 +875,7 @@ def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$i
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
// NOOPT-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APInt_Predicate_simm9,
// NOOPT-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GICXXPred_APInt_Predicate_simm9,
// NOOPT-NEXT: // MIs[0] dst
// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
@ -899,7 +899,7 @@ def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$i
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
// NOOPT-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_cimm8,
// NOOPT-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GICXXPred_I64_Predicate_cimm8,
// NOOPT-NEXT: // MIs[0] dst
// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
@ -922,7 +922,7 @@ def MOVcimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, cimm8:$
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT,
// NOOPT-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APFloat_Predicate_fpimmz,
// NOOPT-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GICXXPred_APFloat_Predicate_fpimmz,
// NOOPT-NEXT: // MIs[0] dst
// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::FPR32RegClassID,

View File

@ -4,22 +4,22 @@
//
// CHECK: // PatFrag predicates.
// CHECK-NEXT: enum {
// CHECK-NEXT: GIPFP_MI_Predicate_and_or_pat = GIPFP_MI_Invalid + 1,
// CHECK-NEXT: GIPFP_MI_Predicate_or_oneuse,
// CHECK-NEXT: GIPFP_MI_Predicate_patfrags_test_pat,
// CHECK-NEXT: GIPFP_MI_Predicate_sub3_pat,
// CHECK-NEXT: GICXXPred_MI_Predicate_and_or_pat = GICXXPred_MI_Invalid + 1,
// CHECK-NEXT: GICXXPred_MI_Predicate_or_oneuse,
// CHECK-NEXT: GICXXPred_MI_Predicate_patfrags_test_pat,
// CHECK-NEXT: GICXXPred_MI_Predicate_sub3_pat,
// CHECK-NEXT: };
// Verify that we emit cases for all MI predicates.
//
// CHECK: bool MyTargetInstructionSelector::testMIPredicate_MI(
// CHECK: case GIPFP_MI_Predicate_and_or_pat: {
// CHECK: case GICXXPred_MI_Predicate_and_or_pat: {
// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
// CHECK: case GIPFP_MI_Predicate_or_oneuse: {
// CHECK: case GICXXPred_MI_Predicate_or_oneuse: {
// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
// CHECK: case GIPFP_MI_Predicate_patfrags_test_pat: {
// CHECK: case GICXXPred_MI_Predicate_patfrags_test_pat: {
// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
// CHECK: case GIPFP_MI_Predicate_sub3_pat: {
// CHECK: case GICXXPred_MI_Predicate_sub3_pat: {
// CHECK: llvm_unreachable("GISelPredicateCode should have returned");
include "llvm/Target/Target.td"
@ -94,7 +94,7 @@ def and_or_pat : PatFrag<
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_RecordNamedOperand, /*MI*/1, /*Op*/2, /*StoreIdx*/1, // Name : pred:3:y
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/Test::DRegsRegClassID,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_and_or_pat,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_and_or_pat,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (and:{ *:[i32] } DOP:{ *:[i32] }:$src2:$pred:3:z, (or:{ *:[i32] } DOP:{ *:[i32] }:$src0:$pred:3:x, DOP:{ *:[i32] }:$src1:$pred:3:y))<<P:3:Predicate_and_or_pat>> => (AND_OR:{ *:[i32] } DOP:{ *:[i32] }:$src0, DOP:{ *:[i32] }:$src1, DOP:{ *:[i32] }:$src2)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::AND_OR,
@ -124,7 +124,7 @@ def and_or_pat : PatFrag<
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_RecordNamedOperand, /*MI*/0, /*Op*/2, /*StoreIdx*/2, // Name : pred:3:z
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/Test::DRegsRegClassID,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_and_or_pat,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_and_or_pat,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (and:{ *:[i32] } (or:{ *:[i32] } DOP:{ *:[i32] }:$src0:$pred:3:x, DOP:{ *:[i32] }:$src1:$pred:3:y), DOP:{ *:[i32] }:$src2:$pred:3:z)<<P:3:Predicate_and_or_pat>> => (AND_OR:{ *:[i32] } DOP:{ *:[i32] }:$src0, DOP:{ *:[i32] }:$src1, DOP:{ *:[i32] }:$src2)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::AND_OR,
@ -168,7 +168,7 @@ def sub3_pat : PatFrag<
// CHECK-NEXT: // MIs[0] src2
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_RecordNamedOperand, /*MI*/0, /*Op*/2, /*StoreIdx*/2, // Name : pred:1:z
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_sub3_pat,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_sub3_pat,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (sub:{ *:[i32] } (sub:{ *:[i32] } i32:{ *:[i32] }:$src0:$pred:1:x, i32:{ *:[i32] }:$src1:$pred:1:y), i32:{ *:[i32] }:$src2:$pred:1:z)<<P:1:Predicate_sub3_pat>> => (SUB3:{ *:[i32] } i32:{ *:[i32] }:$src0, i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SUB3,

View File

@ -17,7 +17,7 @@ let TargetPrefix = "mytarget" in {
// CHECK-NEXT: // MIs[0] src
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/2, /*SizeInBits*/32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_frag_anyptr,
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_frag_anyptr,
// CHECK-NEXT: // (intrinsic_w_chain:{ *:[i32] } {{[0-9]+}}:{ *:[iPTR] }, GPR32:{ *:[i32] }:$src)<<P:Predicate_frag_anyptr>> => (ANYLOAD:{ *:[i32] } GPR32:{ *:[i32] }:$src)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::ANYLOAD,
let hasSideEffects = 1 in {

View File

@ -12,7 +12,7 @@ def int_mytarget_sleep0 : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
// GISEL-NEXT: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/0, Intrinsic::mytarget_sleep0,
// GISEL-NEXT: // MIs[0] src
// GISEL-NEXT: GIM_CheckIsImm, /*MI*/0, /*Op*/1,
// GISEL-NEXT: GIM_CheckImmOperandPredicate, /*MI*/0, /*MO*/1, /*Predicate*/GIPFP_I64_Predicate_tuimm9,
// GISEL-NEXT: GIM_CheckImmOperandPredicate, /*MI*/0, /*MO*/1, /*Predicate*/GICXXPred_I64_Predicate_tuimm9,
// GISEL-NEXT: // (intrinsic_void {{[0-9]+}}:{ *:[iPTR] }, (timm:{ *:[i32] })<<P:Predicate_tuimm9>>:$src) => (SLEEP0 (timm:{ *:[i32] }):$src)
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SLEEP0,
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src

View File

@ -46,17 +46,17 @@ def TGTmul24_oneuse : PatFrag<
// GISEL: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS,
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, Intrinsic::tgt_mul24,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GICXXPred_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS,
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, Intrinsic::tgt_mul24,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GICXXPred_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckOpcode, /*MI*/1, MyTarget::G_TGT_MUL24,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GICXXPred_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckOpcode, /*MI*/1, MyTarget::G_TGT_MUL24,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIPFP_MI_Predicate_TGTmul24_oneuse,
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GICXXPred_MI_Predicate_TGTmul24_oneuse,
def inst_mad24 : I<
(outs GPR32:$dst),
(ins GPR32:$src0, GPR32:$src1, GPR32:$src2),

View File

@ -2235,10 +2235,10 @@ void GlobalISelEmitter::emitCxxPredicateFns(
OS << "// PatFrag predicates.\n"
<< "enum {\n";
std::string EnumeratorSeparator =
(" = GIPFP_" + TypeIdentifier + "_Invalid + 1,\n").str();
(" = GICXXPred_" + TypeIdentifier + "_Invalid + 1,\n").str();
for (const auto *Record : MatchedRecords) {
OS << " GIPFP_" << TypeIdentifier << "_Predicate_" << Record->getName()
<< EnumeratorSeparator;
OS << " GICXXPred_" << TypeIdentifier << "_Predicate_"
<< Record->getName() << EnumeratorSeparator;
EnumeratorSeparator = ",\n";
}
OS << "};\n";
@ -2253,7 +2253,7 @@ void GlobalISelEmitter::emitCxxPredicateFns(
if (!MatchedRecords.empty())
OS << " switch (PredicateID) {\n";
for (const auto *Record : MatchedRecords) {
OS << " case GIPFP_" << TypeIdentifier << "_Predicate_"
OS << " case GICXXPred_" << TypeIdentifier << "_Predicate_"
<< Record->getName() << ": {\n"
<< " " << Record->getValueAsString(CodeFieldName) << "\n"
<< " llvm_unreachable(\"" << CodeFieldName
@ -2278,9 +2278,11 @@ void GlobalISelEmitter::emitImmPredicateFns(
void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) {
return emitCxxPredicateFns(
OS, "GISelPredicateCode", "MI", "const MachineInstr &", "MI",
", const std::array<const MachineOperand *, 3> &Operands",
", const MatcherState &State",
" const MachineFunction &MF = *MI.getParent()->getParent();\n"
" const MachineRegisterInfo &MRI = MF.getRegInfo();\n"
" const auto &Operands = State.RecordedOperands;\n"
" (void)Operands;\n"
" (void)MRI;",
[](const Record *R) { return true; });
}
@ -2427,9 +2429,9 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const "
"MachineInstr &, int) "
"const;\n"
<< " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, "
<< " const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, "
"CustomRendererFn> "
"ISelInfo;\n";
"ExecInfo;\n";
OS << " static " << Target.getName()
<< "InstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];\n"
<< " static " << Target.getName()
@ -2442,13 +2444,13 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
"&Imm) const override;\n"
<< " const int64_t *getMatchTable() const override;\n"
<< " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI"
", const std::array<const MachineOperand *, 3> &Operands) "
", const MatcherState &State) "
"const override;\n"
<< "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
<< ", State(" << MaxTemporaries << "),\n"
<< "ISelInfo(TypeObjects, NumTypeObjects, FeatureBitsets"
<< "ExecInfo(TypeObjects, NumTypeObjects, FeatureBitsets"
<< ", ComplexPredicateFns, CustomRenderers)\n"
<< "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
@ -2629,9 +2631,9 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< " NewMIVector OutMIs;\n"
<< " State.MIs.clear();\n"
<< " State.MIs.push_back(&I);\n\n"
<< " if (executeMatchTable(*this, OutMIs, State, ISelInfo"
<< " if (executeMatchTable(*this, OutMIs, State, ExecInfo"
<< ", getMatchTable(), TII, MRI, TRI, RBI, AvailableFeatures"
<< ", CoverageInfo)) {\n"
<< ", &CoverageInfo)) {\n"
<< " return true;\n"
<< " }\n\n"
<< " return false;\n"

View File

@ -31,8 +31,8 @@ Error failUnsupported(const Twine &Reason) {
/// Get the name of the enum value used to number the predicate function.
std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {
if (Predicate.hasGISelPredicateCode())
return "GIPFP_MI_" + Predicate.getFnName();
return "GIPFP_" + Predicate.getImmTypeIdentifier().str() + "_" +
return "GICXXPred_MI_" + Predicate.getFnName();
return "GICXXPred_" + Predicate.getImmTypeIdentifier().str() + "_" +
Predicate.getFnName();
}

View File

@ -9,7 +9,7 @@
/// \file
/// This file contains the code related to the GlobalISel Match Table emitted by
/// GlobalISelEmitter.cpp. The generated match table is interpreted at runtime
/// by `InstructionSelectorImpl.h` to match & apply ISel patterns.
/// by `GIMatchTableExecutorImpl.h` to match & apply ISel patterns.
///
//===----------------------------------------------------------------------===//