45#include "llvm/IR/IntrinsicsAArch64.h"
52#define DEBUG_TYPE "aarch64-isel"
65#define GET_GLOBALISEL_PREDICATE_BITSET
66#include "AArch64GenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATE_BITSET
87 ProduceNonFlagSettingCondBr =
135 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
213 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
215 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
217 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
219 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
233 unsigned Opc1,
unsigned Opc2,
bool isExt);
239 unsigned emitConstantPoolEntry(
const Constant *CPVal,
258 std::optional<CmpInst::Predicate> = std::nullopt)
const;
261 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
262 std::initializer_list<llvm::SrcOp> SrcOps,
264 const ComplexRendererFns &RenderFns = std::nullopt)
const;
299 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
322 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
344 std::pair<MachineInstr *, AArch64CC::CondCode>
379 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
380 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
381 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
382 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
384 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
386 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
389 unsigned Size)
const;
391 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
392 return selectAddrModeUnscaled(Root, 1);
394 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
395 return selectAddrModeUnscaled(Root, 2);
397 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
398 return selectAddrModeUnscaled(Root, 4);
400 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
401 return selectAddrModeUnscaled(Root, 8);
403 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
404 return selectAddrModeUnscaled(Root, 16);
409 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
413 unsigned Size)
const;
415 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
416 return selectAddrModeIndexed(Root, Width / 8);
425 bool IsAddrOperand)
const;
428 unsigned SizeInBytes)
const;
436 bool WantsExt)
const;
437 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
439 unsigned SizeInBytes)
const;
441 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
442 return selectAddrModeXRO(Root, Width / 8);
446 unsigned SizeInBytes)
const;
448 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
449 return selectAddrModeWRO(Root, Width / 8);
453 bool AllowROR =
false)
const;
455 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
456 return selectShiftedRegister(Root);
459 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
460 return selectShiftedRegister(Root,
true);
470 bool IsLoadStore =
false)
const;
481 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
485 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
490 bool isReciprocal =
false)
const;
492 int OpIdx = -1)
const;
497 int OpIdx = -1)
const;
499 int OpIdx = -1)
const;
501 int OpIdx = -1)
const;
505 int OpIdx = -1)
const;
507 int OpIdx = -1)
const;
509 int OpIdx = -1)
const;
512 int OpIdx = -1)
const;
518 bool tryOptSelect(
GSelect &Sel);
525 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
538 bool ProduceNonFlagSettingCondBr =
false;
547#define GET_GLOBALISEL_PREDICATES_DECL
548#include "AArch64GenGlobalISel.inc"
549#undef GET_GLOBALISEL_PREDICATES_DECL
553#define GET_GLOBALISEL_TEMPORARIES_DECL
554#include "AArch64GenGlobalISel.inc"
555#undef GET_GLOBALISEL_TEMPORARIES_DECL
560#define GET_GLOBALISEL_IMPL
561#include "AArch64GenGlobalISel.inc"
562#undef GET_GLOBALISEL_IMPL
564AArch64InstructionSelector::AArch64InstructionSelector(
567 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
570#include
"AArch64GenGlobalISel.inc"
573#include
"AArch64GenGlobalISel.inc"
585 bool GetAllRegSet =
false) {
586 if (RB.
getID() == AArch64::GPRRegBankID) {
587 if (Ty.getSizeInBits() <= 32)
588 return GetAllRegSet ? &AArch64::GPR32allRegClass
589 : &AArch64::GPR32RegClass;
590 if (Ty.getSizeInBits() == 64)
591 return GetAllRegSet ? &AArch64::GPR64allRegClass
592 : &AArch64::GPR64RegClass;
593 if (Ty.getSizeInBits() == 128)
594 return &AArch64::XSeqPairsClassRegClass;
598 if (RB.
getID() == AArch64::FPRRegBankID) {
599 switch (Ty.getSizeInBits()) {
601 return &AArch64::FPR8RegClass;
603 return &AArch64::FPR16RegClass;
605 return &AArch64::FPR32RegClass;
607 return &AArch64::FPR64RegClass;
609 return &AArch64::FPR128RegClass;
621 bool GetAllRegSet =
false) {
624 "Expected FPR regbank for scalable type size");
625 return &AArch64::ZPRRegClass;
628 unsigned RegBankID = RB.
getID();
630 if (RegBankID == AArch64::GPRRegBankID) {
632 if (SizeInBits <= 32)
633 return GetAllRegSet ? &AArch64::GPR32allRegClass
634 : &AArch64::GPR32RegClass;
635 if (SizeInBits == 64)
636 return GetAllRegSet ? &AArch64::GPR64allRegClass
637 : &AArch64::GPR64RegClass;
638 if (SizeInBits == 128)
639 return &AArch64::XSeqPairsClassRegClass;
642 if (RegBankID == AArch64::FPRRegBankID) {
645 "Unexpected scalable register size");
646 return &AArch64::ZPRRegClass;
649 switch (SizeInBits) {
653 return &AArch64::FPR8RegClass;
655 return &AArch64::FPR16RegClass;
657 return &AArch64::FPR32RegClass;
659 return &AArch64::FPR64RegClass;
661 return &AArch64::FPR128RegClass;
671 switch (
TRI.getRegSizeInBits(*RC)) {
673 SubReg = AArch64::bsub;
676 SubReg = AArch64::hsub;
679 if (RC != &AArch64::FPR32RegClass)
680 SubReg = AArch64::sub_32;
682 SubReg = AArch64::ssub;
685 SubReg = AArch64::dsub;
689 dbgs() <<
"Couldn't find appropriate subregister for register class.");
698 switch (RB.
getID()) {
699 case AArch64::GPRRegBankID:
701 case AArch64::FPRRegBankID:
724 const unsigned RegClassIDs[],
726 unsigned NumRegs = Regs.
size();
729 assert(NumRegs >= 2 && NumRegs <= 4 &&
730 "Only support between two and 4 registers in a tuple!");
732 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
734 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
735 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
736 RegSequence.addUse(Regs[
I]);
737 RegSequence.addImm(SubRegs[
I]);
739 return RegSequence.getReg(0);
744 static const unsigned RegClassIDs[] = {
745 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
746 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
747 AArch64::dsub2, AArch64::dsub3};
748 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
753 static const unsigned RegClassIDs[] = {
754 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
755 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
756 AArch64::qsub2, AArch64::qsub3};
757 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
762 auto &
MBB = *
MI.getParent();
763 auto &MF = *
MBB.getParent();
764 auto &MRI = MF.getRegInfo();
770 else if (Root.
isReg()) {
775 Immed = ValAndVReg->Value.getSExtValue();
798 for (
auto &MO :
I.operands()) {
801 LLVM_DEBUG(
dbgs() <<
"Generic inst non-reg operands are unsupported\n");
809 if (!MO.getReg().isVirtual()) {
810 LLVM_DEBUG(
dbgs() <<
"Generic inst has physical register operand\n");
820 if (PrevOpBank && OpBank != PrevOpBank) {
821 LLVM_DEBUG(
dbgs() <<
"Generic inst operands have different banks\n");
836 case AArch64::GPRRegBankID:
838 switch (GenericOpc) {
839 case TargetOpcode::G_SHL:
840 return AArch64::LSLVWr;
841 case TargetOpcode::G_LSHR:
842 return AArch64::LSRVWr;
843 case TargetOpcode::G_ASHR:
844 return AArch64::ASRVWr;
848 }
else if (OpSize == 64) {
849 switch (GenericOpc) {
850 case TargetOpcode::G_PTR_ADD:
851 return AArch64::ADDXrr;
852 case TargetOpcode::G_SHL:
853 return AArch64::LSLVXr;
854 case TargetOpcode::G_LSHR:
855 return AArch64::LSRVXr;
856 case TargetOpcode::G_ASHR:
857 return AArch64::ASRVXr;
863 case AArch64::FPRRegBankID:
866 switch (GenericOpc) {
867 case TargetOpcode::G_FADD:
868 return AArch64::FADDSrr;
869 case TargetOpcode::G_FSUB:
870 return AArch64::FSUBSrr;
871 case TargetOpcode::G_FMUL:
872 return AArch64::FMULSrr;
873 case TargetOpcode::G_FDIV:
874 return AArch64::FDIVSrr;
879 switch (GenericOpc) {
880 case TargetOpcode::G_FADD:
881 return AArch64::FADDDrr;
882 case TargetOpcode::G_FSUB:
883 return AArch64::FSUBDrr;
884 case TargetOpcode::G_FMUL:
885 return AArch64::FMULDrr;
886 case TargetOpcode::G_FDIV:
887 return AArch64::FDIVDrr;
888 case TargetOpcode::G_OR:
889 return AArch64::ORRv8i8;
906 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
908 case AArch64::GPRRegBankID:
911 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
913 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
915 return isStore ? AArch64::STRWui : AArch64::LDRWui;
917 return isStore ? AArch64::STRXui : AArch64::LDRXui;
920 case AArch64::FPRRegBankID:
923 return isStore ? AArch64::STRBui : AArch64::LDRBui;
925 return isStore ? AArch64::STRHui : AArch64::LDRHui;
927 return isStore ? AArch64::STRSui : AArch64::LDRSui;
929 return isStore ? AArch64::STRDui : AArch64::LDRDui;
931 return isStore ? AArch64::STRQui : AArch64::LDRQui;
945 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
946 assert(To &&
"Destination register class cannot be null");
947 assert(SubReg &&
"Expected a valid subregister");
951 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
953 RegOp.
setReg(SubRegCopy.getReg(0));
957 if (!
I.getOperand(0).getReg().isPhysical())
967static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
971 Register DstReg =
I.getOperand(0).getReg();
972 Register SrcReg =
I.getOperand(1).getReg();
987 if (SrcRegBank != DstRegBank &&
1006 if (
Reg.isPhysical())
1014 RC = getRegClassForTypeOnBank(Ty, RB);
1017 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
1030 Register DstReg =
I.getOperand(0).getReg();
1031 Register SrcReg =
I.getOperand(1).getReg();
1050 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1054 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1055 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1056 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
1070 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1071 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
1072 }
else if (SrcSize > DstSize) {
1079 }
else if (DstSize > SrcSize) {
1088 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1092 RegOp.
setReg(PromoteReg);
1111 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1112 I.setDesc(
TII.get(AArch64::COPY));
1113 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1117 I.setDesc(
TII.get(AArch64::COPY));
1125 MachineRegisterInfo &MRI = *MIB.
getMRI();
1128 "Expected both select operands to have the same regbank?");
1134 "Expected 32 bit or 64 bit select only?");
1135 const bool Is32Bit =
Size == 32;
1137 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1138 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1144 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1146 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1161 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1178 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1197 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1213 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1219 if (!TrueCst && !FalseCst)
1222 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1223 if (TrueCst && FalseCst) {
1224 int64_t
T = TrueCst->Value.getSExtValue();
1225 int64_t
F = FalseCst->Value.getSExtValue();
1227 if (
T == 0 &&
F == 1) {
1229 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1235 if (
T == 0 &&
F == -1) {
1237 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1245 int64_t
T = TrueCst->Value.getSExtValue();
1248 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1257 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1266 int64_t
F = FalseCst->Value.getSExtValue();
1269 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1276 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1284 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1285 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1287 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1289 return &*SelectInst;
1294 MachineRegisterInfo *MRI =
nullptr) {
1307 if (ValAndVReg && ValAndVReg->Value == 0)
1314 if (ValAndVReg && ValAndVReg->Value == 0)
1418 assert(
Reg.isValid() &&
"Expected valid register!");
1419 bool HasZext =
false;
1421 unsigned Opc =
MI->getOpcode();
1423 if (!
MI->getOperand(0).isReg() ||
1432 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1433 Opc == TargetOpcode::G_TRUNC) {
1434 if (
Opc == TargetOpcode::G_ZEXT)
1437 Register NextReg =
MI->getOperand(1).getReg();
1451 std::optional<uint64_t>
C;
1456 case TargetOpcode::G_AND:
1457 case TargetOpcode::G_XOR: {
1458 TestReg =
MI->getOperand(1).getReg();
1459 Register ConstantReg =
MI->getOperand(2).getReg();
1470 C = VRegAndVal->Value.getZExtValue();
1472 C = VRegAndVal->Value.getSExtValue();
1476 case TargetOpcode::G_ASHR:
1477 case TargetOpcode::G_LSHR:
1478 case TargetOpcode::G_SHL: {
1479 TestReg =
MI->getOperand(1).getReg();
1483 C = VRegAndVal->Value.getSExtValue();
1499 case TargetOpcode::G_AND:
1501 if ((*
C >> Bit) & 1)
1504 case TargetOpcode::G_SHL:
1507 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1512 case TargetOpcode::G_ASHR:
1517 if (Bit >= TestRegSize)
1518 Bit = TestRegSize - 1;
1520 case TargetOpcode::G_LSHR:
1522 if ((Bit + *
C) < TestRegSize) {
1527 case TargetOpcode::G_XOR:
1536 if ((*
C >> Bit) & 1)
1551MachineInstr *AArch64InstructionSelector::emitTestBit(
1552 Register TestReg, uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1553 MachineIRBuilder &MIB)
const {
1555 assert(ProduceNonFlagSettingCondBr &&
1556 "Cannot emit TB(N)Z with speculation tracking!");
1557 MachineRegisterInfo &MRI = *MIB.
getMRI();
1561 LLT Ty = MRI.
getType(TestReg);
1564 assert(Bit < 64 &&
"Bit is too large!");
1568 bool UseWReg =
Bit < 32;
1569 unsigned NecessarySize = UseWReg ? 32 : 64;
1570 if (
Size != NecessarySize)
1571 TestReg = moveScalarRegClass(
1572 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1575 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1576 {AArch64::TBZW, AArch64::TBNZW}};
1577 unsigned Opc = OpcTable[UseWReg][IsNegative];
1584bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1585 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1586 MachineIRBuilder &MIB)
const {
1587 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1614 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1621 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1625MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1627 MachineBasicBlock *DestMBB,
1628 MachineIRBuilder &MIB)
const {
1629 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1630 MachineRegisterInfo &MRI = *MIB.
getMRI();
1632 AArch64::GPRRegBankID &&
1633 "Expected GPRs only?");
1634 auto Ty = MRI.
getType(CompareReg);
1637 assert(Width <= 64 &&
"Expected width to be at most 64?");
1638 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1639 {AArch64::CBNZW, AArch64::CBNZX}};
1640 unsigned Opc = OpcTable[IsNegative][Width == 64];
1641 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1646bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1647 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1649 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1657 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1661 I.eraseFromParent();
1665bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1666 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1668 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1674 if (!ProduceNonFlagSettingCondBr)
1677 MachineRegisterInfo &MRI = *MIB.
getMRI();
1678 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1693 if (VRegAndVal && !AndInst) {
1694 int64_t
C = VRegAndVal->Value.getSExtValue();
1700 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1701 I.eraseFromParent();
1709 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1710 I.eraseFromParent();
1718 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1719 I.eraseFromParent();
1733 if (VRegAndVal && VRegAndVal->Value == 0) {
1741 tryOptAndIntoCompareBranch(
1743 I.eraseFromParent();
1749 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1751 I.eraseFromParent();
1760bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1761 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1763 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1764 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1768 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1775 I.eraseFromParent();
1779bool AArch64InstructionSelector::selectCompareBranch(
1780 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI) {
1781 Register CondReg =
I.getOperand(0).getReg();
1782 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1786 if (CCMIOpc == TargetOpcode::G_FCMP)
1787 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1788 if (CCMIOpc == TargetOpcode::G_ICMP)
1789 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1794 if (ProduceNonFlagSettingCondBr) {
1795 emitTestBit(CondReg, 0,
true,
1796 I.getOperand(1).getMBB(), MIB);
1797 I.eraseFromParent();
1807 .
addMBB(
I.getOperand(1).getMBB());
1808 I.eraseFromParent();
1828 return std::nullopt;
1830 int64_t Imm = *ShiftImm;
1832 return std::nullopt;
1833 switch (SrcTy.getElementType().getSizeInBits()) {
1836 return std::nullopt;
1839 return std::nullopt;
1843 return std::nullopt;
1847 return std::nullopt;
1851 return std::nullopt;
1857bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1858 MachineRegisterInfo &MRI) {
1859 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1860 Register DstReg =
I.getOperand(0).getReg();
1861 const LLT Ty = MRI.
getType(DstReg);
1862 Register Src1Reg =
I.getOperand(1).getReg();
1863 Register Src2Reg =
I.getOperand(2).getReg();
1874 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1876 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1878 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1880 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1882 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1884 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1886 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1898 I.eraseFromParent();
1902bool AArch64InstructionSelector::selectVectorAshrLshr(
1903 MachineInstr &
I, MachineRegisterInfo &MRI) {
1904 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1905 I.getOpcode() == TargetOpcode::G_LSHR);
1906 Register DstReg =
I.getOperand(0).getReg();
1907 const LLT Ty = MRI.
getType(DstReg);
1908 Register Src1Reg =
I.getOperand(1).getReg();
1909 Register Src2Reg =
I.getOperand(2).getReg();
1914 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1924 unsigned NegOpc = 0;
1925 const TargetRegisterClass *RC =
1926 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1928 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1929 NegOpc = AArch64::NEGv2i64;
1931 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1932 NegOpc = AArch64::NEGv4i32;
1934 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1935 NegOpc = AArch64::NEGv2i32;
1937 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1938 NegOpc = AArch64::NEGv4i16;
1940 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1941 NegOpc = AArch64::NEGv8i16;
1943 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1944 NegOpc = AArch64::NEGv16i8;
1946 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1947 NegOpc = AArch64::NEGv8i8;
1953 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1957 I.eraseFromParent();
1961bool AArch64InstructionSelector::selectVaStartAAPCS(
1962 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI)
const {
1971 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1973 const auto *PtrRegClass =
1974 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1976 const MCInstrDesc &MCIDAddAddr =
1978 const MCInstrDesc &MCIDStoreAddr =
1990 const auto VAList =
I.getOperand(0).getReg();
1993 unsigned OffsetBytes = 0;
1997 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1999 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
2006 const auto *MMO = *
I.memoperands_begin();
2007 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
2010 .
addImm(OffsetBytes / PtrSize)
2012 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2016 OffsetBytes += PtrSize;
2032 const auto PushIntConstant = [&](
const int32_t
Value) {
2033 constexpr int IntSize = 4;
2036 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
2041 const auto *MMO = *
I.memoperands_begin();
2042 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
2045 .
addImm(OffsetBytes / IntSize)
2047 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2050 OffsetBytes += IntSize;
2054 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2057 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2061 I.eraseFromParent();
2065bool AArch64InstructionSelector::selectVaStartDarwin(
2066 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI)
const {
2067 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2068 Register ListReg =
I.getOperand(0).getReg();
2073 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2081 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2089 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2096 I.eraseFromParent();
2100void AArch64InstructionSelector::materializeLargeCMVal(
2101 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2106 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2121 GV, MovZ->getOperand(1).getOffset(), Flags));
2125 MovZ->getOperand(1).getOffset(), Flags));
2131 Register DstReg = BuildMovK(MovZ.getReg(0),
2137bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2142 switch (
I.getOpcode()) {
2143 case TargetOpcode::G_CONSTANT: {
2144 Register DefReg =
I.getOperand(0).getReg();
2145 const LLT DefTy = MRI.
getType(DefReg);
2149 if (PtrSize != 32 && PtrSize != 64)
2155 case TargetOpcode::G_STORE: {
2156 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2157 MachineOperand &SrcOp =
I.getOperand(0);
2170 case TargetOpcode::G_PTR_ADD: {
2174 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2176 return convertPtrAddToAdd(
I, MRI);
2178 case TargetOpcode::G_LOAD: {
2183 Register DstReg =
I.getOperand(0).getReg();
2184 const LLT DstTy = MRI.
getType(DstReg);
2190 case AArch64::G_DUP: {
2192 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2196 MRI.
setType(
I.getOperand(0).getReg(),
2198 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2199 I.getOperand(1).setReg(NewSrc.getReg(0));
2202 case AArch64::G_INSERT_VECTOR_ELT: {
2203 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2204 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2208 MRI.
setType(
I.getOperand(1).getReg(),
2210 MRI.
setType(
I.getOperand(0).getReg(),
2212 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2213 I.getOperand(2).setReg(NewSrc.getReg(0));
2217 Register EltReg =
I.getOperand(2).getReg();
2218 LLT EltTy = MRI.
getType(EltReg);
2224 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2225 I.getOperand(2).setReg(NewElt.getReg(0));
2230 case TargetOpcode::G_UITOFP:
2231 case TargetOpcode::G_SITOFP: {
2236 Register SrcReg =
I.getOperand(1).getReg();
2237 LLT SrcTy = MRI.
getType(SrcReg);
2238 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2247 I.getOperand(1).setReg(
Copy.getReg(0));
2249 getRegClassForTypeOnBank(
2250 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2252 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2253 I.setDesc(
TII.get(AArch64::G_SITOF));
2255 I.setDesc(
TII.get(AArch64::G_UITOF));
2273bool AArch64InstructionSelector::convertPtrAddToAdd(
2274 MachineInstr &
I, MachineRegisterInfo &MRI) {
2275 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2276 Register DstReg =
I.getOperand(0).getReg();
2277 Register AddOp1Reg =
I.getOperand(1).getReg();
2278 const LLT PtrTy = MRI.
getType(DstReg);
2282 const LLT CastPtrTy = PtrTy.
isVector()
2294 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2295 MRI.
setType(DstReg, CastPtrTy);
2296 I.getOperand(1).setReg(PtrToInt.getReg(0));
2297 if (!select(*PtrToInt)) {
2298 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2307 I.getOperand(2).setReg(NegatedReg);
2308 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2312bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2313 MachineRegisterInfo &MRI) {
2317 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2318 const auto &MO =
I.getOperand(2);
2323 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2327 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2328 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2330 if (!Imm1Fn || !Imm2Fn)
2334 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2335 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2337 for (
auto &RenderFn : *Imm1Fn)
2339 for (
auto &RenderFn : *Imm2Fn)
2342 I.eraseFromParent();
2347bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2348 MachineInstr &
I, MachineRegisterInfo &MRI) {
2349 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2367 LLT DefDstTy = MRI.
getType(DefDstReg);
2368 Register StoreSrcReg =
I.getOperand(0).getReg();
2369 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2385 I.getOperand(0).setReg(DefDstReg);
2389bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2390 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2391 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2397 switch (
I.getOpcode()) {
2398 case AArch64::G_DUP: {
2401 Register Src =
I.getOperand(1).getReg();
2403 Src, MRI,
true,
true);
2407 Register Dst =
I.getOperand(0).getReg();
2413 if (!emitConstantVector(Dst, CV, MIB, MRI))
2415 I.eraseFromParent();
2418 case TargetOpcode::G_SEXT:
2421 if (selectUSMovFromExtend(
I, MRI))
2424 case TargetOpcode::G_BR:
2426 case TargetOpcode::G_SHL:
2427 return earlySelectSHL(
I, MRI);
2428 case TargetOpcode::G_CONSTANT: {
2429 bool IsZero =
false;
2430 if (
I.getOperand(1).isCImm())
2431 IsZero =
I.getOperand(1).getCImm()->isZero();
2432 else if (
I.getOperand(1).isImm())
2433 IsZero =
I.getOperand(1).getImm() == 0;
2438 Register DefReg =
I.getOperand(0).getReg();
2441 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2444 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2449 I.setDesc(
TII.get(TargetOpcode::COPY));
2453 case TargetOpcode::G_ADD: {
2462 Register AddDst =
I.getOperand(0).getReg();
2463 Register AddLHS =
I.getOperand(1).getReg();
2464 Register AddRHS =
I.getOperand(2).getReg();
2474 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2495 MachineInstr *
Cmp = MatchCmp(AddRHS);
2499 Cmp = MatchCmp(AddRHS);
2503 auto &PredOp =
Cmp->getOperand(1);
2505 emitIntegerCompare(
Cmp->getOperand(2),
2506 Cmp->getOperand(3), PredOp, MIB);
2510 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2511 I.eraseFromParent();
2514 case TargetOpcode::G_OR: {
2518 Register Dst =
I.getOperand(0).getReg();
2538 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2541 int64_t Immr =
Size - ShiftImm;
2542 int64_t Imms =
Size - ShiftImm - 1;
2543 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2544 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2545 I.eraseFromParent();
2548 case TargetOpcode::G_FENCE: {
2549 if (
I.getOperand(1).getImm() == 0)
2553 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2554 I.eraseFromParent();
2562bool AArch64InstructionSelector::select(MachineInstr &
I) {
2563 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2564 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2570 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2571 if (Subtarget->requiresStrictAlign()) {
2573 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2579 unsigned Opcode =
I.getOpcode();
2581 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2584 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2589 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2590 const Register DefReg =
I.getOperand(0).getReg();
2591 const LLT DefTy = MRI.
getType(DefReg);
2596 const TargetRegisterClass *DefRC =
2604 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2611 I.setDesc(
TII.get(TargetOpcode::PHI));
2619 if (
I.isDebugInstr())
2626 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2628 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2635 if (preISelLower(
I)) {
2636 Opcode =
I.getOpcode();
2647 if (selectImpl(
I, *CoverageInfo))
2651 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2654 case TargetOpcode::G_SBFX:
2655 case TargetOpcode::G_UBFX: {
2656 static const unsigned OpcTable[2][2] = {
2657 {AArch64::UBFMWri, AArch64::UBFMXri},
2658 {AArch64::SBFMWri, AArch64::SBFMXri}};
2659 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2661 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2664 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2667 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2668 auto LSB = Cst1->Value.getZExtValue();
2669 auto Width = Cst2->Value.getZExtValue();
2673 .
addImm(LSB + Width - 1);
2674 I.eraseFromParent();
2678 case TargetOpcode::G_BRCOND:
2679 return selectCompareBranch(
I, MF, MRI);
2681 case TargetOpcode::G_BRINDIRECT: {
2683 if (std::optional<uint16_t> BADisc =
2685 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2688 MI.addReg(AArch64::XZR);
2689 I.eraseFromParent();
2693 I.setDesc(
TII.get(AArch64::BR));
2698 case TargetOpcode::G_BRJT:
2699 return selectBrJT(
I, MRI);
2701 case AArch64::G_ADD_LOW: {
2706 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2707 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2708 I.setDesc(
TII.get(AArch64::ADDXri));
2714 "Expected small code model");
2716 auto Op2 =
I.getOperand(2);
2717 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2718 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2719 Op1.getTargetFlags())
2721 Op2.getTargetFlags());
2722 I.eraseFromParent();
2727 case TargetOpcode::G_FCONSTANT: {
2728 const Register DefReg =
I.getOperand(0).getReg();
2729 const LLT DefTy = MRI.
getType(DefReg);
2733 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2740 bool OptForSize = shouldOptForSize(&MF);
2744 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2751 auto *FPImm =
I.getOperand(1).getFPImm();
2754 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2757 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2758 I.eraseFromParent();
2763 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2766 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2767 MachineOperand &RegOp =
I.getOperand(0);
2773 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2777 MachineOperand &ImmOp =
I.getOperand(1);
2781 const unsigned MovOpc =
2782 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2783 I.setDesc(
TII.get(MovOpc));
2787 case TargetOpcode::G_EXTRACT: {
2788 Register DstReg =
I.getOperand(0).getReg();
2789 Register SrcReg =
I.getOperand(1).getReg();
2790 LLT SrcTy = MRI.
getType(SrcReg);
2791 LLT DstTy = MRI.
getType(DstReg);
2803 unsigned Offset =
I.getOperand(2).getImm();
2808 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2809 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2812 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2814 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2816 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2818 AArch64::GPR64RegClass, NewI->getOperand(0));
2819 I.eraseFromParent();
2825 unsigned LaneIdx =
Offset / 64;
2826 MachineInstr *Extract = emitExtractVectorElt(
2827 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2830 I.eraseFromParent();
2834 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2835 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2840 "unexpected G_EXTRACT types");
2847 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2848 .addReg(DstReg, {}, AArch64::sub_32);
2850 AArch64::GPR32RegClass, MRI);
2851 I.getOperand(0).setReg(DstReg);
2857 case TargetOpcode::G_INSERT: {
2858 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2859 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2866 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2867 unsigned LSB =
I.getOperand(3).getImm();
2869 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2870 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2874 "unexpected G_INSERT types");
2881 TII.get(AArch64::SUBREG_TO_REG))
2883 .
addUse(
I.getOperand(2).getReg())
2884 .
addImm(AArch64::sub_32);
2886 AArch64::GPR32RegClass, MRI);
2887 I.getOperand(2).setReg(SrcReg);
2892 case TargetOpcode::G_FRAME_INDEX: {
2899 I.setDesc(
TII.get(AArch64::ADDXri));
2909 case TargetOpcode::G_GLOBAL_VALUE: {
2910 const GlobalValue *GV =
nullptr;
2912 if (
I.getOperand(1).isSymbol()) {
2913 OpFlags =
I.getOperand(1).getTargetFlags();
2922 return selectTLSGlobalValue(
I, MRI);
2928 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2929 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2930 I.getOperand(1).setTargetFlags(OpFlags);
2931 I.addImplicitDefUseOperands(MF);
2935 materializeLargeCMVal(
I, GV, OpFlags);
2936 I.eraseFromParent();
2939 I.setDesc(
TII.get(AArch64::ADR));
2940 I.getOperand(1).setTargetFlags(OpFlags);
2942 I.setDesc(
TII.get(AArch64::MOVaddr));
2944 MachineInstrBuilder MIB(MF,
I);
2945 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2952 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2953 return selectPtrAuthGlobalValue(
I, MRI);
2955 case TargetOpcode::G_ZEXTLOAD:
2956 case TargetOpcode::G_LOAD:
2957 case TargetOpcode::G_STORE: {
2959 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2974 assert(MemSizeInBytes <= 8 &&
2975 "128-bit atomics should already be custom-legalized");
2978 static constexpr unsigned LDAPROpcodes[] = {
2979 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2980 static constexpr unsigned LDAROpcodes[] = {
2981 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2982 ArrayRef<unsigned> Opcodes =
2983 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2986 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2988 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2989 AArch64::STLRW, AArch64::STLRX};
2994 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2995 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2996 I.getOperand(0).setReg(NewVal);
2998 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
3006 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
3009 "Load/Store pointer operand isn't a GPR");
3011 "Load/Store pointer operand isn't a pointer");
3016 LLT ValTy = MRI.
getType(ValReg);
3023 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3029 .addReg(ValReg, {}, SubReg)
3036 if (RB.
getID() == AArch64::FPRRegBankID) {
3039 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3049 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3052 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3061 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3063 const unsigned NewOpc =
3065 if (NewOpc ==
I.getOpcode())
3069 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3072 I.setDesc(
TII.get(NewOpc));
3078 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3079 Register CurValReg =
I.getOperand(0).getReg();
3080 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3081 NewInst.cloneMemRefs(
I);
3082 for (
auto &Fn : *AddrModeFns)
3084 I.eraseFromParent();
3088 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3093 if (Opcode == TargetOpcode::G_STORE) {
3095 LoadStore->getOperand(0).getReg(), MRI);
3096 if (CVal && CVal->Value == 0) {
3098 case AArch64::STRWui:
3099 case AArch64::STRHHui:
3100 case AArch64::STRBBui:
3101 LoadStore->getOperand(0).setReg(AArch64::WZR);
3103 case AArch64::STRXui:
3104 LoadStore->getOperand(0).setReg(AArch64::XZR);
3110 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3111 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3123 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3125 .
addImm(AArch64::sub_32);
3134 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3135 case TargetOpcode::G_INDEXED_SEXTLOAD:
3136 return selectIndexedExtLoad(
I, MRI);
3137 case TargetOpcode::G_INDEXED_LOAD:
3138 return selectIndexedLoad(
I, MRI);
3139 case TargetOpcode::G_INDEXED_STORE:
3142 case TargetOpcode::G_LSHR:
3143 case TargetOpcode::G_ASHR:
3145 return selectVectorAshrLshr(
I, MRI);
3147 case TargetOpcode::G_SHL:
3148 if (Opcode == TargetOpcode::G_SHL &&
3150 return selectVectorSHL(
I, MRI);
3157 Register SrcReg =
I.getOperand(1).getReg();
3158 Register ShiftReg =
I.getOperand(2).getReg();
3159 const LLT ShiftTy = MRI.
getType(ShiftReg);
3160 const LLT SrcTy = MRI.
getType(SrcReg);
3165 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3166 .addReg(ShiftReg, {}, AArch64::sub_32);
3168 I.getOperand(2).setReg(Trunc.getReg(0));
3172 case TargetOpcode::G_OR: {
3179 const Register DefReg =
I.getOperand(0).getReg();
3183 if (NewOpc ==
I.getOpcode())
3186 I.setDesc(
TII.get(NewOpc));
3195 case TargetOpcode::G_PTR_ADD: {
3196 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3197 I.eraseFromParent();
3201 case TargetOpcode::G_SADDE:
3202 case TargetOpcode::G_UADDE:
3203 case TargetOpcode::G_SSUBE:
3204 case TargetOpcode::G_USUBE:
3205 case TargetOpcode::G_SADDO:
3206 case TargetOpcode::G_UADDO:
3207 case TargetOpcode::G_SSUBO:
3208 case TargetOpcode::G_USUBO:
3209 return selectOverflowOp(
I, MRI);
3211 case TargetOpcode::G_PTRMASK: {
3212 Register MaskReg =
I.getOperand(2).getReg();
3218 uint64_t
Mask = *MaskVal;
3219 I.setDesc(
TII.get(AArch64::ANDXri));
3220 I.getOperand(2).ChangeToImmediate(
3226 case TargetOpcode::G_PTRTOINT:
3227 case TargetOpcode::G_TRUNC: {
3228 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3229 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3231 const Register DstReg =
I.getOperand(0).getReg();
3232 const Register SrcReg =
I.getOperand(1).getReg();
3234 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3235 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3239 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3243 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3244 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3248 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3254 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3258 if (DstRC == SrcRC) {
3260 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3264 }
else if (DstRC == &AArch64::GPR32RegClass &&
3265 SrcRC == &AArch64::GPR64RegClass) {
3266 I.getOperand(1).setSubReg(AArch64::sub_32);
3269 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3273 I.setDesc(
TII.get(TargetOpcode::COPY));
3275 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3278 I.setDesc(
TII.get(AArch64::XTNv4i16));
3284 MachineInstr *Extract = emitExtractVectorElt(
3288 I.eraseFromParent();
3293 if (Opcode == TargetOpcode::G_PTRTOINT) {
3294 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3295 I.setDesc(
TII.get(TargetOpcode::COPY));
3303 case TargetOpcode::G_ANYEXT: {
3304 if (selectUSMovFromExtend(
I, MRI))
3307 const Register DstReg =
I.getOperand(0).getReg();
3308 const Register SrcReg =
I.getOperand(1).getReg();
3310 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3311 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3313 <<
", expected: GPR\n");
3317 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3318 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3320 <<
", expected: GPR\n");
3327 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3331 if (DstSize != 64 && DstSize > 32) {
3333 <<
", expected: 32 or 64\n");
3343 .
addImm(AArch64::sub_32);
3344 I.getOperand(1).setReg(ExtSrc);
3349 case TargetOpcode::G_ZEXT:
3350 case TargetOpcode::G_SEXT_INREG:
3351 case TargetOpcode::G_SEXT: {
3352 if (selectUSMovFromExtend(
I, MRI))
3355 unsigned Opcode =
I.getOpcode();
3356 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3357 const Register DefReg =
I.getOperand(0).getReg();
3358 Register SrcReg =
I.getOperand(1).getReg();
3359 const LLT DstTy = MRI.
getType(DefReg);
3360 const LLT SrcTy = MRI.
getType(SrcReg);
3366 if (Opcode == TargetOpcode::G_SEXT_INREG)
3367 SrcSize =
I.getOperand(2).getImm();
3373 AArch64::GPRRegBankID &&
3374 "Unexpected ext regbank");
3385 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3388 if (LoadMI && IsGPR) {
3389 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3390 unsigned BytesLoaded = MemOp->getSize().getValue();
3397 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3400 const Register ZReg = AArch64::WZR;
3401 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3404 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3405 .addUse(SubregToRegSrc)
3406 .
addImm(AArch64::sub_32);
3410 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3420 I.eraseFromParent();
3425 if (DstSize == 64) {
3426 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3434 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3435 {&AArch64::GPR64RegClass}, {})
3441 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3445 }
else if (DstSize <= 32) {
3446 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3455 I.eraseFromParent();
3459 case TargetOpcode::G_FREEZE:
3462 case TargetOpcode::G_INTTOPTR:
3467 case TargetOpcode::G_BITCAST:
3475 case TargetOpcode::G_SELECT: {
3477 const Register CondReg = Sel.getCondReg();
3479 const Register FReg = Sel.getFalseReg();
3481 if (tryOptSelect(Sel))
3487 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3492 Sel.eraseFromParent();
3495 case TargetOpcode::G_ICMP: {
3505 auto &PredOp =
I.getOperand(1);
3506 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3510 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3511 AArch64::WZR, InvCC, MIB);
3512 I.eraseFromParent();
3516 case TargetOpcode::G_FCMP: {
3519 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3521 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3523 I.eraseFromParent();
3526 case TargetOpcode::G_VASTART:
3528 : selectVaStartAAPCS(
I, MF, MRI);
3529 case TargetOpcode::G_INTRINSIC:
3530 return selectIntrinsic(
I, MRI);
3531 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3532 return selectIntrinsicWithSideEffects(
I, MRI);
3533 case TargetOpcode::G_IMPLICIT_DEF: {
3534 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3535 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3536 const Register DstReg =
I.getOperand(0).getReg();
3537 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3538 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3542 case TargetOpcode::G_BLOCK_ADDR: {
3543 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3544 if (std::optional<uint16_t> BADisc =
3546 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3547 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3556 AArch64::GPR64RegClass, MRI);
3557 I.eraseFromParent();
3561 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3562 I.eraseFromParent();
3565 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3566 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3567 I.getOperand(0).getReg())
3571 I.getOperand(1).getBlockAddress(), 0,
3573 I.eraseFromParent();
3578 case AArch64::G_DUP: {
3585 AArch64::GPRRegBankID)
3587 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3589 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3591 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3593 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3595 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3601 case TargetOpcode::G_BUILD_VECTOR:
3602 return selectBuildVector(
I, MRI);
3603 case TargetOpcode::G_MERGE_VALUES:
3605 case TargetOpcode::G_UNMERGE_VALUES:
3607 case TargetOpcode::G_SHUFFLE_VECTOR:
3608 return selectShuffleVector(
I, MRI);
3609 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3610 return selectExtractElt(
I, MRI);
3611 case TargetOpcode::G_CONCAT_VECTORS:
3612 return selectConcatVectors(
I, MRI);
3613 case TargetOpcode::G_JUMP_TABLE:
3614 return selectJumpTable(
I, MRI);
3615 case TargetOpcode::G_MEMCPY:
3616 case TargetOpcode::G_MEMCPY_INLINE:
3617 case TargetOpcode::G_MEMMOVE:
3618 case TargetOpcode::G_MEMSET:
3619 case TargetOpcode::G_MEMSET_INLINE:
3620 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3621 return selectMOPS(
I, MRI);
3627bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3628 MachineIRBuilderState OldMIBState = MIB.
getState();
3634bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3635 MachineRegisterInfo &MRI) {
3638 case TargetOpcode::G_MEMCPY:
3639 case TargetOpcode::G_MEMCPY_INLINE:
3640 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3642 case TargetOpcode::G_MEMMOVE:
3643 Mopcode = AArch64::MOPSMemoryMovePseudo;
3645 case TargetOpcode::G_MEMSET:
3646 case TargetOpcode::G_MEMSET_INLINE:
3648 Mopcode = AArch64::MOPSMemorySetPseudo;
3661 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3662 const auto &SrcValRegClass =
3663 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3681 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3682 {DstPtrCopy, SizeCopy, SrcValCopy});
3685 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3686 {DstPtrCopy, SrcValCopy, SizeCopy});
3693bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3694 MachineRegisterInfo &MRI) {
3695 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3696 Register JTAddr =
I.getOperand(0).getReg();
3697 unsigned JTI =
I.getOperand(1).getIndex();
3700 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3712 "jump table hardening only supported on MachO/ELF");
3720 I.eraseFromParent();
3727 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3728 {TargetReg, ScratchReg}, {JTAddr,
Index})
3729 .addJumpTableIndex(JTI);
3731 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3732 {
static_cast<int64_t
>(JTI)});
3734 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3735 I.eraseFromParent();
3740bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3741 MachineRegisterInfo &MRI) {
3742 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3743 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3745 Register DstReg =
I.getOperand(0).getReg();
3746 unsigned JTI =
I.getOperand(1).getIndex();
3749 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3752 I.eraseFromParent();
3757bool AArch64InstructionSelector::selectTLSGlobalValue(
3758 MachineInstr &
I, MachineRegisterInfo &MRI) {
3761 MachineFunction &MF = *
I.getParent()->getParent();
3764 const auto &GlobalOp =
I.getOperand(1);
3765 assert(GlobalOp.getOffset() == 0 &&
3766 "Shouldn't have an offset on TLS globals!");
3767 const GlobalValue &GV = *GlobalOp.getGlobal();
3770 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3773 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3774 {LoadGOT.getReg(0)})
3785 assert(Opcode == AArch64::BLR);
3786 Opcode = AArch64::BLRAAZ;
3790 .addUse(AArch64::X0, RegState::Implicit)
3791 .
addDef(AArch64::X0, RegState::Implicit)
3797 I.eraseFromParent();
3801MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3802 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3803 MachineIRBuilder &MIRBuilder)
const {
3804 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3806 auto BuildFn = [&](
unsigned SubregIndex) {
3810 .addImm(SubregIndex);
3818 return BuildFn(AArch64::bsub);
3820 return BuildFn(AArch64::hsub);
3822 return BuildFn(AArch64::ssub);
3824 return BuildFn(AArch64::dsub);
3831AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3832 MachineIRBuilder &MIB,
3833 MachineRegisterInfo &MRI)
const {
3834 LLT DstTy = MRI.
getType(DstReg);
3835 const TargetRegisterClass *RC =
3836 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3837 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3841 unsigned SubReg = 0;
3844 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3850 .addReg(SrcReg, {}, SubReg);
3855bool AArch64InstructionSelector::selectMergeValues(
3856 MachineInstr &
I, MachineRegisterInfo &MRI) {
3857 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3858 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3859 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3861 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3863 if (
I.getNumOperands() != 3)
3870 Register DstReg =
I.getOperand(0).getReg();
3871 Register Src1Reg =
I.getOperand(1).getReg();
3872 Register Src2Reg =
I.getOperand(2).getReg();
3873 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3874 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3878 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3879 Src2Reg, 1, RB, MIB);
3884 I.eraseFromParent();
3888 if (RB.
getID() != AArch64::GPRRegBankID)
3894 auto *DstRC = &AArch64::GPR64RegClass;
3896 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3897 TII.get(TargetOpcode::SUBREG_TO_REG))
3899 .
addUse(
I.getOperand(1).getReg())
3900 .
addImm(AArch64::sub_32);
3903 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3904 TII.get(TargetOpcode::SUBREG_TO_REG))
3906 .
addUse(
I.getOperand(2).getReg())
3907 .
addImm(AArch64::sub_32);
3909 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3910 .
addDef(
I.getOperand(0).getReg())
3918 I.eraseFromParent();
3923 const unsigned EltSize) {
3928 CopyOpc = AArch64::DUPi8;
3929 ExtractSubReg = AArch64::bsub;
3932 CopyOpc = AArch64::DUPi16;
3933 ExtractSubReg = AArch64::hsub;
3936 CopyOpc = AArch64::DUPi32;
3937 ExtractSubReg = AArch64::ssub;
3940 CopyOpc = AArch64::DUPi64;
3941 ExtractSubReg = AArch64::dsub;
3945 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3951MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3952 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3953 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3954 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3955 unsigned CopyOpc = 0;
3956 unsigned ExtractSubReg = 0;
3959 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3963 const TargetRegisterClass *DstRC =
3964 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3966 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3970 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3971 const LLT &VecTy = MRI.
getType(VecReg);
3972 const TargetRegisterClass *VecRC =
3973 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3975 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3985 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3986 .addReg(VecReg, {}, ExtractSubReg);
3995 MachineInstr *ScalarToVector = emitScalarToVector(
3996 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3997 if (!ScalarToVector)
4002 MachineInstr *LaneCopyMI =
4003 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4011bool AArch64InstructionSelector::selectExtractElt(
4012 MachineInstr &
I, MachineRegisterInfo &MRI) {
4013 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4014 "unexpected opcode!");
4015 Register DstReg =
I.getOperand(0).getReg();
4016 const LLT NarrowTy = MRI.
getType(DstReg);
4017 const Register SrcReg =
I.getOperand(1).getReg();
4018 const LLT WideTy = MRI.
getType(SrcReg);
4021 "source register size too small!");
4022 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4025 MachineOperand &LaneIdxOp =
I.getOperand(2);
4026 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4037 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4040 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4041 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4046 I.eraseFromParent();
4050bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4051 MachineInstr &
I, MachineRegisterInfo &MRI) {
4052 unsigned NumElts =
I.getNumOperands() - 1;
4053 Register SrcReg =
I.getOperand(NumElts).getReg();
4054 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4055 const LLT SrcTy = MRI.
getType(SrcReg);
4057 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4059 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4065 const RegisterBank &DstRB =
4069 MachineInstr *Extract =
4070 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4074 I.eraseFromParent();
4078bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4079 MachineRegisterInfo &MRI) {
4080 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4081 "unexpected opcode");
4085 AArch64::FPRRegBankID ||
4087 AArch64::FPRRegBankID) {
4088 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4089 "currently unsupported.\n");
4095 unsigned NumElts =
I.getNumOperands() - 1;
4096 Register SrcReg =
I.getOperand(NumElts).getReg();
4097 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4098 const LLT WideTy = MRI.
getType(SrcReg);
4101 "source register size too small!");
4104 return selectSplitVectorUnmerge(
I, MRI);
4108 unsigned CopyOpc = 0;
4109 unsigned ExtractSubReg = 0;
4120 unsigned NumInsertRegs = NumElts - 1;
4133 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4135 unsigned SubReg = 0;
4138 assert(Found &&
"expected to find last operand's subeg idx");
4139 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4141 MachineInstr &ImpDefMI =
4142 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4147 MachineInstr &InsMI =
4149 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4166 Register CopyTo =
I.getOperand(0).getReg();
4167 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4168 .addReg(InsertRegs[0], {}, ExtractSubReg);
4172 unsigned LaneIdx = 1;
4173 for (
Register InsReg : InsertRegs) {
4174 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4175 MachineInstr &CopyInst =
4186 const TargetRegisterClass *RC =
4194 I.eraseFromParent();
4198bool AArch64InstructionSelector::selectConcatVectors(
4199 MachineInstr &
I, MachineRegisterInfo &MRI) {
4200 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4201 "Unexpected opcode");
4202 Register Dst =
I.getOperand(0).getReg();
4203 Register Op1 =
I.getOperand(1).getReg();
4204 Register Op2 =
I.getOperand(2).getReg();
4205 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4208 I.eraseFromParent();
4213AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4214 MachineFunction &MF)
const {
4222MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4223 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4224 const TargetRegisterClass *RC;
4230 RC = &AArch64::FPR128RegClass;
4231 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4234 RC = &AArch64::FPR64RegClass;
4235 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4238 RC = &AArch64::FPR32RegClass;
4239 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4242 RC = &AArch64::FPR16RegClass;
4243 Opc = AArch64::LDRHui;
4246 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4251 MachineInstr *LoadMI =
nullptr;
4252 auto &MF = MIRBuilder.
getMF();
4253 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4254 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4256 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4259 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4263 .addConstantPoolIndex(
4279static std::pair<unsigned, unsigned>
4281 unsigned Opc, SubregIdx;
4282 if (RB.
getID() == AArch64::GPRRegBankID) {
4284 Opc = AArch64::INSvi8gpr;
4285 SubregIdx = AArch64::bsub;
4286 }
else if (EltSize == 16) {
4287 Opc = AArch64::INSvi16gpr;
4288 SubregIdx = AArch64::ssub;
4289 }
else if (EltSize == 32) {
4290 Opc = AArch64::INSvi32gpr;
4291 SubregIdx = AArch64::ssub;
4292 }
else if (EltSize == 64) {
4293 Opc = AArch64::INSvi64gpr;
4294 SubregIdx = AArch64::dsub;
4300 Opc = AArch64::INSvi8lane;
4301 SubregIdx = AArch64::bsub;
4302 }
else if (EltSize == 16) {
4303 Opc = AArch64::INSvi16lane;
4304 SubregIdx = AArch64::hsub;
4305 }
else if (EltSize == 32) {
4306 Opc = AArch64::INSvi32lane;
4307 SubregIdx = AArch64::ssub;
4308 }
else if (EltSize == 64) {
4309 Opc = AArch64::INSvi64lane;
4310 SubregIdx = AArch64::dsub;
4315 return std::make_pair(
Opc, SubregIdx);
4318MachineInstr *AArch64InstructionSelector::emitInstr(
4319 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4320 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4321 const ComplexRendererFns &RenderFns)
const {
4322 assert(Opcode &&
"Expected an opcode?");
4324 "Function should only be used to produce selected instructions!");
4325 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4327 for (
auto &Fn : *RenderFns)
4333MachineInstr *AArch64InstructionSelector::emitAddSub(
4334 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4336 MachineIRBuilder &MIRBuilder)
const {
4338 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4342 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4343 bool Is32Bit =
Size == 32;
4346 if (
auto Fns = selectArithImmed(
RHS))
4347 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4351 if (
auto Fns = selectNegArithImmed(
RHS))
4352 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4356 if (
auto Fns = selectArithExtendedRegister(
RHS))
4357 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4361 if (
auto Fns = selectShiftedRegister(
RHS))
4362 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4364 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4369AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4370 MachineOperand &
RHS,
4371 MachineIRBuilder &MIRBuilder)
const {
4372 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4373 {{AArch64::ADDXri, AArch64::ADDWri},
4374 {AArch64::ADDXrs, AArch64::ADDWrs},
4375 {AArch64::ADDXrr, AArch64::ADDWrr},
4376 {AArch64::SUBXri, AArch64::SUBWri},
4377 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4378 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4382AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4383 MachineOperand &
RHS,
4384 MachineIRBuilder &MIRBuilder)
const {
4385 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4386 {{AArch64::ADDSXri, AArch64::ADDSWri},
4387 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4388 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4389 {AArch64::SUBSXri, AArch64::SUBSWri},
4390 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4391 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4395AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4396 MachineOperand &
RHS,
4397 MachineIRBuilder &MIRBuilder)
const {
4398 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4399 {{AArch64::SUBSXri, AArch64::SUBSWri},
4400 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4401 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4402 {AArch64::ADDSXri, AArch64::ADDSWri},
4403 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4404 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4408AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4409 MachineOperand &
RHS,
4410 MachineIRBuilder &MIRBuilder)
const {
4411 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4412 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4414 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4415 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4419AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4420 MachineOperand &
RHS,
4421 MachineIRBuilder &MIRBuilder)
const {
4422 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4423 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4425 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4426 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4430AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4431 MachineIRBuilder &MIRBuilder)
const {
4434 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4439AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4440 MachineIRBuilder &MIRBuilder)
const {
4443 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4448AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4449 MachineIRBuilder &MIRBuilder)
const {
4450 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4454 bool Is32Bit = (
RegSize == 32);
4455 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4456 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4457 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4461 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4464 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4471 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4472 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4473 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4476MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4477 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4478 MachineIRBuilder &MIRBuilder)
const {
4479 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4486 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4488 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4490 return emitCMP(
LHS,
RHS, MIRBuilder);
4493MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4495 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4499 "Expected a 32-bit scalar register?");
4501 const Register ZReg = AArch64::WZR;
4506 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4508 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4512 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4513 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4514 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4519MachineInstr *AArch64InstructionSelector::emitFPCompare(
4521 std::optional<CmpInst::Predicate> Pred)
const {
4522 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4527 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4538 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4542 ShouldUseImm =
true;
4546 unsigned CmpOpcTbl[2][3] = {
4547 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4548 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4550 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4562MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4564 MachineIRBuilder &MIRBuilder)
const {
4571 const LLT Op1Ty = MRI.
getType(Op1);
4572 const LLT Op2Ty = MRI.
getType(Op2);
4574 if (Op1Ty != Op2Ty) {
4575 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4578 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4581 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4592 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4593 const TargetRegisterClass *DstRC =
4596 MachineInstr *WidenedOp1 =
4597 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4598 MachineInstr *WidenedOp2 =
4599 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4600 if (!WidenedOp1 || !WidenedOp2) {
4601 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4606 unsigned InsertOpc, InsSubRegIdx;
4607 std::tie(InsertOpc, InsSubRegIdx) =
4625 MachineIRBuilder &MIRBuilder)
const {
4626 auto &MRI = *MIRBuilder.
getMRI();
4632 Size =
TRI.getRegSizeInBits(*RC);
4636 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4637 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4638 unsigned Opc = OpcTable[
Size == 64];
4639 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4644MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4646 MachineRegisterInfo *MRI = MIB.
getMRI();
4647 unsigned Opcode =
I.getOpcode();
4651 bool NeedsNegatedCarry =
4652 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4661 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4662 if (SrcMI ==
I.getPrevNode()) {
4664 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4665 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4666 CarrySrcMI->isUnsigned() &&
4667 CarrySrcMI->getCarryOutReg() == CarryReg &&
4668 selectAndRestoreState(*SrcMI))
4675 if (NeedsNegatedCarry) {
4678 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4682 auto Fns = select12BitValueWithLeftShift(1);
4683 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4686bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4687 MachineRegisterInfo &MRI) {
4692 emitCarryIn(
I, CarryInMI->getCarryInReg());
4696 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4697 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4699 Register CarryOutReg = CarryMI.getCarryOutReg();
4708 emitCSINC(CarryOutReg, ZReg, ZReg,
4709 getInvertedCondCode(OpAndCC.second), MIB);
4712 I.eraseFromParent();
4716std::pair<MachineInstr *, AArch64CC::CondCode>
4717AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4718 MachineOperand &
LHS,
4719 MachineOperand &
RHS,
4720 MachineIRBuilder &MIRBuilder)
const {
4724 case TargetOpcode::G_SADDO:
4726 case TargetOpcode::G_UADDO:
4728 case TargetOpcode::G_SSUBO:
4730 case TargetOpcode::G_USUBO:
4732 case TargetOpcode::G_SADDE:
4734 case TargetOpcode::G_UADDE:
4736 case TargetOpcode::G_SSUBE:
4738 case TargetOpcode::G_USUBE:
4759 unsigned Depth = 0) {
4766 MustBeFirst =
false;
4772 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4773 bool IsOR = Opcode == TargetOpcode::G_OR;
4785 if (MustBeFirstL && MustBeFirstR)
4791 if (!CanNegateL && !CanNegateR)
4795 CanNegate = WillNegate && CanNegateL && CanNegateR;
4798 MustBeFirst = !CanNegate;
4800 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4803 MustBeFirst = MustBeFirstL || MustBeFirstR;
4810MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4813 MachineIRBuilder &MIB)
const {
4814 auto &MRI = *MIB.
getMRI();
4817 std::optional<ValueAndVReg>
C;
4821 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4822 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4823 else if (
C->Value.ule(31))
4824 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4826 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4832 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4833 CCmpOpc = AArch64::FCCMPHrr;
4836 CCmpOpc = AArch64::FCCMPSrr;
4839 CCmpOpc = AArch64::FCCMPDrr;
4849 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4850 CCmp.
addImm(
C->Value.getZExtValue());
4851 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4852 CCmp.
addImm(
C->Value.abs().getZExtValue());
4860MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4864 auto &MRI = *MIB.
getMRI();
4882 MachineInstr *ExtraCmp;
4884 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4896 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4897 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4898 Cmp->getOperand(3).getReg(), MIB);
4905 bool IsOR = Opcode == TargetOpcode::G_OR;
4911 assert(ValidL &&
"Valid conjunction/disjunction tree");
4918 assert(ValidR &&
"Valid conjunction/disjunction tree");
4923 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4932 bool NegateAfterAll;
4933 if (Opcode == TargetOpcode::G_OR) {
4936 assert(CanNegateR &&
"at least one side must be negatable");
4937 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4941 NegateAfterR =
true;
4944 NegateR = CanNegateR;
4945 NegateAfterR = !CanNegateR;
4948 NegateAfterAll = !Negate;
4950 assert(Opcode == TargetOpcode::G_AND &&
4951 "Valid conjunction/disjunction tree");
4952 assert(!Negate &&
"Valid conjunction/disjunction tree");
4956 NegateAfterR =
false;
4957 NegateAfterAll =
false;
4962 MachineInstr *CmpR =
4973MachineInstr *AArch64InstructionSelector::emitConjunction(
4975 bool DummyCanNegate;
4976 bool DummyMustBeFirst;
4983bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4984 MachineInstr &CondMI) {
4995bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4996 MachineRegisterInfo &MRI = *MIB.
getMRI();
5015 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5024 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5030 unsigned CondOpc = CondDef->
getOpcode();
5031 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5032 if (tryOptSelectConjunction(
I, *CondDef))
5038 if (CondOpc == TargetOpcode::G_ICMP) {
5067 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5068 I.getOperand(3).getReg(), CondCode, MIB);
5069 I.eraseFromParent();
5073MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5074 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5075 MachineIRBuilder &MIRBuilder)
const {
5077 "Unexpected MachineOperand");
5078 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5101 if (
isCMN(RHSDef,
P, MRI))
5116 if (
isCMN(LHSDef,
P, MRI)) {
5133 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5136 if (!ValAndVReg || ValAndVReg->Value != 0)
5146bool AArch64InstructionSelector::selectShuffleVector(
5147 MachineInstr &
I, MachineRegisterInfo &MRI) {
5148 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5149 Register Src1Reg =
I.getOperand(1).getReg();
5150 Register Src2Reg =
I.getOperand(2).getReg();
5151 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5160 for (
int Val : Mask) {
5163 Val = Val < 0 ? 0 : Val;
5164 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5182 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5189 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5193 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5198 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5199 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5201 I.eraseFromParent();
5209 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5212 I.eraseFromParent();
5216MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5218 unsigned LaneIdx,
const RegisterBank &RB,
5219 MachineIRBuilder &MIRBuilder)
const {
5220 MachineInstr *InsElt =
nullptr;
5221 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5222 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5231 if (RB.
getID() == AArch64::FPRRegBankID) {
5232 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5235 .
addUse(InsSub->getOperand(0).getReg())
5247bool AArch64InstructionSelector::selectUSMovFromExtend(
5248 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5249 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5250 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5251 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5253 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5254 const Register DefReg =
MI.getOperand(0).getReg();
5255 const LLT DstTy = MRI.
getType(DefReg);
5258 if (DstSize != 32 && DstSize != 64)
5261 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5262 MI.getOperand(1).getReg(), MRI);
5268 const LLT VecTy = MRI.
getType(Src0);
5273 const MachineInstr *ScalarToVector = emitScalarToVector(
5274 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5275 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5281 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5283 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5285 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5287 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5289 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5297 MachineInstr *ExtI =
nullptr;
5298 if (DstSize == 64 && !IsSigned) {
5300 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5301 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5303 .
addImm(AArch64::sub_32);
5306 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5309 MI.eraseFromParent();
5313MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5314 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5316 if (DstSize == 128) {
5317 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5319 Op = AArch64::MOVIv16b_ns;
5321 Op = AArch64::MOVIv8b_ns;
5324 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5328 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5335MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5336 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5340 if (DstSize == 128) {
5341 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5343 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5345 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5348 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5365MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5366 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5370 if (DstSize == 128) {
5371 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5373 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5375 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5378 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5401MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5402 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5405 if (DstSize == 128) {
5406 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5408 Op = AArch64::MOVIv2d_ns;
5410 Op = AArch64::MOVID;
5413 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5416 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5423MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5424 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5428 if (DstSize == 128) {
5429 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5431 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5433 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5436 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5453MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5454 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5457 bool IsWide =
false;
5458 if (DstSize == 128) {
5459 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5461 Op = AArch64::FMOVv4f32_ns;
5464 Op = AArch64::FMOVv2f32_ns;
5467 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5473 Op = AArch64::FMOVv2f64_ns;
5477 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5482bool AArch64InstructionSelector::selectIndexedExtLoad(
5483 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5486 Register WriteBack = ExtLd.getWritebackReg();
5491 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5492 bool IsPre = ExtLd.isPre();
5494 unsigned InsertIntoSubReg = 0;
5500 if ((IsSExt && IsFPR) || Ty.
isVector())
5508 if (MemSizeBits == 8) {
5511 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5513 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5514 NewLdDstTy = IsDst64 ? s64 : s32;
5516 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5517 InsertIntoSubReg = AArch64::bsub;
5520 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5521 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5524 }
else if (MemSizeBits == 16) {
5527 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5529 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5530 NewLdDstTy = IsDst64 ? s64 : s32;
5532 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5533 InsertIntoSubReg = AArch64::hsub;
5536 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5537 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5540 }
else if (MemSizeBits == 32) {
5542 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5545 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5546 InsertIntoSubReg = AArch64::ssub;
5549 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5550 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5562 .addImm(Cst->getSExtValue());
5567 if (InsertIntoSubReg) {
5569 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5570 .addUse(LdMI.getReg(1))
5571 .
addImm(InsertIntoSubReg);
5574 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5581 MI.eraseFromParent();
5586bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5587 MachineRegisterInfo &MRI) {
5590 Register WriteBack = Ld.getWritebackReg();
5594 "Unexpected type for indexed load");
5595 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5598 return selectIndexedExtLoad(
MI, MRI);
5602 static constexpr unsigned GPROpcodes[] = {
5603 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5605 static constexpr unsigned FPROpcodes[] = {
5606 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5609 ? FPROpcodes[
Log2_32(MemSize)]
5610 : GPROpcodes[
Log2_32(MemSize)];
5613 static constexpr unsigned GPROpcodes[] = {
5614 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5616 static constexpr unsigned FPROpcodes[] = {
5617 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5618 AArch64::LDRDpost, AArch64::LDRQpost};
5620 ? FPROpcodes[
Log2_32(MemSize)]
5621 : GPROpcodes[
Log2_32(MemSize)];
5631 MI.eraseFromParent();
5635bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5636 MachineRegisterInfo &MRI) {
5642 "Unexpected type for indexed store");
5644 LocationSize MemSize =
I.getMMO().getSize();
5645 unsigned MemSizeInBytes = MemSize.
getValue();
5647 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5648 "Unexpected indexed store size");
5649 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5653 static constexpr unsigned GPROpcodes[] = {
5654 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5656 static constexpr unsigned FPROpcodes[] = {
5657 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5661 Opc = FPROpcodes[MemSizeLog2];
5663 Opc = GPROpcodes[MemSizeLog2];
5665 static constexpr unsigned GPROpcodes[] = {
5666 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5668 static constexpr unsigned FPROpcodes[] = {
5669 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5670 AArch64::STRDpost, AArch64::STRQpost};
5673 Opc = FPROpcodes[MemSizeLog2];
5675 Opc = GPROpcodes[MemSizeLog2];
5683 Str.cloneMemRefs(
I);
5685 I.eraseFromParent();
5690AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5691 MachineIRBuilder &MIRBuilder,
5692 MachineRegisterInfo &MRI) {
5695 assert((DstSize == 64 || DstSize == 128) &&
5696 "Unexpected vector constant size");
5699 if (DstSize == 128) {
5701 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5706 if (DstSize == 64) {
5709 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5712 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5719 APInt SplatValueAsInt =
5722 : SplatValue->getUniqueInteger();
5725 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5726 MachineInstr *NewOp;
5750 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5754 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5755 unsigned NegOpc) -> MachineInstr * {
5758 APInt NegBits(DstSize, 0);
5759 unsigned NumElts = DstSize / NumBits;
5760 for (
unsigned i = 0; i < NumElts; i++)
5761 NegBits |= Neg << (NumBits * i);
5762 NegBits = DefBits ^ NegBits;
5766 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5768 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5770 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5775 if ((R = TryWithFNeg(DefBits, 32,
5776 DstSize == 64 ? AArch64::FNEGv2f32
5777 : AArch64::FNEGv4f32)) ||
5778 (R = TryWithFNeg(DefBits, 64,
5779 DstSize == 64 ? AArch64::FNEGDr
5780 : AArch64::FNEGv2f64)) ||
5781 (STI.hasFullFP16() &&
5782 (R = TryWithFNeg(DefBits, 16,
5783 DstSize == 64 ? AArch64::FNEGv4f16
5784 : AArch64::FNEGv8f16))))
5790 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5794 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5796 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5800bool AArch64InstructionSelector::tryOptConstantBuildVec(
5801 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5802 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5804 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5810 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5811 Register OpReg =
I.getOperand(Idx).getReg();
5820 std::move(AnyConst->Value)));
5833 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5835 I.eraseFromParent();
5839bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5840 MachineInstr &
I, MachineRegisterInfo &MRI) {
5845 Register Dst =
I.getOperand(0).getReg();
5846 Register EltReg =
I.getOperand(1).getReg();
5847 LLT EltTy = MRI.
getType(EltReg);
5850 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5855 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5859 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5862 const TargetRegisterClass *DstRC =
5863 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5868 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5871 I.eraseFromParent();
5876bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5877 MachineRegisterInfo &MRI) {
5878 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5881 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5882 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5885 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5887 if (tryOptBuildVecToSubregToReg(
I, MRI))
5890 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5892 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5894 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5895 MachineInstr *ScalarToVec =
5897 I.getOperand(1).getReg(), MIB);
5906 MachineInstr *PrevMI = ScalarToVec;
5907 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5910 Register OpReg =
I.getOperand(i).getReg();
5913 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5920 if (DstSize < 128) {
5922 const TargetRegisterClass *RC =
5923 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5926 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5931 unsigned SubReg = 0;
5934 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5935 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5941 Register DstReg =
I.getOperand(0).getReg();
5943 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5944 MachineOperand &RegOp =
I.getOperand(1);
5964 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5965 const TargetRegisterClass *RC =
5966 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5975bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5978 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5980 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5981 auto &MRI = *MIB.
getMRI();
5982 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5985 "Destination must be 64 bits or 128 bits?");
5986 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5987 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5990 Load.cloneMemRefs(
I);
5992 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5993 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5994 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5995 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6004bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6005 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6006 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6008 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6009 auto &MRI = *MIB.
getMRI();
6010 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6013 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6015 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6016 [](
auto MO) { return MO.getReg(); });
6020 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6035 .
addImm(LaneNo->getZExtValue())
6037 Load.cloneMemRefs(
I);
6039 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6040 unsigned SubReg = AArch64::qsub0;
6041 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6042 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6043 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6044 : DstOp(
I.getOperand(Idx).
getReg())},
6046 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6051 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6057void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6060 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6061 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6062 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6065 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6066 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6075bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6076 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6077 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6078 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6082 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6083 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6087 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6097 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6100 .
addImm(LaneNo->getZExtValue())
6107bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6108 MachineInstr &
I, MachineRegisterInfo &MRI) {
6121 case Intrinsic::aarch64_ldxp:
6122 case Intrinsic::aarch64_ldaxp: {
6124 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6125 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6131 case Intrinsic::aarch64_neon_ld1x2: {
6132 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6135 Opc = AArch64::LD1Twov8b;
6137 Opc = AArch64::LD1Twov16b;
6139 Opc = AArch64::LD1Twov4h;
6141 Opc = AArch64::LD1Twov8h;
6143 Opc = AArch64::LD1Twov2s;
6145 Opc = AArch64::LD1Twov4s;
6147 Opc = AArch64::LD1Twov2d;
6148 else if (Ty ==
S64 || Ty == P0)
6149 Opc = AArch64::LD1Twov1d;
6152 selectVectorLoadIntrinsic(
Opc, 2,
I);
6155 case Intrinsic::aarch64_neon_ld1x3: {
6156 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6159 Opc = AArch64::LD1Threev8b;
6161 Opc = AArch64::LD1Threev16b;
6163 Opc = AArch64::LD1Threev4h;
6165 Opc = AArch64::LD1Threev8h;
6167 Opc = AArch64::LD1Threev2s;
6169 Opc = AArch64::LD1Threev4s;
6171 Opc = AArch64::LD1Threev2d;
6172 else if (Ty ==
S64 || Ty == P0)
6173 Opc = AArch64::LD1Threev1d;
6176 selectVectorLoadIntrinsic(
Opc, 3,
I);
6179 case Intrinsic::aarch64_neon_ld1x4: {
6180 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6183 Opc = AArch64::LD1Fourv8b;
6185 Opc = AArch64::LD1Fourv16b;
6187 Opc = AArch64::LD1Fourv4h;
6189 Opc = AArch64::LD1Fourv8h;
6191 Opc = AArch64::LD1Fourv2s;
6193 Opc = AArch64::LD1Fourv4s;
6195 Opc = AArch64::LD1Fourv2d;
6196 else if (Ty ==
S64 || Ty == P0)
6197 Opc = AArch64::LD1Fourv1d;
6200 selectVectorLoadIntrinsic(
Opc, 4,
I);
6203 case Intrinsic::aarch64_neon_ld2: {
6204 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6207 Opc = AArch64::LD2Twov8b;
6209 Opc = AArch64::LD2Twov16b;
6211 Opc = AArch64::LD2Twov4h;
6213 Opc = AArch64::LD2Twov8h;
6215 Opc = AArch64::LD2Twov2s;
6217 Opc = AArch64::LD2Twov4s;
6219 Opc = AArch64::LD2Twov2d;
6220 else if (Ty ==
S64 || Ty == P0)
6221 Opc = AArch64::LD1Twov1d;
6224 selectVectorLoadIntrinsic(
Opc, 2,
I);
6227 case Intrinsic::aarch64_neon_ld2lane: {
6228 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6231 Opc = AArch64::LD2i8;
6233 Opc = AArch64::LD2i16;
6235 Opc = AArch64::LD2i32;
6238 Opc = AArch64::LD2i64;
6241 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6245 case Intrinsic::aarch64_neon_ld2r: {
6246 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6249 Opc = AArch64::LD2Rv8b;
6251 Opc = AArch64::LD2Rv16b;
6253 Opc = AArch64::LD2Rv4h;
6255 Opc = AArch64::LD2Rv8h;
6257 Opc = AArch64::LD2Rv2s;
6259 Opc = AArch64::LD2Rv4s;
6261 Opc = AArch64::LD2Rv2d;
6262 else if (Ty ==
S64 || Ty == P0)
6263 Opc = AArch64::LD2Rv1d;
6266 selectVectorLoadIntrinsic(
Opc, 2,
I);
6269 case Intrinsic::aarch64_neon_ld3: {
6270 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6273 Opc = AArch64::LD3Threev8b;
6275 Opc = AArch64::LD3Threev16b;
6277 Opc = AArch64::LD3Threev4h;
6279 Opc = AArch64::LD3Threev8h;
6281 Opc = AArch64::LD3Threev2s;
6283 Opc = AArch64::LD3Threev4s;
6285 Opc = AArch64::LD3Threev2d;
6286 else if (Ty ==
S64 || Ty == P0)
6287 Opc = AArch64::LD1Threev1d;
6290 selectVectorLoadIntrinsic(
Opc, 3,
I);
6293 case Intrinsic::aarch64_neon_ld3lane: {
6294 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6297 Opc = AArch64::LD3i8;
6299 Opc = AArch64::LD3i16;
6301 Opc = AArch64::LD3i32;
6304 Opc = AArch64::LD3i64;
6307 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6311 case Intrinsic::aarch64_neon_ld3r: {
6312 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6315 Opc = AArch64::LD3Rv8b;
6317 Opc = AArch64::LD3Rv16b;
6319 Opc = AArch64::LD3Rv4h;
6321 Opc = AArch64::LD3Rv8h;
6323 Opc = AArch64::LD3Rv2s;
6325 Opc = AArch64::LD3Rv4s;
6327 Opc = AArch64::LD3Rv2d;
6328 else if (Ty ==
S64 || Ty == P0)
6329 Opc = AArch64::LD3Rv1d;
6332 selectVectorLoadIntrinsic(
Opc, 3,
I);
6335 case Intrinsic::aarch64_neon_ld4: {
6336 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6339 Opc = AArch64::LD4Fourv8b;
6341 Opc = AArch64::LD4Fourv16b;
6343 Opc = AArch64::LD4Fourv4h;
6345 Opc = AArch64::LD4Fourv8h;
6347 Opc = AArch64::LD4Fourv2s;
6349 Opc = AArch64::LD4Fourv4s;
6351 Opc = AArch64::LD4Fourv2d;
6352 else if (Ty ==
S64 || Ty == P0)
6353 Opc = AArch64::LD1Fourv1d;
6356 selectVectorLoadIntrinsic(
Opc, 4,
I);
6359 case Intrinsic::aarch64_neon_ld4lane: {
6360 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6363 Opc = AArch64::LD4i8;
6365 Opc = AArch64::LD4i16;
6367 Opc = AArch64::LD4i32;
6370 Opc = AArch64::LD4i64;
6373 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6377 case Intrinsic::aarch64_neon_ld4r: {
6378 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6381 Opc = AArch64::LD4Rv8b;
6383 Opc = AArch64::LD4Rv16b;
6385 Opc = AArch64::LD4Rv4h;
6387 Opc = AArch64::LD4Rv8h;
6389 Opc = AArch64::LD4Rv2s;
6391 Opc = AArch64::LD4Rv4s;
6393 Opc = AArch64::LD4Rv2d;
6394 else if (Ty ==
S64 || Ty == P0)
6395 Opc = AArch64::LD4Rv1d;
6398 selectVectorLoadIntrinsic(
Opc, 4,
I);
6401 case Intrinsic::aarch64_neon_st1x2: {
6402 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6405 Opc = AArch64::ST1Twov8b;
6407 Opc = AArch64::ST1Twov16b;
6409 Opc = AArch64::ST1Twov4h;
6411 Opc = AArch64::ST1Twov8h;
6413 Opc = AArch64::ST1Twov2s;
6415 Opc = AArch64::ST1Twov4s;
6417 Opc = AArch64::ST1Twov2d;
6418 else if (Ty ==
S64 || Ty == P0)
6419 Opc = AArch64::ST1Twov1d;
6422 selectVectorStoreIntrinsic(
I, 2,
Opc);
6425 case Intrinsic::aarch64_neon_st1x3: {
6426 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6429 Opc = AArch64::ST1Threev8b;
6431 Opc = AArch64::ST1Threev16b;
6433 Opc = AArch64::ST1Threev4h;
6435 Opc = AArch64::ST1Threev8h;
6437 Opc = AArch64::ST1Threev2s;
6439 Opc = AArch64::ST1Threev4s;
6441 Opc = AArch64::ST1Threev2d;
6442 else if (Ty ==
S64 || Ty == P0)
6443 Opc = AArch64::ST1Threev1d;
6446 selectVectorStoreIntrinsic(
I, 3,
Opc);
6449 case Intrinsic::aarch64_neon_st1x4: {
6450 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6453 Opc = AArch64::ST1Fourv8b;
6455 Opc = AArch64::ST1Fourv16b;
6457 Opc = AArch64::ST1Fourv4h;
6459 Opc = AArch64::ST1Fourv8h;
6461 Opc = AArch64::ST1Fourv2s;
6463 Opc = AArch64::ST1Fourv4s;
6465 Opc = AArch64::ST1Fourv2d;
6466 else if (Ty ==
S64 || Ty == P0)
6467 Opc = AArch64::ST1Fourv1d;
6470 selectVectorStoreIntrinsic(
I, 4,
Opc);
6473 case Intrinsic::aarch64_neon_st2: {
6474 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6477 Opc = AArch64::ST2Twov8b;
6479 Opc = AArch64::ST2Twov16b;
6481 Opc = AArch64::ST2Twov4h;
6483 Opc = AArch64::ST2Twov8h;
6485 Opc = AArch64::ST2Twov2s;
6487 Opc = AArch64::ST2Twov4s;
6489 Opc = AArch64::ST2Twov2d;
6490 else if (Ty ==
S64 || Ty == P0)
6491 Opc = AArch64::ST1Twov1d;
6494 selectVectorStoreIntrinsic(
I, 2,
Opc);
6497 case Intrinsic::aarch64_neon_st3: {
6498 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6501 Opc = AArch64::ST3Threev8b;
6503 Opc = AArch64::ST3Threev16b;
6505 Opc = AArch64::ST3Threev4h;
6507 Opc = AArch64::ST3Threev8h;
6509 Opc = AArch64::ST3Threev2s;
6511 Opc = AArch64::ST3Threev4s;
6513 Opc = AArch64::ST3Threev2d;
6514 else if (Ty ==
S64 || Ty == P0)
6515 Opc = AArch64::ST1Threev1d;
6518 selectVectorStoreIntrinsic(
I, 3,
Opc);
6521 case Intrinsic::aarch64_neon_st4: {
6522 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6525 Opc = AArch64::ST4Fourv8b;
6527 Opc = AArch64::ST4Fourv16b;
6529 Opc = AArch64::ST4Fourv4h;
6531 Opc = AArch64::ST4Fourv8h;
6533 Opc = AArch64::ST4Fourv2s;
6535 Opc = AArch64::ST4Fourv4s;
6537 Opc = AArch64::ST4Fourv2d;
6538 else if (Ty ==
S64 || Ty == P0)
6539 Opc = AArch64::ST1Fourv1d;
6542 selectVectorStoreIntrinsic(
I, 4,
Opc);
6545 case Intrinsic::aarch64_neon_st2lane: {
6546 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6549 Opc = AArch64::ST2i8;
6551 Opc = AArch64::ST2i16;
6553 Opc = AArch64::ST2i32;
6556 Opc = AArch64::ST2i64;
6559 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6563 case Intrinsic::aarch64_neon_st3lane: {
6564 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6567 Opc = AArch64::ST3i8;
6569 Opc = AArch64::ST3i16;
6571 Opc = AArch64::ST3i32;
6574 Opc = AArch64::ST3i64;
6577 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6581 case Intrinsic::aarch64_neon_st4lane: {
6582 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6585 Opc = AArch64::ST4i8;
6587 Opc = AArch64::ST4i16;
6589 Opc = AArch64::ST4i32;
6592 Opc = AArch64::ST4i64;
6595 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6599 case Intrinsic::aarch64_mops_memset_tag: {
6612 Register DstDef =
I.getOperand(0).getReg();
6614 Register DstUse =
I.getOperand(2).getReg();
6615 Register ValUse =
I.getOperand(3).getReg();
6616 Register SizeUse =
I.getOperand(4).getReg();
6623 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6624 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6629 case Intrinsic::ptrauth_resign_load_relative: {
6630 Register DstReg =
I.getOperand(0).getReg();
6631 Register ValReg =
I.getOperand(2).getReg();
6632 uint64_t AUTKey =
I.getOperand(3).getImm();
6633 Register AUTDisc =
I.getOperand(4).getReg();
6634 uint64_t PACKey =
I.getOperand(5).getImm();
6635 Register PACDisc =
I.getOperand(6).getReg();
6636 int64_t Addend =
I.getOperand(7).getImm();
6639 uint16_t AUTConstDiscC = 0;
6640 std::tie(AUTConstDiscC, AUTAddrDisc) =
6644 uint16_t PACConstDiscC = 0;
6645 std::tie(PACConstDiscC, PACAddrDisc) =
6648 MIB.
buildCopy({AArch64::X16}, {ValReg});
6662 I.eraseFromParent();
6667 I.eraseFromParent();
6671bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6672 MachineRegisterInfo &MRI) {
6678 case Intrinsic::ptrauth_resign: {
6679 Register DstReg =
I.getOperand(0).getReg();
6680 Register ValReg =
I.getOperand(2).getReg();
6681 uint64_t AUTKey =
I.getOperand(3).getImm();
6682 Register AUTDisc =
I.getOperand(4).getReg();
6683 uint64_t PACKey =
I.getOperand(5).getImm();
6684 Register PACDisc =
I.getOperand(6).getReg();
6687 uint16_t AUTConstDiscC = 0;
6688 std::tie(AUTConstDiscC, AUTAddrDisc) =
6692 uint16_t PACConstDiscC = 0;
6693 std::tie(PACConstDiscC, PACAddrDisc) =
6696 MIB.
buildCopy({AArch64::X16}, {ValReg});
6697 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6709 I.eraseFromParent();
6712 case Intrinsic::ptrauth_auth: {
6713 Register DstReg =
I.getOperand(0).getReg();
6714 Register ValReg =
I.getOperand(2).getReg();
6715 uint64_t AUTKey =
I.getOperand(3).getImm();
6716 Register AUTDisc =
I.getOperand(4).getReg();
6719 uint16_t AUTConstDiscC = 0;
6720 std::tie(AUTConstDiscC, AUTAddrDisc) =
6724 MIB.
buildCopy({AArch64::X16}, {ValReg});
6725 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6746 I.eraseFromParent();
6749 case Intrinsic::frameaddress:
6750 case Intrinsic::returnaddress: {
6751 MachineFunction &MF = *
I.getParent()->getParent();
6754 unsigned Depth =
I.getOperand(2).getImm();
6755 Register DstReg =
I.getOperand(0).getReg();
6758 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6759 if (!MFReturnAddr) {
6764 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6767 if (STI.hasPAuth()) {
6768 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6775 I.eraseFromParent();
6784 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6786 FrameAddr = NextFrame;
6789 if (IntrinID == Intrinsic::frameaddress)
6794 if (STI.hasPAuth()) {
6796 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6797 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6806 I.eraseFromParent();
6809 case Intrinsic::aarch64_neon_tbl2:
6810 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6812 case Intrinsic::aarch64_neon_tbl3:
6813 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6816 case Intrinsic::aarch64_neon_tbl4:
6817 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6819 case Intrinsic::aarch64_neon_tbx2:
6820 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6822 case Intrinsic::aarch64_neon_tbx3:
6823 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6825 case Intrinsic::aarch64_neon_tbx4:
6826 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6828 case Intrinsic::swift_async_context_addr:
6829 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6836 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6837 I.eraseFromParent();
6872bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6873 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6874 Register DefReg =
I.getOperand(0).getReg();
6875 Register Addr =
I.getOperand(1).getReg();
6876 uint64_t
Key =
I.getOperand(2).getImm();
6877 Register AddrDisc =
I.getOperand(3).getReg();
6878 uint64_t Disc =
I.getOperand(4).getImm();
6888 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6904 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6916 const GlobalValue *GV;
6927 MachineIRBuilder MIB(
I);
6933 "unsupported non-GOT op flags on ptrauth global reference");
6935 "unsupported non-GOT reference to weak ptrauth global");
6938 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6945 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6946 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6947 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6950 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6955 I.eraseFromParent();
6967 "unsupported non-zero offset in weak ptrauth global reference");
6972 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6973 .addGlobalAddress(GV,
Offset)
6978 I.eraseFromParent();
6982void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6983 MachineRegisterInfo &MRI,
6984 unsigned NumVec,
unsigned Opc1,
6985 unsigned Opc2,
bool isExt) {
6986 Register DstReg =
I.getOperand(0).getReg();
6991 for (
unsigned i = 0; i < NumVec; i++)
6992 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6995 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6996 MachineInstrBuilder
Instr;
7003 I.eraseFromParent();
7006InstructionSelector::ComplexRendererFns
7007AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7009 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7010 return std::nullopt;
7011 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7012 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7015InstructionSelector::ComplexRendererFns
7016AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7018 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7019 return std::nullopt;
7020 uint64_t Enc = 31 - *MaybeImmed;
7021 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7024InstructionSelector::ComplexRendererFns
7025AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7027 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7028 return std::nullopt;
7029 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7030 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7033InstructionSelector::ComplexRendererFns
7034AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7036 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7037 return std::nullopt;
7038 uint64_t Enc = 63 - *MaybeImmed;
7039 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7047InstructionSelector::ComplexRendererFns
7048AArch64InstructionSelector::select12BitValueWithLeftShift(
7049 uint64_t Immed)
const {
7051 if (Immed >> 12 == 0) {
7053 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7055 Immed = Immed >> 12;
7057 return std::nullopt;
7061 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7062 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7069InstructionSelector::ComplexRendererFns
7070AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7077 if (MaybeImmed == std::nullopt)
7078 return std::nullopt;
7079 return select12BitValueWithLeftShift(*MaybeImmed);
7084InstructionSelector::ComplexRendererFns
7085AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7089 return std::nullopt;
7091 if (MaybeImmed == std::nullopt)
7092 return std::nullopt;
7093 uint64_t Immed = *MaybeImmed;
7099 return std::nullopt;
7105 Immed = ~((uint32_t)Immed) + 1;
7107 Immed = ~Immed + 1ULL;
7109 if (Immed & 0xFFFFFFFFFF000000ULL)
7110 return std::nullopt;
7112 Immed &= 0xFFFFFFULL;
7113 return select12BitValueWithLeftShift(Immed);
7130std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7131 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7132 if (
MI.getOpcode() == AArch64::G_SHL) {
7136 MI.getOperand(2).getReg(), MRI)) {
7137 const APInt ShiftVal = ValAndVeg->Value;
7140 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7143 return std::nullopt;
7151bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7152 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7153 bool IsAddrOperand)
const {
7158 MI.getParent()->getParent()->getFunction().hasOptSize())
7161 if (IsAddrOperand) {
7163 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7167 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7168 MachineInstr *OffsetInst =
7174 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7185 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7188InstructionSelector::ComplexRendererFns
7189AArch64InstructionSelector::selectExtendedSHL(
7190 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7191 unsigned SizeInBytes,
bool WantsExt)
const {
7192 assert(
Base.isReg() &&
"Expected base to be a register operand");
7193 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7198 unsigned OffsetOpc = OffsetInst->
getOpcode();
7199 bool LookedThroughZExt =
false;
7200 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7202 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7203 return std::nullopt;
7207 LookedThroughZExt =
true;
7209 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7210 return std::nullopt;
7213 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7214 if (LegalShiftVal == 0)
7215 return std::nullopt;
7216 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7217 return std::nullopt;
7228 if (OffsetOpc == TargetOpcode::G_SHL)
7229 return std::nullopt;
7235 return std::nullopt;
7240 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7244 if (OffsetOpc == TargetOpcode::G_MUL) {
7246 return std::nullopt;
7252 if ((ImmVal & 0x7) != ImmVal)
7253 return std::nullopt;
7257 if (ImmVal != LegalShiftVal)
7258 return std::nullopt;
7260 unsigned SignExtend = 0;
7264 if (!LookedThroughZExt) {
7266 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7268 return std::nullopt;
7273 return std::nullopt;
7279 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7284 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7285 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7286 [=](MachineInstrBuilder &MIB) {
7289 MIB.addImm(SignExtend);
7302InstructionSelector::ComplexRendererFns
7303AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7304 MachineOperand &Root,
unsigned SizeInBytes)
const {
7306 return std::nullopt;
7321 MachineInstr *PtrAdd =
7323 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7324 return std::nullopt;
7328 MachineInstr *OffsetInst =
7330 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7343InstructionSelector::ComplexRendererFns
7344AArch64InstructionSelector::selectAddrModeRegisterOffset(
7345 MachineOperand &Root)
const {
7350 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7351 return std::nullopt;
7357 return std::nullopt;
7360 return {{[=](MachineInstrBuilder &MIB) {
7363 [=](MachineInstrBuilder &MIB) {
7366 [=](MachineInstrBuilder &MIB) {
7376InstructionSelector::ComplexRendererFns
7377AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7378 unsigned SizeInBytes)
const {
7381 return std::nullopt;
7382 MachineInstr *PtrAdd =
7385 return std::nullopt;
7403 unsigned Scale =
Log2_32(SizeInBytes);
7404 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7408 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7409 ImmOff < (0x1000 << Scale))
7410 return std::nullopt;
7415 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7419 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7425 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7426 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7431 return std::nullopt;
7435 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7441 return selectAddrModeRegisterOffset(Root);
7450InstructionSelector::ComplexRendererFns
7451AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7452 unsigned SizeInBytes)
const {
7455 MachineInstr *PtrAdd =
7457 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7458 return std::nullopt;
7479 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7488 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7489 return std::nullopt;
7493 getExtendTypeForInst(*OffsetInst, MRI,
true);
7495 return std::nullopt;
7498 MachineIRBuilder MIB(*PtrAdd);
7500 AArch64::GPR32RegClass, MIB);
7504 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7505 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7506 [=](MachineInstrBuilder &MIB) {
7507 MIB.addImm(SignExtend);
7517InstructionSelector::ComplexRendererFns
7518AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7519 unsigned Size)
const {
7520 MachineRegisterInfo &MRI =
7524 return std::nullopt;
7526 if (!isBaseWithConstantOffset(Root, MRI))
7527 return std::nullopt;
7531 MachineOperand &OffImm = RootDef->
getOperand(2);
7532 if (!OffImm.
isReg())
7533 return std::nullopt;
7535 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7536 return std::nullopt;
7538 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7540 return std::nullopt;
7543 if (RHSC >= -256 && RHSC < 256) {
7546 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7547 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7550 return std::nullopt;
7553InstructionSelector::ComplexRendererFns
7554AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7556 MachineRegisterInfo &MRI)
const {
7557 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7558 return std::nullopt;
7561 return std::nullopt;
7566 return std::nullopt;
7570 return std::nullopt;
7574 return std::nullopt;
7577 MachineIRBuilder MIRBuilder(RootDef);
7579 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7580 [=](MachineInstrBuilder &MIB) {
7581 MIB.addGlobalAddress(GV,
Offset,
7590InstructionSelector::ComplexRendererFns
7591AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7592 unsigned Size)
const {
7597 return std::nullopt;
7600 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7602 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7603 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7611 MachineInstr *RootParent = Root.
getParent();
7613 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7615 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7620 if (isBaseWithConstantOffset(Root, MRI)) {
7628 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7629 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7631 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7632 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7636 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7637 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7644 if (selectAddrModeUnscaled(Root,
Size))
7645 return std::nullopt;
7648 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7649 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7656 switch (
MI.getOpcode()) {
7659 case TargetOpcode::G_SHL:
7661 case TargetOpcode::G_LSHR:
7663 case TargetOpcode::G_ASHR:
7665 case TargetOpcode::G_ROTR:
7672InstructionSelector::ComplexRendererFns
7673AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7674 bool AllowROR)
const {
7676 return std::nullopt;
7677 MachineRegisterInfo &MRI =
7685 return std::nullopt;
7687 return std::nullopt;
7688 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7689 return std::nullopt;
7692 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7695 return std::nullopt;
7699 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7703 unsigned Val = *Immed & (NumBits - 1);
7706 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7707 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7711 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7712 unsigned Opc =
MI.getOpcode();
7715 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7717 if (
Opc == TargetOpcode::G_SEXT)
7720 Size =
MI.getOperand(2).getImm();
7721 assert(
Size != 64 &&
"Extend from 64 bits?");
7734 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7736 assert(
Size != 64 &&
"Extend from 64 bits?");
7751 if (
Opc != TargetOpcode::G_AND)
7757 uint64_t AndMask = *MaybeAndMask;
7770Register AArch64InstructionSelector::moveScalarRegClass(
7771 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7772 MachineRegisterInfo &MRI = *MIB.
getMRI();
7782 return Copy.getReg(0);
7787InstructionSelector::ComplexRendererFns
7788AArch64InstructionSelector::selectArithExtendedRegister(
7789 MachineOperand &Root)
const {
7791 return std::nullopt;
7792 MachineRegisterInfo &MRI =
7795 uint64_t ShiftVal = 0;
7800 return std::nullopt;
7802 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7803 return std::nullopt;
7806 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7811 return std::nullopt;
7812 ShiftVal = *MaybeShiftVal;
7814 return std::nullopt;
7819 return std::nullopt;
7820 Ext = getExtendTypeForInst(*ExtDef, MRI);
7822 return std::nullopt;
7826 Ext = getExtendTypeForInst(*RootDef, MRI);
7828 return std::nullopt;
7836 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7837 if (isDef32(*ExtInst))
7838 return std::nullopt;
7844 MachineIRBuilder MIB(*RootDef);
7845 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7847 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7848 [=](MachineInstrBuilder &MIB) {
7849 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7853InstructionSelector::ComplexRendererFns
7854AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7856 return std::nullopt;
7857 MachineRegisterInfo &MRI =
7861 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7866 return std::nullopt;
7869 if (Unmerge->getNumDefs() == 2 &&
7871 Register ExtReg = Unmerge->getSourceReg();
7872 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7876 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7880 LaneIdx->Value.getSExtValue() == 1) {
7881 Register ExtReg = ExtElt->getVectorReg();
7882 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7886 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7887 auto LaneIdx = Subvec->getIndexImm();
7889 Register ExtReg = Subvec->getSrcVec();
7890 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7894 return std::nullopt;
7897InstructionSelector::ComplexRendererFns
7898AArch64InstructionSelector::selectCVTFixedPointVecBase(
7899 const MachineOperand &Root,
bool isReciprocal)
const {
7901 return std::nullopt;
7902 const MachineRegisterInfo &MRI =
7907 return std::nullopt;
7908 std::optional<ValueAndVReg> CstVal =
7911 return std::nullopt;
7917 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7920 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7923 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7926 return std::nullopt;
7928 if (
unsigned FBits =
7930 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7932 return std::nullopt;
7935InstructionSelector::ComplexRendererFns
7936AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
7937 return selectCVTFixedPointVecBase(Root,
false);
7940InstructionSelector::ComplexRendererFns
7941AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
7942 MachineOperand &Root)
const {
7943 return selectCVTFixedPointVecBase(Root,
true);
7946void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
7947 const MachineInstr &
MI,
7952 InstructionSelector::ComplexRendererFns Renderer =
7953 selectCVTFixedPointVecBase(
MI.getOperand(2),
false);
7954 assert((Renderer && Renderer->size() == 1) &&
7955 "Expected selectCVTFixedPointVec to provide a function\n");
7956 (Renderer->front())(MIB);
7959void AArch64InstructionSelector::renderFixedPointRecipXForm(
7960 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7961 InstructionSelector::ComplexRendererFns Renderer =
7962 selectCVTFixedPointVecBase(
MI.getOperand(2),
true);
7963 assert((Renderer && Renderer->size() == 1) &&
7964 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
7965 (Renderer->front())(MIB);
7968void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7969 const MachineInstr &
MI,
7971 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
7972 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7973 "Expected G_CONSTANT");
7974 std::optional<int64_t> CstVal =
7976 assert(CstVal &&
"Expected constant value");
7980void AArch64InstructionSelector::renderLogicalImm32(
7981 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7982 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7983 "Expected G_CONSTANT");
7984 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7989void AArch64InstructionSelector::renderLogicalImm64(
7990 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7991 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7992 "Expected G_CONSTANT");
7993 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7998void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7999 const MachineInstr &
MI,
8001 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
8002 "Expected G_UBSANTRAP");
8003 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8006void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8007 const MachineInstr &
MI,
8009 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8010 "Expected G_FCONSTANT");
8015void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8016 const MachineInstr &
MI,
8018 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8019 "Expected G_FCONSTANT");
8024void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8025 const MachineInstr &
MI,
8027 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8028 "Expected G_FCONSTANT");
8033void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8034 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8035 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8036 "Expected G_FCONSTANT");
8044bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8045 const MachineInstr &
MI,
unsigned NumBytes)
const {
8046 if (!
MI.mayLoadOrStore())
8049 "Expected load/store to have only one mem op!");
8050 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8053bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8054 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8062 switch (
MI.getOpcode()) {
8065 case TargetOpcode::COPY:
8066 case TargetOpcode::G_BITCAST:
8067 case TargetOpcode::G_TRUNC:
8068 case TargetOpcode::G_PHI:
8078 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8081 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8099 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8104 MO.setReg(Copy.getReg(0));
8109void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8113 for (
auto &BB : MF) {
8114 for (
auto &
MI : BB) {
8115 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8120 for (
auto *
MI : Phis) {
8142 bool HasGPROp =
false, HasFPROp =
false;
8146 const LLT &Ty = MRI.
getType(MO.getReg());
8156 if (RB->
getID() == AArch64::GPRRegBankID)
8162 if (HasGPROp && HasFPROp)
8168InstructionSelector *
8172 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
static std::pair< const TargetRegisterClass *, const TargetRegisterClass * > getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Helper function to get the source and destination register classes for a copy.
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc (such as G_OR or G_SDIV),...
static bool getSubRegForClass(const TargetRegisterClass *RC, const TargetRegisterInfo &TRI, unsigned &SubReg)
Returns the correct subregister to use for a given register class.
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI, Register SrcReg, const TargetRegisterClass *To, unsigned SubReg)
Helper function for selectCopy.
static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P, Register RHS={}, MachineRegisterInfo *MRI=nullptr)
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, const AArch64RegisterBankInfo &RBI)
static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool unsupportedBinOp(const MachineInstr &I, const AArch64RegisterBankInfo &RBI, const MachineRegisterInfo &MRI, const AArch64RegisterInfo &TRI)
Check whether I is a currently unsupported binary operation:
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineInstr unsigned OpIdx
static MachineBasicBlock * emitSelect(MachineInstr &MI, MachineBasicBlock *BB, const TargetInstrInfo *TII, const PPCSubtarget &Subtarget)
Emit SELECT instruction, using ISEL if available, otherwise use branch-based control flow.
static StringRef getName(Value *V)
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.