llvm/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

//===- AArch64InstructionSelector.cpp ----------------------------*- 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 implements the targeting of the InstructionSelector class for
/// AArch64.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#include "AArch64GlobalISelUtils.h"
#include "AArch64InstrInfo.h"
#include "AArch64MachineFunctionInfo.h"
#include "AArch64RegisterBankInfo.h"
#include "AArch64RegisterInfo.h"
#include "AArch64Subtarget.h"
#include "AArch64TargetMachine.h"
#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/MIPatternMatch.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicsAArch64.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>

#define DEBUG_TYPE

usingnamespacellvm;
usingnamespaceMIPatternMatch;
usingnamespaceAArch64GISelUtils;

namespace llvm {
class BlockFrequencyInfo;
class ProfileSummaryInfo;
}

namespace {

#define GET_GLOBALISEL_PREDICATE_BITSET
#include "AArch64GenGlobalISel.inc"
#undef GET_GLOBALISEL_PREDICATE_BITSET


class AArch64InstructionSelector : public InstructionSelector {};

} // end anonymous namespace

#define GET_GLOBALISEL_IMPL
#include "AArch64GenGlobalISel.inc"
#undef GET_GLOBALISEL_IMPL

AArch64InstructionSelector::AArch64InstructionSelector(
    const AArch64TargetMachine &TM, const AArch64Subtarget &STI,
    const AArch64RegisterBankInfo &RBI)
    :{}

// FIXME: This should be target-independent, inferred from the types declared
// for each class in the bank.
//
/// Given a register bank, and a type, return the smallest register class that
/// can represent that combination.
static const TargetRegisterClass *
getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB,
                         bool GetAllRegSet = false) {}

/// Given a register bank, and size in bits, return the smallest register class
/// that can represent that combination.
static const TargetRegisterClass *
getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits,
                      bool GetAllRegSet = false) {}

/// Returns the correct subregister to use for a given register class.
static bool getSubRegForClass(const TargetRegisterClass *RC,
                              const TargetRegisterInfo &TRI, unsigned &SubReg) {}

/// Returns the minimum size the given register bank can hold.
static unsigned getMinSizeForRegBank(const RegisterBank &RB) {}

/// Create a REG_SEQUENCE instruction using the registers in \p Regs.
/// Helper function for functions like createDTuple and createQTuple.
///
/// \p RegClassIDs - The list of register class IDs available for some tuple of
/// a scalar class. E.g. QQRegClassID, QQQRegClassID, QQQQRegClassID. This is
/// expected to contain between 2 and 4 tuple classes.
///
/// \p SubRegs - The list of subregister classes associated with each register
/// class ID in \p RegClassIDs. E.g., QQRegClassID should use the qsub0
/// subregister class. The index of each subregister class is expected to
/// correspond with the index of each register class.
///
/// \returns Either the destination register of REG_SEQUENCE instruction that
/// was created, or the 0th element of \p Regs if \p Regs contains a single
/// element.
static Register createTuple(ArrayRef<Register> Regs,
                            const unsigned RegClassIDs[],
                            const unsigned SubRegs[], MachineIRBuilder &MIB) {}

/// Create a tuple of D-registers using the registers in \p Regs.
static Register createDTuple(ArrayRef<Register> Regs, MachineIRBuilder &MIB) {}

/// Create a tuple of Q-registers using the registers in \p Regs.
static Register createQTuple(ArrayRef<Register> Regs, MachineIRBuilder &MIB) {}

static std::optional<uint64_t> getImmedFromMO(const MachineOperand &Root) {}

/// Check whether \p I is a currently unsupported binary operation:
/// - it has an unsized type
/// - an operand is not a vreg
/// - all operands are not in the same bank
/// These are checks that should someday live in the verifier, but right now,
/// these are mostly limitations of the aarch64 selector.
static bool unsupportedBinOp(const MachineInstr &I,
                             const AArch64RegisterBankInfo &RBI,
                             const MachineRegisterInfo &MRI,
                             const AArch64RegisterInfo &TRI) {}

/// Select the AArch64 opcode for the basic binary operation \p GenericOpc
/// (such as G_OR or G_SDIV), appropriate for the register bank \p RegBankID
/// and of size \p OpSize.
/// \returns \p GenericOpc if the combination is unsupported.
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID,
                               unsigned OpSize) {}

/// Select the AArch64 opcode for the G_LOAD or G_STORE operation \p GenericOpc,
/// appropriate for the (value) register bank \p RegBankID and of memory access
/// size \p OpSize.  This returns the variant with the base+unsigned-immediate
/// addressing mode (e.g., LDRXui).
/// \returns \p GenericOpc if the combination is unsupported.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID,
                                    unsigned OpSize) {}

/// Helper function for selectCopy. Inserts a subregister copy from \p SrcReg
/// to \p *To.
///
/// E.g "To = COPY SrcReg:SubReg"
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI,
                       const RegisterBankInfo &RBI, Register SrcReg,
                       const TargetRegisterClass *To, unsigned SubReg) {}

/// Helper function to get the source and destination register classes for a
/// copy. Returns a std::pair containing the source register class for the
/// copy, and the destination register class for the copy. If a register class
/// cannot be determined, then it will be nullptr.
static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII,
                     MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
                     const RegisterBankInfo &RBI) {}

// FIXME: We need some sort of API in RBI/TRI to allow generic code to
// constrain operands of simple instructions given a TargetRegisterClass
// and LLT
static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI,
                             const RegisterBankInfo &RBI) {}

static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
                       MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
                       const RegisterBankInfo &RBI) {}

static unsigned selectFPConvOpc(unsigned GenericOpc, LLT DstTy, LLT SrcTy) {}

MachineInstr *
AArch64InstructionSelector::emitSelect(Register Dst, Register True,
                                       Register False, AArch64CC::CondCode CC,
                                       MachineIRBuilder &MIB) const {}

static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P) {}

/// changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC,
                                    AArch64CC::CondCode &CondCode,
                                    AArch64CC::CondCode &CondCode2) {}

/// Convert an IR fp condition code to an AArch64 CC.
/// This differs from changeFPCCToAArch64CC in that it returns cond codes that
/// should be AND'ed instead of OR'ed.
static void changeFPCCToANDAArch64CC(CmpInst::Predicate CC,
                                     AArch64CC::CondCode &CondCode,
                                     AArch64CC::CondCode &CondCode2) {}

/// Return a register which can be used as a bit to test in a TB(N)Z.
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert,
                              MachineRegisterInfo &MRI) {}

MachineInstr *AArch64InstructionSelector::emitTestBit(
    Register TestReg, uint64_t Bit, bool IsNegative, MachineBasicBlock *DstMBB,
    MachineIRBuilder &MIB) const {}

bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
    MachineInstr &AndInst, bool Invert, MachineBasicBlock *DstMBB,
    MachineIRBuilder &MIB) const {}

MachineInstr *AArch64InstructionSelector::emitCBZ(Register CompareReg,
                                                  bool IsNegative,
                                                  MachineBasicBlock *DestMBB,
                                                  MachineIRBuilder &MIB) const {}

bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
    MachineInstr &I, MachineInstr &FCmp, MachineIRBuilder &MIB) const {}

bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
    MachineInstr &I, MachineInstr &ICmp, MachineIRBuilder &MIB) const {}

bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
    MachineInstr &I, MachineInstr &ICmp, MachineIRBuilder &MIB) const {}

bool AArch64InstructionSelector::selectCompareBranch(
    MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) {}

/// Returns the element immediate value of a vector shift operand if found.
/// This needs to detect a splat-like operation, e.g. a G_BUILD_VECTOR.
static std::optional<int64_t> getVectorShiftImm(Register Reg,
                                                MachineRegisterInfo &MRI) {}

/// Matches and returns the shift immediate value for a SHL instruction given
/// a shift operand.
static std::optional<int64_t> getVectorSHLImm(LLT SrcTy, Register Reg,
                                              MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &I,
                                                 MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectVectorAshrLshr(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectVaStartAAPCS(
    MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) const {}

bool AArch64InstructionSelector::selectVaStartDarwin(
    MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) const {}

void AArch64InstructionSelector::materializeLargeCMVal(
    MachineInstr &I, const Value *V, unsigned OpFlags) {}

bool AArch64InstructionSelector::preISelLower(MachineInstr &I) {}

/// This lowering tries to look for G_PTR_ADD instructions and then converts
/// them to a standard G_ADD with a COPY on the source.
///
/// The motivation behind this is to expose the add semantics to the imported
/// tablegen patterns. We shouldn't need to check for uses being loads/stores,
/// because the selector works bottom up, uses before defs. By the time we
/// end up trying to select a G_PTR_ADD, we should have already attempted to
/// fold this into addressing modes and were therefore unsuccessful.
bool AArch64InstructionSelector::convertPtrAddToAdd(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &I,
                                                MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::earlySelect(MachineInstr &I) {}

bool AArch64InstructionSelector::select(MachineInstr &I) {}

bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &I) {}

bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
                                            MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectBrJT(MachineInstr &I,
                                            MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectJumpTable(MachineInstr &I,
                                                 MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectTLSGlobalValue(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

MachineInstr *AArch64InstructionSelector::emitScalarToVector(
    unsigned EltSize, const TargetRegisterClass *DstRC, Register Scalar,
    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitNarrowVector(Register DstReg, Register SrcReg,
                                             MachineIRBuilder &MIB,
                                             MachineRegisterInfo &MRI) const {}

bool AArch64InstructionSelector::selectMergeValues(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg,
                              const unsigned EltSize) {}

MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
    std::optional<Register> DstReg, const RegisterBank &DstRB, LLT ScalarTy,
    Register VecReg, unsigned LaneIdx, MachineIRBuilder &MIRBuilder) const {}

bool AArch64InstructionSelector::selectExtractElt(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectSplitVectorUnmerge(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
                                                     MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectConcatVectors(
    MachineInstr &I, MachineRegisterInfo &MRI)  {}

unsigned
AArch64InstructionSelector::emitConstantPoolEntry(const Constant *CPVal,
                                                  MachineFunction &MF) const {}

MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
    const Constant *CPVal, MachineIRBuilder &MIRBuilder) const {}

/// Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given
/// size and RB.
static std::pair<unsigned, unsigned>
getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize) {}

MachineInstr *AArch64InstructionSelector::emitInstr(
    unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
    std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
    const ComplexRendererFns &RenderFns) const {}

MachineInstr *AArch64InstructionSelector::emitAddSub(
    const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
    Register Dst, MachineOperand &LHS, MachineOperand &RHS,
    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitADD(Register DefReg, MachineOperand &LHS,
                                    MachineOperand &RHS,
                                    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitADDS(Register Dst, MachineOperand &LHS,
                                     MachineOperand &RHS,
                                     MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitSUBS(Register Dst, MachineOperand &LHS,
                                     MachineOperand &RHS,
                                     MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitADCS(Register Dst, MachineOperand &LHS,
                                     MachineOperand &RHS,
                                     MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitSBCS(Register Dst, MachineOperand &LHS,
                                     MachineOperand &RHS,
                                     MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitCMN(MachineOperand &LHS, MachineOperand &RHS,
                                    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitTST(MachineOperand &LHS, MachineOperand &RHS,
                                    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
    MachineOperand &LHS, MachineOperand &RHS, MachineOperand &Predicate,
    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
    Register Dst, CmpInst::Predicate Pred, MachineIRBuilder &MIRBuilder) const {}

MachineInstr *AArch64InstructionSelector::emitFPCompare(
    Register LHS, Register RHS, MachineIRBuilder &MIRBuilder,
    std::optional<CmpInst::Predicate> Pred) const {}

MachineInstr *AArch64InstructionSelector::emitVectorConcat(
    std::optional<Register> Dst, Register Op1, Register Op2,
    MachineIRBuilder &MIRBuilder) const {}

MachineInstr *
AArch64InstructionSelector::emitCSINC(Register Dst, Register Src1,
                                      Register Src2, AArch64CC::CondCode Pred,
                                      MachineIRBuilder &MIRBuilder) const {}

MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &I,
                                                      Register CarryReg) {}

bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &I,
                                                  MachineRegisterInfo &MRI) {}

std::pair<MachineInstr *, AArch64CC::CondCode>
AArch64InstructionSelector::emitOverflowOp(unsigned Opcode, Register Dst,
                                           MachineOperand &LHS,
                                           MachineOperand &RHS,
                                           MachineIRBuilder &MIRBuilder) const {}

/// Returns true if @p Val is a tree of AND/OR/CMP operations that can be
/// expressed as a conjunction.
/// \param CanNegate    Set to true if we can negate the whole sub-tree just by
///                     changing the conditions on the CMP tests.
///                     (this means we can call emitConjunctionRec() with
///                      Negate==true on this sub-tree)
/// \param MustBeFirst  Set to true if this subtree needs to be negated and we
///                     cannot do the negation naturally. We are required to
///                     emit the subtree first in this case.
/// \param WillNegate   Is true if are called when the result of this
///                     subexpression must be negated. This happens when the
///                     outer expression is an OR. We can use this fact to know
///                     that we have a double negation (or (or ...) ...) that
///                     can be implemented for free.
static bool canEmitConjunction(Register Val, bool &CanNegate, bool &MustBeFirst,
                               bool WillNegate, MachineRegisterInfo &MRI,
                               unsigned Depth = 0) {}

MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
    Register LHS, Register RHS, CmpInst::Predicate CC,
    AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC,
    MachineIRBuilder &MIB) const {}

MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
    Register Val, AArch64CC::CondCode &OutCC, bool Negate, Register CCOp,
    AArch64CC::CondCode Predicate, MachineIRBuilder &MIB) const {}

MachineInstr *AArch64InstructionSelector::emitConjunction(
    Register Val, AArch64CC::CondCode &OutCC, MachineIRBuilder &MIB) const {}

bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
                                                         MachineInstr &CondMI) {}

bool AArch64InstructionSelector::tryOptSelect(GSelect &I) {}

MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
    MachineOperand &LHS, MachineOperand &RHS, MachineOperand &Predicate,
    MachineIRBuilder &MIRBuilder) const {}

bool AArch64InstructionSelector::selectShuffleVector(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

MachineInstr *AArch64InstructionSelector::emitLaneInsert(
    std::optional<Register> DstReg, Register SrcReg, Register EltReg,
    unsigned LaneIdx, const RegisterBank &RB,
    MachineIRBuilder &MIRBuilder) const {}

bool AArch64InstructionSelector::selectUSMovFromExtend(
    MachineInstr &MI, MachineRegisterInfo &MRI) {}

MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
    Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {}

MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
    Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
    bool Inv) {}

MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
    Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
    bool Inv) {}

MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
    Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {}

MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
    Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
    bool Inv) {}

MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
    Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {}

bool AArch64InstructionSelector::selectIndexedExtLoad(
    MachineInstr &MI, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &MI,
                                                   MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &I,
                                                    MachineRegisterInfo &MRI) {}

MachineInstr *
AArch64InstructionSelector::emitConstantVector(Register Dst, Constant *CV,
                                               MachineIRBuilder &MIRBuilder,
                                               MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::tryOptConstantBuildVec(
    MachineInstr &I, LLT DstTy, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectBuildVector(MachineInstr &I,
                                                   MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectVectorLoadIntrinsic(unsigned Opc,
                                                           unsigned NumVecs,
                                                           MachineInstr &I) {}

bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
    unsigned Opc, unsigned NumVecs, MachineInstr &I) {}

void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &I,
                                                            unsigned NumVecs,
                                                            unsigned Opc) {}

bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
    MachineInstr &I, unsigned NumVecs, unsigned Opc) {}

bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
    MachineInstr &I, MachineRegisterInfo &MRI) {}

bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
                                                 MachineRegisterInfo &MRI) {}

// G_PTRAUTH_GLOBAL_VALUE lowering
//
// We have 3 lowering alternatives to choose from:
// - MOVaddrPAC: similar to MOVaddr, with added PAC.
//   If the GV doesn't need a GOT load (i.e., is locally defined)
//   materialize the pointer using adrp+add+pac. See LowerMOVaddrPAC.
//
// - LOADgotPAC: similar to LOADgot, with added PAC.
//   If the GV needs a GOT load, materialize the pointer using the usual
//   GOT adrp+ldr, +pac. Pointers in GOT are assumed to be not signed, the GOT
//   section is assumed to be read-only (for example, via relro mechanism). See
//   LowerMOVaddrPAC.
//
// - LOADauthptrstatic: similar to LOADgot, but use a
//   special stub slot instead of a GOT slot.
//   Load a signed pointer for symbol 'sym' from a stub slot named
//   'sym$auth_ptr$key$disc' filled by dynamic linker during relocation
//   resolving. This usually lowers to adrp+ldr, but also emits an entry into
//   .data with an
//   @AUTH relocation. See LowerLOADauthptrstatic.
//
// All 3 are pseudos that are expand late to longer sequences: this lets us
// provide integrity guarantees on the to-be-signed intermediate values.
//
// LOADauthptrstatic is undesirable because it requires a large section filled
// with often similarly-signed pointers, making it a good harvesting target.
// Thus, it's only used for ptrauth references to extern_weak to avoid null
// checks.

bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
    MachineInstr &I, MachineRegisterInfo &MRI) const {}

void AArch64InstructionSelector::SelectTable(MachineInstr &I,
                                             MachineRegisterInfo &MRI,
                                             unsigned NumVec, unsigned Opc1,
                                             unsigned Opc2, bool isExt) {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectShiftA_32(const MachineOperand &Root) const {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectShiftB_32(const MachineOperand &Root) const {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectShiftA_64(const MachineOperand &Root) const {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectShiftB_64(const MachineOperand &Root) const {}

/// Helper to select an immediate value that can be represented as a 12-bit
/// value shifted left by either 0 or 12. If it is possible to do so, return
/// the immediate and shift value. If not, return std::nullopt.
///
/// Used by selectArithImmed and selectNegArithImmed.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::select12BitValueWithLeftShift(
    uint64_t Immed) const {}

/// SelectArithImmed - Select an immediate value that can be represented as
/// a 12-bit value shifted left by either 0 or 12.  If so, return true with
/// Val set to the 12-bit value and Shift set to the shifter operand.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectArithImmed(MachineOperand &Root) const {}

/// SelectNegArithImmed - As above, but negates the value before trying to
/// select it.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root) const {}

/// Checks if we are sure that folding MI into load/store addressing mode is
/// beneficial or not.
///
/// Returns:
/// - true if folding MI would be beneficial.
/// - false if folding MI would be bad.
/// - std::nullopt if it is not sure whether folding MI is beneficial.
///
/// \p MI can be the offset operand of G_PTR_ADD, e.g. G_SHL in the example:
///
/// %13:gpr(s64) = G_CONSTANT i64 1
/// %8:gpr(s64) = G_SHL %6, %13(s64)
/// %9:gpr(p0) = G_PTR_ADD %0, %8(s64)
/// %12:gpr(s32) = G_LOAD %9(p0) :: (load (s16))
std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
    MachineInstr &MI, const MachineRegisterInfo &MRI) const {}

/// Return true if it is worth folding MI into an extended register. That is,
/// if it's safe to pull it into the addressing mode of a load or store as a
/// shift.
/// \p IsAddrOperand whether the def of MI is used as an address operand
/// (e.g. feeding into an LDR/STR).
bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
    MachineInstr &MI, const MachineRegisterInfo &MRI,
    bool IsAddrOperand) const {}

static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type) {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectExtendedSHL(
    MachineOperand &Root, MachineOperand &Base, MachineOperand &Offset,
    unsigned SizeInBytes, bool WantsExt) const {}

/// This is used for computing addresses like this:
///
/// ldr x1, [x2, x3, lsl #3]
///
/// Where x2 is the base register, and x3 is an offset register. The shift-left
/// is a constant value specific to this load instruction. That is, we'll never
/// see anything other than a 3 here (which corresponds to the size of the
/// element being loaded.)
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
    MachineOperand &Root, unsigned SizeInBytes) const {}

/// This is used for computing addresses like this:
///
/// ldr x1, [x2, x3]
///
/// Where x2 is the base register, and x3 is an offset register.
///
/// When possible (or profitable) to fold a G_PTR_ADD into the address
/// calculation, this will do so. Otherwise, it will return std::nullopt.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectAddrModeRegisterOffset(
    MachineOperand &Root) const {}

/// This is intended to be equivalent to selectAddrModeXRO in
/// AArch64ISelDAGtoDAG. It's used for selecting X register offset loads.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
                                              unsigned SizeInBytes) const {}

/// This is used for computing addresses like this:
///
/// ldr x0, [xBase, wOffset, sxtw #LegalShiftVal]
///
/// Where we have a 64-bit base register, a 32-bit offset register, and an
/// extend (which may or may not be signed).
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
                                              unsigned SizeInBytes) const {}

/// Select a "register plus unscaled signed 9-bit immediate" address.  This
/// should only match when there is an offset that is not valid for a scaled
/// immediate addressing mode.  The "Size" argument is the size in bytes of the
/// memory reference, which is needed here to know what is valid for a scaled
/// immediate.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
                                                   unsigned Size) const {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
                                                 unsigned Size,
                                                 MachineRegisterInfo &MRI) const {}

/// Select a "register plus scaled unsigned 12-bit immediate" address.  The
/// "Size" argument is the size in bytes of the memory reference, which
/// determines the scale.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
                                                  unsigned Size) const {}

/// Given a shift instruction, return the correct shift type for that
/// instruction.
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI) {}

/// Select a "shifted register" operand. If the value is not shifted, set the
/// shift operand to a default value of "lsl 0".
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
                                                  bool AllowROR) const {}

AArch64_AM::ShiftExtendType AArch64InstructionSelector::getExtendTypeForInst(
    MachineInstr &MI, MachineRegisterInfo &MRI, bool IsLoadStore) const {}

Register AArch64InstructionSelector::moveScalarRegClass(
    Register Reg, const TargetRegisterClass &RC, MachineIRBuilder &MIB) const {}

/// Select an "extended register" operand. This operand folds in an extend
/// followed by an optional left shift.
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectArithExtendedRegister(
    MachineOperand &Root) const {}

InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root) const {}

void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
                                                const MachineInstr &MI,
                                                int OpIdx) const {}

void AArch64InstructionSelector::renderLogicalImm32(
  MachineInstrBuilder &MIB, const MachineInstr &I, int OpIdx) const {}

void AArch64InstructionSelector::renderLogicalImm64(
  MachineInstrBuilder &MIB, const MachineInstr &I, int OpIdx) const {}

void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
                                                 const MachineInstr &MI,
                                                 int OpIdx) const {}

void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
                                               const MachineInstr &MI,
                                               int OpIdx) const {}

void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
                                               const MachineInstr &MI,
                                               int OpIdx) const {}

void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
                                               const MachineInstr &MI,
                                               int OpIdx) const {}

void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
    MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const {}

bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
    const MachineInstr &MI, unsigned NumBytes) const {}

bool AArch64InstructionSelector::isDef32(const MachineInstr &MI) const {}


// Perform fixups on the given PHI instruction's operands to force them all
// to be the same as the destination regbank.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI,
                            const AArch64RegisterBankInfo &RBI) {}

void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {}

namespace llvm {
InstructionSelector *
createAArch64InstructionSelector(const AArch64TargetMachine &TM,
                                 const AArch64Subtarget &Subtarget,
                                 const AArch64RegisterBankInfo &RBI) {}
}