123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- llvm/CodeGen/GlobalISel/InstructionSelector.h ------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- /// \file This file declares the API for the instruction selector.
- /// This class is responsible for selecting machine instructions.
- /// It's implemented by the target. It's used by the InstructionSelect pass.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
- #define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/Optional.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/Analysis/BlockFrequencyInfo.h"
- #include "llvm/Analysis/ProfileSummaryInfo.h"
- #include "llvm/CodeGen/GlobalISel/Utils.h"
- #include "llvm/CodeGen/MachineBasicBlock.h"
- #include "llvm/CodeGen/MachineFunction.h"
- #include "llvm/Support/CodeGenCoverage.h"
- #include "llvm/Support/LowLevelTypeImpl.h"
- #include <bitset>
- #include <cstddef>
- #include <cstdint>
- #include <functional>
- #include <initializer_list>
- #include <vector>
- namespace llvm {
- class APInt;
- class APFloat;
- class GISelKnownBits;
- class MachineInstr;
- class MachineInstrBuilder;
- class MachineFunction;
- class MachineOperand;
- class MachineRegisterInfo;
- class RegisterBankInfo;
- class TargetInstrInfo;
- class TargetRegisterInfo;
- /// Container class for CodeGen predicate results.
- /// This is convenient because std::bitset does not have a constructor
- /// with an initializer list of set bits.
- ///
- /// Each InstructionSelector subclass should define a PredicateBitset class
- /// with:
- /// const unsigned MAX_SUBTARGET_PREDICATES = 192;
- /// using PredicateBitset = PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
- /// and updating the constant to suit the target. Tablegen provides a suitable
- /// definition for the predicates in use in <Target>GenGlobalISel.inc when
- /// GET_GLOBALISEL_PREDICATE_BITSET is defined.
- template <std::size_t MaxPredicates>
- class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
- public:
- // Cannot inherit constructors because it's not supported by VC++..
- PredicateBitsetImpl() = default;
- PredicateBitsetImpl(const std::bitset<MaxPredicates> &B)
- : std::bitset<MaxPredicates>(B) {}
- PredicateBitsetImpl(std::initializer_list<unsigned> Init) {
- for (auto I : Init)
- std::bitset<MaxPredicates>::set(I);
- }
- };
- enum {
- /// Begin a try-block to attempt a match and jump to OnFail if it is
- /// unsuccessful.
- /// - OnFail - The MatchTable entry at which to resume if the match fails.
- ///
- /// FIXME: This ought to take an argument indicating the number of try-blocks
- /// to exit on failure. It's usually one but the last match attempt of
- /// a block will need more. The (implemented) alternative is to tack a
- /// GIM_Reject on the end of each try-block which is simpler but
- /// requires an extra opcode and iteration in the interpreter on each
- /// failed match.
- GIM_Try,
- /// Switch over the opcode on the specified instruction
- /// - InsnID - Instruction ID
- /// - LowerBound - numerically minimum opcode supported
- /// - UpperBound - numerically maximum + 1 opcode supported
- /// - Default - failure jump target
- /// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
- GIM_SwitchOpcode,
- /// Switch over the LLT on the specified instruction operand
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - LowerBound - numerically minimum Type ID supported
- /// - UpperBound - numerically maximum + 1 Type ID supported
- /// - Default - failure jump target
- /// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
- GIM_SwitchType,
- /// Record the specified instruction
- /// - NewInsnID - Instruction ID to define
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- GIM_RecordInsn,
- /// Check the feature bits
- /// - Expected features
- GIM_CheckFeatures,
- /// Check the opcode on the specified instruction
- /// - InsnID - Instruction ID
- /// - Expected opcode
- GIM_CheckOpcode,
- /// Check the opcode on the specified instruction, checking 2 acceptable
- /// alternatives.
- /// - InsnID - Instruction ID
- /// - Expected opcode
- /// - Alternative expected opcode
- GIM_CheckOpcodeIsEither,
- /// Check the instruction has the right number of operands
- /// - InsnID - Instruction ID
- /// - Expected number of operands
- GIM_CheckNumOperands,
- /// Check an immediate predicate on the specified instruction
- /// - InsnID - Instruction ID
- /// - The predicate to test
- GIM_CheckI64ImmPredicate,
- /// Check an immediate predicate on the specified instruction via an APInt.
- /// - InsnID - Instruction ID
- /// - The predicate to test
- GIM_CheckAPIntImmPredicate,
- /// Check a floating point immediate predicate on the specified instruction.
- /// - InsnID - Instruction ID
- /// - The predicate to test
- GIM_CheckAPFloatImmPredicate,
- /// Check an immediate predicate on the specified instruction
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - The predicate to test
- GIM_CheckImmOperandPredicate,
- /// Check a memory operation has the specified atomic ordering.
- /// - InsnID - Instruction ID
- /// - Ordering - The AtomicOrdering value
- GIM_CheckAtomicOrdering,
- GIM_CheckAtomicOrderingOrStrongerThan,
- GIM_CheckAtomicOrderingWeakerThan,
- /// Check the size of the memory access for the given machine memory operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - Size - The size in bytes of the memory access
- GIM_CheckMemorySizeEqualTo,
- /// Check the address space of the memory access for the given machine memory
- /// operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - NumAddrSpace - Number of valid address spaces
- /// - AddrSpaceN - An allowed space of the memory access
- /// - AddrSpaceN+1 ...
- GIM_CheckMemoryAddressSpace,
- /// Check the minimum alignment of the memory access for the given machine
- /// memory operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - MinAlign - Minimum acceptable alignment
- GIM_CheckMemoryAlignment,
- /// Check the size of the memory access for the given machine memory operand
- /// against the size of an operand.
- /// - InsnID - Instruction ID
- /// - MMOIdx - MMO index
- /// - OpIdx - The operand index to compare the MMO against
- GIM_CheckMemorySizeEqualToLLT,
- GIM_CheckMemorySizeLessThanLLT,
- GIM_CheckMemorySizeGreaterThanLLT,
- /// Check if this is a vector that can be treated as a vector splat
- /// constant. This is valid for both G_BUILD_VECTOR as well as
- /// G_BUILD_VECTOR_TRUNC. For AllOnes refers to individual bits, so a -1
- /// element.
- /// - InsnID - Instruction ID
- GIM_CheckIsBuildVectorAllOnes,
- GIM_CheckIsBuildVectorAllZeros,
- /// Check a generic C++ instruction predicate
- /// - InsnID - Instruction ID
- /// - PredicateID - The ID of the predicate function to call
- GIM_CheckCxxInsnPredicate,
- /// Check the type for the specified operand
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected type
- GIM_CheckType,
- /// Check the type of a pointer to any address space.
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - SizeInBits - The size of the pointer value in bits.
- GIM_CheckPointerToAny,
- /// Check the register bank for the specified operand
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected register bank (specified as a register class)
- GIM_CheckRegBankForClass,
- /// Check the operand matches a complex predicate
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - RendererID - The renderer to hold the result
- /// - Complex predicate ID
- GIM_CheckComplexPattern,
- /// Check the operand is a specific integer
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected integer
- GIM_CheckConstantInt,
- /// Check the operand is a specific literal integer (i.e. MO.isImm() or
- /// MO.isCImm() is true).
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected integer
- GIM_CheckLiteralInt,
- /// Check the operand is a specific intrinsic ID
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected Intrinsic ID
- GIM_CheckIntrinsicID,
- /// Check the operand is a specific predicate
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - Expected predicate
- GIM_CheckCmpPredicate,
- /// Check the specified operand is an MBB
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- GIM_CheckIsMBB,
- /// Check the specified operand is an Imm
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- GIM_CheckIsImm,
- /// Check if the specified operand is safe to fold into the current
- /// instruction.
- /// - InsnID - Instruction ID
- GIM_CheckIsSafeToFold,
- /// Check the specified operands are identical.
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - OtherInsnID - Other instruction ID
- /// - OtherOpIdx - Other operand index
- GIM_CheckIsSameOperand,
- /// Predicates with 'let PredicateCodeUsesOperands = 1' need to examine some
- /// named operands that will be recorded in RecordedOperands. Names of these
- /// operands are referenced in predicate argument list. Emitter determines
- /// StoreIdx(corresponds to the order in which names appear in argument list).
- /// - InsnID - Instruction ID
- /// - OpIdx - Operand index
- /// - StoreIdx - Store location in RecordedOperands.
- GIM_RecordNamedOperand,
- /// Fail the current try-block, or completely fail to match if there is no
- /// current try-block.
- GIM_Reject,
- //=== Renderers ===
- /// Mutate an instruction
- /// - NewInsnID - Instruction ID to define
- /// - OldInsnID - Instruction ID to mutate
- /// - NewOpcode - The new opcode to use
- GIR_MutateOpcode,
- /// Build a new instruction
- /// - InsnID - Instruction ID to define
- /// - Opcode - The new opcode to use
- GIR_BuildMI,
- /// Copy an operand to the specified instruction
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// - OpIdx - The operand to copy
- GIR_Copy,
- /// Copy an operand to the specified instruction or add a zero register if the
- /// operand is a zero immediate.
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// - OpIdx - The operand to copy
- /// - ZeroReg - The zero register to use
- GIR_CopyOrAddZeroReg,
- /// Copy an operand to the specified instruction
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// - OpIdx - The operand to copy
- /// - SubRegIdx - The subregister to copy
- GIR_CopySubReg,
- /// Add an implicit register def to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RegNum - The register to add
- GIR_AddImplicitDef,
- /// Add an implicit register use to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RegNum - The register to add
- GIR_AddImplicitUse,
- /// Add an register to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RegNum - The register to add
- GIR_AddRegister,
- /// Add a temporary register to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - TempRegID - The temporary register ID to add
- /// - TempRegFlags - The register flags to set
- GIR_AddTempRegister,
- /// Add a temporary register to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - TempRegID - The temporary register ID to add
- /// - TempRegFlags - The register flags to set
- /// - SubRegIndex - The subregister index to set
- GIR_AddTempSubRegister,
- /// Add an immediate to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - Imm - The immediate to add
- GIR_AddImm,
- /// Render complex operands to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RendererID - The renderer to call
- GIR_ComplexRenderer,
- /// Render sub-operands of complex operands to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - RendererID - The renderer to call
- /// - RenderOpID - The suboperand to render.
- GIR_ComplexSubOperandRenderer,
- /// Render operands to the specified instruction using a custom function
- /// - InsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to get the matched operand from
- /// - RendererFnID - Custom renderer function to call
- GIR_CustomRenderer,
- /// Render operands to the specified instruction using a custom function,
- /// reading from a specific operand.
- /// - InsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to get the matched operand from
- /// - OpIdx - Operand index in OldInsnID the render function should read from..
- /// - RendererFnID - Custom renderer function to call
- GIR_CustomOperandRenderer,
- /// Render a G_CONSTANT operator as a sign-extended immediate.
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// The operand index is implicitly 1.
- GIR_CopyConstantAsSImm,
- /// Render a G_FCONSTANT operator as a sign-extended immediate.
- /// - NewInsnID - Instruction ID to modify
- /// - OldInsnID - Instruction ID to copy from
- /// The operand index is implicitly 1.
- GIR_CopyFConstantAsFPImm,
- /// Constrain an instruction operand to a register class.
- /// - InsnID - Instruction ID to modify
- /// - OpIdx - Operand index
- /// - RCEnum - Register class enumeration value
- GIR_ConstrainOperandRC,
- /// Constrain an instructions operands according to the instruction
- /// description.
- /// - InsnID - Instruction ID to modify
- GIR_ConstrainSelectedInstOperands,
- /// Merge all memory operands into instruction.
- /// - InsnID - Instruction ID to modify
- /// - MergeInsnID... - One or more Instruction ID to merge into the result.
- /// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to
- /// merge.
- GIR_MergeMemOperands,
- /// Erase from parent.
- /// - InsnID - Instruction ID to erase
- GIR_EraseFromParent,
- /// Create a new temporary register that's not constrained.
- /// - TempRegID - The temporary register ID to initialize.
- /// - Expected type
- GIR_MakeTempReg,
- /// A successful emission
- GIR_Done,
- /// Increment the rule coverage counter.
- /// - RuleID - The ID of the rule that was covered.
- GIR_Coverage,
- /// Keeping track of the number of the GI opcodes. Must be the last entry.
- GIU_NumOpcodes,
- };
- enum {
- /// Indicates the end of the variable-length MergeInsnID list in a
- /// GIR_MergeMemOperands opcode.
- GIU_MergeMemOperands_EndOfList = -1,
- };
- /// Provides the logic to select generic machine instructions.
- class InstructionSelector {
- public:
- virtual ~InstructionSelector() = default;
- /// Select the (possibly generic) instruction \p I to only use target-specific
- /// opcodes. It is OK to insert multiple instructions, but they cannot be
- /// generic pre-isel instructions.
- ///
- /// \returns whether selection succeeded.
- /// \pre I.getParent() && I.getParent()->getParent()
- /// \post
- /// if returns true:
- /// for I in all mutated/inserted instructions:
- /// !isPreISelGenericOpcode(I.getOpcode())
- virtual bool select(MachineInstr &I) = 0;
- CodeGenCoverage *CoverageInfo = nullptr;
- GISelKnownBits *KnownBits = nullptr;
- MachineFunction *MF = nullptr;
- ProfileSummaryInfo *PSI = nullptr;
- BlockFrequencyInfo *BFI = nullptr;
- // For some predicates, we need to track the current MBB.
- MachineBasicBlock *CurMBB = nullptr;
- virtual void setupGeneratedPerFunctionState(MachineFunction &MF) {
- llvm_unreachable("TableGen should have emitted implementation");
- }
- /// Setup per-MF selector state.
- virtual void setupMF(MachineFunction &mf, GISelKnownBits *KB,
- CodeGenCoverage &covinfo, ProfileSummaryInfo *psi,
- BlockFrequencyInfo *bfi) {
- CoverageInfo = &covinfo;
- KnownBits = KB;
- MF = &mf;
- PSI = psi;
- BFI = bfi;
- CurMBB = nullptr;
- setupGeneratedPerFunctionState(mf);
- }
- protected:
- using ComplexRendererFns =
- Optional<SmallVector<std::function<void(MachineInstrBuilder &)>, 4>>;
- using RecordedMIVector = SmallVector<MachineInstr *, 4>;
- using NewMIVector = SmallVector<MachineInstrBuilder, 4>;
- struct MatcherState {
- std::vector<ComplexRendererFns::value_type> Renderers;
- RecordedMIVector MIs;
- DenseMap<unsigned, unsigned> TempRegisters;
- /// Named operands that predicate with 'let PredicateCodeUsesOperands = 1'
- /// referenced in its argument list. Operands are inserted at index set by
- /// emitter, it corresponds to the order in which names appear in argument
- /// list. Currently such predicates don't have more then 3 arguments.
- std::array<const MachineOperand *, 3> RecordedOperands;
- MatcherState(unsigned MaxRenderers);
- };
- bool shouldOptForSize(const MachineFunction *MF) const {
- const auto &F = MF->getFunction();
- return F.hasOptSize() || F.hasMinSize() ||
- (PSI && BFI && CurMBB && llvm::shouldOptForSize(*CurMBB, PSI, BFI));
- }
- public:
- template <class PredicateBitset, class ComplexMatcherMemFn,
- class CustomRendererFn>
- struct ISelInfoTy {
- ISelInfoTy(const LLT *TypeObjects, size_t NumTypeObjects,
- const PredicateBitset *FeatureBitsets,
- const ComplexMatcherMemFn *ComplexPredicates,
- const CustomRendererFn *CustomRenderers)
- : TypeObjects(TypeObjects),
- FeatureBitsets(FeatureBitsets),
- ComplexPredicates(ComplexPredicates),
- CustomRenderers(CustomRenderers) {
- for (size_t I = 0; I < NumTypeObjects; ++I)
- TypeIDMap[TypeObjects[I]] = I;
- }
- const LLT *TypeObjects;
- const PredicateBitset *FeatureBitsets;
- const ComplexMatcherMemFn *ComplexPredicates;
- const CustomRendererFn *CustomRenderers;
- SmallDenseMap<LLT, unsigned, 64> TypeIDMap;
- };
- protected:
- InstructionSelector();
- /// Execute a given matcher table and return true if the match was successful
- /// and false otherwise.
- template <class TgtInstructionSelector, class PredicateBitset,
- class ComplexMatcherMemFn, class CustomRendererFn>
- bool executeMatchTable(
- TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
- const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
- &ISelInfo,
- const int64_t *MatchTable, const TargetInstrInfo &TII,
- MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
- const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
- CodeGenCoverage &CoverageInfo) const;
- virtual const int64_t *getMatchTable() const {
- llvm_unreachable("Should have been overridden by tablegen if used");
- }
- virtual bool testImmPredicate_I64(unsigned, int64_t) const {
- llvm_unreachable(
- "Subclasses must override this with a tablegen-erated function");
- }
- virtual bool testImmPredicate_APInt(unsigned, const APInt &) const {
- llvm_unreachable(
- "Subclasses must override this with a tablegen-erated function");
- }
- virtual bool testImmPredicate_APFloat(unsigned, const APFloat &) const {
- llvm_unreachable(
- "Subclasses must override this with a tablegen-erated function");
- }
- virtual bool testMIPredicate_MI(
- unsigned, const MachineInstr &,
- const std::array<const MachineOperand *, 3> &Operands) const {
- llvm_unreachable(
- "Subclasses must override this with a tablegen-erated function");
- }
- bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
- const MachineRegisterInfo &MRI) const;
- /// Return true if the specified operand is a G_PTR_ADD with a G_CONSTANT on the
- /// right-hand side. GlobalISel's separation of pointer and integer types
- /// means that we don't need to worry about G_OR with equivalent semantics.
- bool isBaseWithConstantOffset(const MachineOperand &Root,
- const MachineRegisterInfo &MRI) const;
- /// Return true if MI can obviously be folded into IntoMI.
- /// MI and IntoMI do not need to be in the same basic blocks, but MI must
- /// preceed IntoMI.
- bool isObviouslySafeToFold(MachineInstr &MI, MachineInstr &IntoMI) const;
- };
- } // end namespace llvm
- #endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|