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: {
2204 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2205 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2209 MRI.
setType(
I.getOperand(1).getReg(),
2211 MRI.
setType(
I.getOperand(0).getReg(),
2213 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2214 I.getOperand(2).setReg(NewSrc.getReg(0));
2217 case TargetOpcode::G_UITOFP:
2218 case TargetOpcode::G_SITOFP: {
2223 Register SrcReg =
I.getOperand(1).getReg();
2224 LLT SrcTy = MRI.
getType(SrcReg);
2225 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2234 I.getOperand(1).setReg(
Copy.getReg(0));
2236 getRegClassForTypeOnBank(
2237 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2239 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2240 I.setDesc(
TII.get(AArch64::G_SITOF));
2242 I.setDesc(
TII.get(AArch64::G_UITOF));
2260bool AArch64InstructionSelector::convertPtrAddToAdd(
2261 MachineInstr &
I, MachineRegisterInfo &MRI) {
2262 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2263 Register DstReg =
I.getOperand(0).getReg();
2264 Register AddOp1Reg =
I.getOperand(1).getReg();
2265 const LLT PtrTy = MRI.
getType(DstReg);
2269 const LLT CastPtrTy = PtrTy.
isVector()
2281 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2282 MRI.
setType(DstReg, CastPtrTy);
2283 I.getOperand(1).setReg(PtrToInt.getReg(0));
2284 if (!select(*PtrToInt)) {
2285 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2294 I.getOperand(2).setReg(NegatedReg);
2295 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2299bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2300 MachineRegisterInfo &MRI) {
2304 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2305 const auto &MO =
I.getOperand(2);
2310 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2314 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2315 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2317 if (!Imm1Fn || !Imm2Fn)
2321 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2322 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2324 for (
auto &RenderFn : *Imm1Fn)
2326 for (
auto &RenderFn : *Imm2Fn)
2329 I.eraseFromParent();
2334bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2335 MachineInstr &
I, MachineRegisterInfo &MRI) {
2336 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2354 LLT DefDstTy = MRI.
getType(DefDstReg);
2355 Register StoreSrcReg =
I.getOperand(0).getReg();
2356 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2372 I.getOperand(0).setReg(DefDstReg);
2376bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2377 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2378 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2384 switch (
I.getOpcode()) {
2385 case AArch64::G_DUP: {
2388 Register Src =
I.getOperand(1).getReg();
2390 Src, MRI,
true,
true);
2394 Register Dst =
I.getOperand(0).getReg();
2400 if (!emitConstantVector(Dst, CV, MIB, MRI))
2402 I.eraseFromParent();
2405 case TargetOpcode::G_SEXT:
2408 if (selectUSMovFromExtend(
I, MRI))
2411 case TargetOpcode::G_BR:
2413 case TargetOpcode::G_SHL:
2414 return earlySelectSHL(
I, MRI);
2415 case TargetOpcode::G_CONSTANT: {
2416 bool IsZero =
false;
2417 if (
I.getOperand(1).isCImm())
2418 IsZero =
I.getOperand(1).getCImm()->isZero();
2419 else if (
I.getOperand(1).isImm())
2420 IsZero =
I.getOperand(1).getImm() == 0;
2425 Register DefReg =
I.getOperand(0).getReg();
2428 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2431 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2436 I.setDesc(
TII.get(TargetOpcode::COPY));
2440 case TargetOpcode::G_ADD: {
2449 Register AddDst =
I.getOperand(0).getReg();
2450 Register AddLHS =
I.getOperand(1).getReg();
2451 Register AddRHS =
I.getOperand(2).getReg();
2461 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2482 MachineInstr *
Cmp = MatchCmp(AddRHS);
2486 Cmp = MatchCmp(AddRHS);
2490 auto &PredOp =
Cmp->getOperand(1);
2492 emitIntegerCompare(
Cmp->getOperand(2),
2493 Cmp->getOperand(3), PredOp, MIB);
2497 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2498 I.eraseFromParent();
2501 case TargetOpcode::G_OR: {
2505 Register Dst =
I.getOperand(0).getReg();
2525 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2528 int64_t Immr =
Size - ShiftImm;
2529 int64_t Imms =
Size - ShiftImm - 1;
2530 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2531 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2532 I.eraseFromParent();
2535 case TargetOpcode::G_FENCE: {
2536 if (
I.getOperand(1).getImm() == 0)
2540 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2541 I.eraseFromParent();
2549bool AArch64InstructionSelector::select(MachineInstr &
I) {
2550 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2551 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2557 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2558 if (Subtarget->requiresStrictAlign()) {
2560 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2566 unsigned Opcode =
I.getOpcode();
2568 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2571 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2576 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2577 const Register DefReg =
I.getOperand(0).getReg();
2578 const LLT DefTy = MRI.
getType(DefReg);
2583 const TargetRegisterClass *DefRC =
2591 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2598 I.setDesc(
TII.get(TargetOpcode::PHI));
2606 if (
I.isDebugInstr())
2613 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2615 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2622 if (preISelLower(
I)) {
2623 Opcode =
I.getOpcode();
2634 if (selectImpl(
I, *CoverageInfo))
2638 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2641 case TargetOpcode::G_SBFX:
2642 case TargetOpcode::G_UBFX: {
2643 static const unsigned OpcTable[2][2] = {
2644 {AArch64::UBFMWri, AArch64::UBFMXri},
2645 {AArch64::SBFMWri, AArch64::SBFMXri}};
2646 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2648 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2651 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2654 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2655 auto LSB = Cst1->Value.getZExtValue();
2656 auto Width = Cst2->Value.getZExtValue();
2660 .
addImm(LSB + Width - 1);
2661 I.eraseFromParent();
2665 case TargetOpcode::G_BRCOND:
2666 return selectCompareBranch(
I, MF, MRI);
2668 case TargetOpcode::G_BRINDIRECT: {
2670 if (std::optional<uint16_t> BADisc =
2672 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2675 MI.addReg(AArch64::XZR);
2676 I.eraseFromParent();
2680 I.setDesc(
TII.get(AArch64::BR));
2685 case TargetOpcode::G_BRJT:
2686 return selectBrJT(
I, MRI);
2688 case AArch64::G_ADD_LOW: {
2693 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2694 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2695 I.setDesc(
TII.get(AArch64::ADDXri));
2701 "Expected small code model");
2703 auto Op2 =
I.getOperand(2);
2704 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2705 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2706 Op1.getTargetFlags())
2708 Op2.getTargetFlags());
2709 I.eraseFromParent();
2714 case TargetOpcode::G_FCONSTANT: {
2715 const Register DefReg =
I.getOperand(0).getReg();
2716 const LLT DefTy = MRI.
getType(DefReg);
2720 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2727 bool OptForSize = shouldOptForSize(&MF);
2731 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2738 auto *FPImm =
I.getOperand(1).getFPImm();
2741 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2744 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2745 I.eraseFromParent();
2750 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2753 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2754 MachineOperand &RegOp =
I.getOperand(0);
2760 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2764 MachineOperand &ImmOp =
I.getOperand(1);
2768 const unsigned MovOpc =
2769 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2770 I.setDesc(
TII.get(MovOpc));
2774 case TargetOpcode::G_EXTRACT: {
2775 Register DstReg =
I.getOperand(0).getReg();
2776 Register SrcReg =
I.getOperand(1).getReg();
2777 LLT SrcTy = MRI.
getType(SrcReg);
2778 LLT DstTy = MRI.
getType(DstReg);
2790 unsigned Offset =
I.getOperand(2).getImm();
2795 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2796 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2799 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2801 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2803 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2805 AArch64::GPR64RegClass, NewI->getOperand(0));
2806 I.eraseFromParent();
2812 unsigned LaneIdx =
Offset / 64;
2813 MachineInstr *Extract = emitExtractVectorElt(
2814 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2817 I.eraseFromParent();
2821 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2822 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2827 "unexpected G_EXTRACT types");
2834 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2835 .addReg(DstReg, {}, AArch64::sub_32);
2837 AArch64::GPR32RegClass, MRI);
2838 I.getOperand(0).setReg(DstReg);
2844 case TargetOpcode::G_INSERT: {
2845 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2846 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2853 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2854 unsigned LSB =
I.getOperand(3).getImm();
2856 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2857 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2861 "unexpected G_INSERT types");
2868 TII.get(AArch64::SUBREG_TO_REG))
2870 .
addUse(
I.getOperand(2).getReg())
2871 .
addImm(AArch64::sub_32);
2873 AArch64::GPR32RegClass, MRI);
2874 I.getOperand(2).setReg(SrcReg);
2879 case TargetOpcode::G_FRAME_INDEX: {
2886 I.setDesc(
TII.get(AArch64::ADDXri));
2896 case TargetOpcode::G_GLOBAL_VALUE: {
2897 const GlobalValue *GV =
nullptr;
2899 if (
I.getOperand(1).isSymbol()) {
2900 OpFlags =
I.getOperand(1).getTargetFlags();
2909 return selectTLSGlobalValue(
I, MRI);
2915 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2916 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2917 I.getOperand(1).setTargetFlags(OpFlags);
2918 I.addImplicitDefUseOperands(MF);
2922 materializeLargeCMVal(
I, GV, OpFlags);
2923 I.eraseFromParent();
2926 I.setDesc(
TII.get(AArch64::ADR));
2927 I.getOperand(1).setTargetFlags(OpFlags);
2929 I.setDesc(
TII.get(AArch64::MOVaddr));
2931 MachineInstrBuilder MIB(MF,
I);
2932 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2939 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2940 return selectPtrAuthGlobalValue(
I, MRI);
2942 case TargetOpcode::G_ZEXTLOAD:
2943 case TargetOpcode::G_LOAD:
2944 case TargetOpcode::G_STORE: {
2946 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2961 assert(MemSizeInBytes <= 8 &&
2962 "128-bit atomics should already be custom-legalized");
2965 static constexpr unsigned LDAPROpcodes[] = {
2966 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2967 static constexpr unsigned LDAROpcodes[] = {
2968 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2969 ArrayRef<unsigned> Opcodes =
2970 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2973 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2975 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2976 AArch64::STLRW, AArch64::STLRX};
2981 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2982 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2983 I.getOperand(0).setReg(NewVal);
2985 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2993 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2996 "Load/Store pointer operand isn't a GPR");
2998 "Load/Store pointer operand isn't a pointer");
3003 LLT ValTy = MRI.
getType(ValReg);
3010 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3016 .addReg(ValReg, {}, SubReg)
3023 if (RB.
getID() == AArch64::FPRRegBankID) {
3026 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3036 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3039 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3048 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3050 const unsigned NewOpc =
3052 if (NewOpc ==
I.getOpcode())
3056 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3059 I.setDesc(
TII.get(NewOpc));
3065 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3066 Register CurValReg =
I.getOperand(0).getReg();
3067 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3068 NewInst.cloneMemRefs(
I);
3069 for (
auto &Fn : *AddrModeFns)
3071 I.eraseFromParent();
3075 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3080 if (Opcode == TargetOpcode::G_STORE) {
3082 LoadStore->getOperand(0).getReg(), MRI);
3083 if (CVal && CVal->Value == 0) {
3085 case AArch64::STRWui:
3086 case AArch64::STRHHui:
3087 case AArch64::STRBBui:
3088 LoadStore->getOperand(0).setReg(AArch64::WZR);
3090 case AArch64::STRXui:
3091 LoadStore->getOperand(0).setReg(AArch64::XZR);
3097 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3098 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3110 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3112 .
addImm(AArch64::sub_32);
3121 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3122 case TargetOpcode::G_INDEXED_SEXTLOAD:
3123 return selectIndexedExtLoad(
I, MRI);
3124 case TargetOpcode::G_INDEXED_LOAD:
3125 return selectIndexedLoad(
I, MRI);
3126 case TargetOpcode::G_INDEXED_STORE:
3129 case TargetOpcode::G_LSHR:
3130 case TargetOpcode::G_ASHR:
3132 return selectVectorAshrLshr(
I, MRI);
3134 case TargetOpcode::G_SHL:
3135 if (Opcode == TargetOpcode::G_SHL &&
3137 return selectVectorSHL(
I, MRI);
3144 Register SrcReg =
I.getOperand(1).getReg();
3145 Register ShiftReg =
I.getOperand(2).getReg();
3146 const LLT ShiftTy = MRI.
getType(ShiftReg);
3147 const LLT SrcTy = MRI.
getType(SrcReg);
3152 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3153 .addReg(ShiftReg, {}, AArch64::sub_32);
3155 I.getOperand(2).setReg(Trunc.getReg(0));
3159 case TargetOpcode::G_OR: {
3166 const Register DefReg =
I.getOperand(0).getReg();
3170 if (NewOpc ==
I.getOpcode())
3173 I.setDesc(
TII.get(NewOpc));
3182 case TargetOpcode::G_PTR_ADD: {
3183 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3184 I.eraseFromParent();
3188 case TargetOpcode::G_SADDE:
3189 case TargetOpcode::G_UADDE:
3190 case TargetOpcode::G_SSUBE:
3191 case TargetOpcode::G_USUBE:
3192 case TargetOpcode::G_SADDO:
3193 case TargetOpcode::G_UADDO:
3194 case TargetOpcode::G_SSUBO:
3195 case TargetOpcode::G_USUBO:
3196 return selectOverflowOp(
I, MRI);
3198 case TargetOpcode::G_PTRMASK: {
3199 Register MaskReg =
I.getOperand(2).getReg();
3205 uint64_t
Mask = *MaskVal;
3206 I.setDesc(
TII.get(AArch64::ANDXri));
3207 I.getOperand(2).ChangeToImmediate(
3213 case TargetOpcode::G_PTRTOINT:
3214 case TargetOpcode::G_TRUNC: {
3215 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3216 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3218 const Register DstReg =
I.getOperand(0).getReg();
3219 const Register SrcReg =
I.getOperand(1).getReg();
3221 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3222 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3226 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3230 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3231 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3235 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3241 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3245 if (DstRC == SrcRC) {
3247 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3251 }
else if (DstRC == &AArch64::GPR32RegClass &&
3252 SrcRC == &AArch64::GPR64RegClass) {
3253 I.getOperand(1).setSubReg(AArch64::sub_32);
3256 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3260 I.setDesc(
TII.get(TargetOpcode::COPY));
3262 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3265 I.setDesc(
TII.get(AArch64::XTNv4i16));
3271 MachineInstr *Extract = emitExtractVectorElt(
3275 I.eraseFromParent();
3280 if (Opcode == TargetOpcode::G_PTRTOINT) {
3281 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3282 I.setDesc(
TII.get(TargetOpcode::COPY));
3290 case TargetOpcode::G_ANYEXT: {
3291 if (selectUSMovFromExtend(
I, MRI))
3294 const Register DstReg =
I.getOperand(0).getReg();
3295 const Register SrcReg =
I.getOperand(1).getReg();
3297 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3298 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3300 <<
", expected: GPR\n");
3304 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3305 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3307 <<
", expected: GPR\n");
3314 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3318 if (DstSize != 64 && DstSize > 32) {
3320 <<
", expected: 32 or 64\n");
3330 .
addImm(AArch64::sub_32);
3331 I.getOperand(1).setReg(ExtSrc);
3336 case TargetOpcode::G_ZEXT:
3337 case TargetOpcode::G_SEXT_INREG:
3338 case TargetOpcode::G_SEXT: {
3339 if (selectUSMovFromExtend(
I, MRI))
3342 unsigned Opcode =
I.getOpcode();
3343 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3344 const Register DefReg =
I.getOperand(0).getReg();
3345 Register SrcReg =
I.getOperand(1).getReg();
3346 const LLT DstTy = MRI.
getType(DefReg);
3347 const LLT SrcTy = MRI.
getType(SrcReg);
3353 if (Opcode == TargetOpcode::G_SEXT_INREG)
3354 SrcSize =
I.getOperand(2).getImm();
3360 AArch64::GPRRegBankID &&
3361 "Unexpected ext regbank");
3372 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3375 if (LoadMI && IsGPR) {
3376 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3377 unsigned BytesLoaded = MemOp->getSize().getValue();
3384 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3387 const Register ZReg = AArch64::WZR;
3388 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3391 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3392 .addUse(SubregToRegSrc)
3393 .
addImm(AArch64::sub_32);
3397 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3407 I.eraseFromParent();
3412 if (DstSize == 64) {
3413 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3421 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3422 {&AArch64::GPR64RegClass}, {})
3428 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3432 }
else if (DstSize <= 32) {
3433 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3442 I.eraseFromParent();
3446 case TargetOpcode::G_FREEZE:
3449 case TargetOpcode::G_INTTOPTR:
3454 case TargetOpcode::G_BITCAST:
3462 case TargetOpcode::G_SELECT: {
3464 const Register CondReg = Sel.getCondReg();
3466 const Register FReg = Sel.getFalseReg();
3468 if (tryOptSelect(Sel))
3474 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3479 Sel.eraseFromParent();
3482 case TargetOpcode::G_ICMP: {
3492 auto &PredOp =
I.getOperand(1);
3493 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3497 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3498 AArch64::WZR, InvCC, MIB);
3499 I.eraseFromParent();
3503 case TargetOpcode::G_FCMP: {
3506 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3508 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3510 I.eraseFromParent();
3513 case TargetOpcode::G_VASTART:
3515 : selectVaStartAAPCS(
I, MF, MRI);
3516 case TargetOpcode::G_INTRINSIC:
3517 return selectIntrinsic(
I, MRI);
3518 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3519 return selectIntrinsicWithSideEffects(
I, MRI);
3520 case TargetOpcode::G_IMPLICIT_DEF: {
3521 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3522 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3523 const Register DstReg =
I.getOperand(0).getReg();
3524 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3525 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3529 case TargetOpcode::G_BLOCK_ADDR: {
3530 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3531 if (std::optional<uint16_t> BADisc =
3533 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3534 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3543 AArch64::GPR64RegClass, MRI);
3544 I.eraseFromParent();
3548 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3549 I.eraseFromParent();
3552 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3553 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3554 I.getOperand(0).getReg())
3558 I.getOperand(1).getBlockAddress(), 0,
3560 I.eraseFromParent();
3565 case AArch64::G_DUP: {
3572 AArch64::GPRRegBankID)
3574 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3576 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3578 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3580 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3582 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3588 case TargetOpcode::G_BUILD_VECTOR:
3589 return selectBuildVector(
I, MRI);
3590 case TargetOpcode::G_MERGE_VALUES:
3592 case TargetOpcode::G_UNMERGE_VALUES:
3594 case TargetOpcode::G_SHUFFLE_VECTOR:
3595 return selectShuffleVector(
I, MRI);
3596 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3597 return selectExtractElt(
I, MRI);
3598 case TargetOpcode::G_CONCAT_VECTORS:
3599 return selectConcatVectors(
I, MRI);
3600 case TargetOpcode::G_JUMP_TABLE:
3601 return selectJumpTable(
I, MRI);
3602 case TargetOpcode::G_MEMCPY:
3603 case TargetOpcode::G_MEMCPY_INLINE:
3604 case TargetOpcode::G_MEMMOVE:
3605 case TargetOpcode::G_MEMSET:
3606 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3607 return selectMOPS(
I, MRI);
3613bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3614 MachineIRBuilderState OldMIBState = MIB.
getState();
3620bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3621 MachineRegisterInfo &MRI) {
3624 case TargetOpcode::G_MEMCPY:
3625 case TargetOpcode::G_MEMCPY_INLINE:
3626 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3628 case TargetOpcode::G_MEMMOVE:
3629 Mopcode = AArch64::MOPSMemoryMovePseudo;
3631 case TargetOpcode::G_MEMSET:
3633 Mopcode = AArch64::MOPSMemorySetPseudo;
3646 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3647 const auto &SrcValRegClass =
3648 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3666 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3667 {DstPtrCopy, SizeCopy, SrcValCopy});
3670 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3671 {DstPtrCopy, SrcValCopy, SizeCopy});
3678bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3679 MachineRegisterInfo &MRI) {
3680 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3681 Register JTAddr =
I.getOperand(0).getReg();
3682 unsigned JTI =
I.getOperand(1).getIndex();
3685 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3697 "jump table hardening only supported on MachO/ELF");
3705 I.eraseFromParent();
3712 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3713 {TargetReg, ScratchReg}, {JTAddr,
Index})
3714 .addJumpTableIndex(JTI);
3716 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3717 {
static_cast<int64_t
>(JTI)});
3719 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3720 I.eraseFromParent();
3725bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3726 MachineRegisterInfo &MRI) {
3727 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3728 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3730 Register DstReg =
I.getOperand(0).getReg();
3731 unsigned JTI =
I.getOperand(1).getIndex();
3734 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3737 I.eraseFromParent();
3742bool AArch64InstructionSelector::selectTLSGlobalValue(
3743 MachineInstr &
I, MachineRegisterInfo &MRI) {
3746 MachineFunction &MF = *
I.getParent()->getParent();
3749 const auto &GlobalOp =
I.getOperand(1);
3750 assert(GlobalOp.getOffset() == 0 &&
3751 "Shouldn't have an offset on TLS globals!");
3752 const GlobalValue &GV = *GlobalOp.getGlobal();
3755 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3758 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3759 {LoadGOT.getReg(0)})
3770 assert(Opcode == AArch64::BLR);
3771 Opcode = AArch64::BLRAAZ;
3775 .addUse(AArch64::X0, RegState::Implicit)
3776 .
addDef(AArch64::X0, RegState::Implicit)
3782 I.eraseFromParent();
3786MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3787 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3788 MachineIRBuilder &MIRBuilder)
const {
3789 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3791 auto BuildFn = [&](
unsigned SubregIndex) {
3795 .addImm(SubregIndex);
3803 return BuildFn(AArch64::bsub);
3805 return BuildFn(AArch64::hsub);
3807 return BuildFn(AArch64::ssub);
3809 return BuildFn(AArch64::dsub);
3816AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3817 MachineIRBuilder &MIB,
3818 MachineRegisterInfo &MRI)
const {
3819 LLT DstTy = MRI.
getType(DstReg);
3820 const TargetRegisterClass *RC =
3821 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3822 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3826 unsigned SubReg = 0;
3829 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3835 .addReg(SrcReg, {}, SubReg);
3840bool AArch64InstructionSelector::selectMergeValues(
3841 MachineInstr &
I, MachineRegisterInfo &MRI) {
3842 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3843 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3844 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3846 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3848 if (
I.getNumOperands() != 3)
3855 Register DstReg =
I.getOperand(0).getReg();
3856 Register Src1Reg =
I.getOperand(1).getReg();
3857 Register Src2Reg =
I.getOperand(2).getReg();
3858 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3859 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3863 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3864 Src2Reg, 1, RB, MIB);
3869 I.eraseFromParent();
3873 if (RB.
getID() != AArch64::GPRRegBankID)
3879 auto *DstRC = &AArch64::GPR64RegClass;
3881 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3882 TII.get(TargetOpcode::SUBREG_TO_REG))
3884 .
addUse(
I.getOperand(1).getReg())
3885 .
addImm(AArch64::sub_32);
3888 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3889 TII.get(TargetOpcode::SUBREG_TO_REG))
3891 .
addUse(
I.getOperand(2).getReg())
3892 .
addImm(AArch64::sub_32);
3894 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3895 .
addDef(
I.getOperand(0).getReg())
3903 I.eraseFromParent();
3908 const unsigned EltSize) {
3913 CopyOpc = AArch64::DUPi8;
3914 ExtractSubReg = AArch64::bsub;
3917 CopyOpc = AArch64::DUPi16;
3918 ExtractSubReg = AArch64::hsub;
3921 CopyOpc = AArch64::DUPi32;
3922 ExtractSubReg = AArch64::ssub;
3925 CopyOpc = AArch64::DUPi64;
3926 ExtractSubReg = AArch64::dsub;
3930 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3936MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3937 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3938 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3939 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3940 unsigned CopyOpc = 0;
3941 unsigned ExtractSubReg = 0;
3944 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3948 const TargetRegisterClass *DstRC =
3949 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3951 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3955 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3956 const LLT &VecTy = MRI.
getType(VecReg);
3957 const TargetRegisterClass *VecRC =
3958 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3960 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3970 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3971 .addReg(VecReg, {}, ExtractSubReg);
3980 MachineInstr *ScalarToVector = emitScalarToVector(
3981 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3982 if (!ScalarToVector)
3987 MachineInstr *LaneCopyMI =
3988 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3996bool AArch64InstructionSelector::selectExtractElt(
3997 MachineInstr &
I, MachineRegisterInfo &MRI) {
3998 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3999 "unexpected opcode!");
4000 Register DstReg =
I.getOperand(0).getReg();
4001 const LLT NarrowTy = MRI.
getType(DstReg);
4002 const Register SrcReg =
I.getOperand(1).getReg();
4003 const LLT WideTy = MRI.
getType(SrcReg);
4006 "source register size too small!");
4007 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4010 MachineOperand &LaneIdxOp =
I.getOperand(2);
4011 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4022 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4025 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4026 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4031 I.eraseFromParent();
4035bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4036 MachineInstr &
I, MachineRegisterInfo &MRI) {
4037 unsigned NumElts =
I.getNumOperands() - 1;
4038 Register SrcReg =
I.getOperand(NumElts).getReg();
4039 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4040 const LLT SrcTy = MRI.
getType(SrcReg);
4042 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4044 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4050 const RegisterBank &DstRB =
4054 MachineInstr *Extract =
4055 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4059 I.eraseFromParent();
4063bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4064 MachineRegisterInfo &MRI) {
4065 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4066 "unexpected opcode");
4070 AArch64::FPRRegBankID ||
4072 AArch64::FPRRegBankID) {
4073 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4074 "currently unsupported.\n");
4080 unsigned NumElts =
I.getNumOperands() - 1;
4081 Register SrcReg =
I.getOperand(NumElts).getReg();
4082 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4083 const LLT WideTy = MRI.
getType(SrcReg);
4086 "source register size too small!");
4089 return selectSplitVectorUnmerge(
I, MRI);
4093 unsigned CopyOpc = 0;
4094 unsigned ExtractSubReg = 0;
4105 unsigned NumInsertRegs = NumElts - 1;
4118 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4120 unsigned SubReg = 0;
4123 assert(Found &&
"expected to find last operand's subeg idx");
4124 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4126 MachineInstr &ImpDefMI =
4127 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4132 MachineInstr &InsMI =
4134 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4151 Register CopyTo =
I.getOperand(0).getReg();
4152 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4153 .addReg(InsertRegs[0], {}, ExtractSubReg);
4157 unsigned LaneIdx = 1;
4158 for (
Register InsReg : InsertRegs) {
4159 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4160 MachineInstr &CopyInst =
4171 const TargetRegisterClass *RC =
4179 I.eraseFromParent();
4183bool AArch64InstructionSelector::selectConcatVectors(
4184 MachineInstr &
I, MachineRegisterInfo &MRI) {
4185 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4186 "Unexpected opcode");
4187 Register Dst =
I.getOperand(0).getReg();
4188 Register Op1 =
I.getOperand(1).getReg();
4189 Register Op2 =
I.getOperand(2).getReg();
4190 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4193 I.eraseFromParent();
4198AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4199 MachineFunction &MF)
const {
4207MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4208 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4209 const TargetRegisterClass *RC;
4215 RC = &AArch64::FPR128RegClass;
4216 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4219 RC = &AArch64::FPR64RegClass;
4220 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4223 RC = &AArch64::FPR32RegClass;
4224 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4227 RC = &AArch64::FPR16RegClass;
4228 Opc = AArch64::LDRHui;
4231 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4236 MachineInstr *LoadMI =
nullptr;
4237 auto &MF = MIRBuilder.
getMF();
4238 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4239 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4241 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4244 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4248 .addConstantPoolIndex(
4264static std::pair<unsigned, unsigned>
4266 unsigned Opc, SubregIdx;
4267 if (RB.
getID() == AArch64::GPRRegBankID) {
4269 Opc = AArch64::INSvi8gpr;
4270 SubregIdx = AArch64::bsub;
4271 }
else if (EltSize == 16) {
4272 Opc = AArch64::INSvi16gpr;
4273 SubregIdx = AArch64::ssub;
4274 }
else if (EltSize == 32) {
4275 Opc = AArch64::INSvi32gpr;
4276 SubregIdx = AArch64::ssub;
4277 }
else if (EltSize == 64) {
4278 Opc = AArch64::INSvi64gpr;
4279 SubregIdx = AArch64::dsub;
4285 Opc = AArch64::INSvi8lane;
4286 SubregIdx = AArch64::bsub;
4287 }
else if (EltSize == 16) {
4288 Opc = AArch64::INSvi16lane;
4289 SubregIdx = AArch64::hsub;
4290 }
else if (EltSize == 32) {
4291 Opc = AArch64::INSvi32lane;
4292 SubregIdx = AArch64::ssub;
4293 }
else if (EltSize == 64) {
4294 Opc = AArch64::INSvi64lane;
4295 SubregIdx = AArch64::dsub;
4300 return std::make_pair(
Opc, SubregIdx);
4303MachineInstr *AArch64InstructionSelector::emitInstr(
4304 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4305 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4306 const ComplexRendererFns &RenderFns)
const {
4307 assert(Opcode &&
"Expected an opcode?");
4309 "Function should only be used to produce selected instructions!");
4310 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4312 for (
auto &Fn : *RenderFns)
4318MachineInstr *AArch64InstructionSelector::emitAddSub(
4319 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4321 MachineIRBuilder &MIRBuilder)
const {
4323 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4327 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4328 bool Is32Bit =
Size == 32;
4331 if (
auto Fns = selectArithImmed(
RHS))
4332 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4336 if (
auto Fns = selectNegArithImmed(
RHS))
4337 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4341 if (
auto Fns = selectArithExtendedRegister(
RHS))
4342 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4346 if (
auto Fns = selectShiftedRegister(
RHS))
4347 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4349 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4354AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4355 MachineOperand &
RHS,
4356 MachineIRBuilder &MIRBuilder)
const {
4357 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4358 {{AArch64::ADDXri, AArch64::ADDWri},
4359 {AArch64::ADDXrs, AArch64::ADDWrs},
4360 {AArch64::ADDXrr, AArch64::ADDWrr},
4361 {AArch64::SUBXri, AArch64::SUBWri},
4362 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4363 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4367AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4368 MachineOperand &
RHS,
4369 MachineIRBuilder &MIRBuilder)
const {
4370 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4371 {{AArch64::ADDSXri, AArch64::ADDSWri},
4372 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4373 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4374 {AArch64::SUBSXri, AArch64::SUBSWri},
4375 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4376 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4380AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4381 MachineOperand &
RHS,
4382 MachineIRBuilder &MIRBuilder)
const {
4383 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4384 {{AArch64::SUBSXri, AArch64::SUBSWri},
4385 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4386 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4387 {AArch64::ADDSXri, AArch64::ADDSWri},
4388 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4389 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4393AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4394 MachineOperand &
RHS,
4395 MachineIRBuilder &MIRBuilder)
const {
4396 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4397 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4399 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4400 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4404AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4405 MachineOperand &
RHS,
4406 MachineIRBuilder &MIRBuilder)
const {
4407 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4408 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4410 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4411 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4415AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4416 MachineIRBuilder &MIRBuilder)
const {
4419 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4424AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4425 MachineIRBuilder &MIRBuilder)
const {
4428 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4433AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4434 MachineIRBuilder &MIRBuilder)
const {
4435 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4439 bool Is32Bit = (
RegSize == 32);
4440 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4441 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4442 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4446 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4449 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4456 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4457 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4458 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4461MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4462 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4463 MachineIRBuilder &MIRBuilder)
const {
4464 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4471 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4473 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4475 return emitCMP(
LHS,
RHS, MIRBuilder);
4478MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4480 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4484 "Expected a 32-bit scalar register?");
4486 const Register ZReg = AArch64::WZR;
4491 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4493 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4497 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4498 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4499 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4504MachineInstr *AArch64InstructionSelector::emitFPCompare(
4506 std::optional<CmpInst::Predicate> Pred)
const {
4507 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4512 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4523 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4527 ShouldUseImm =
true;
4531 unsigned CmpOpcTbl[2][3] = {
4532 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4533 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4535 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4547MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4549 MachineIRBuilder &MIRBuilder)
const {
4556 const LLT Op1Ty = MRI.
getType(Op1);
4557 const LLT Op2Ty = MRI.
getType(Op2);
4559 if (Op1Ty != Op2Ty) {
4560 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4563 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4566 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4577 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4578 const TargetRegisterClass *DstRC =
4581 MachineInstr *WidenedOp1 =
4582 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4583 MachineInstr *WidenedOp2 =
4584 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4585 if (!WidenedOp1 || !WidenedOp2) {
4586 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4591 unsigned InsertOpc, InsSubRegIdx;
4592 std::tie(InsertOpc, InsSubRegIdx) =
4610 MachineIRBuilder &MIRBuilder)
const {
4611 auto &MRI = *MIRBuilder.
getMRI();
4617 Size =
TRI.getRegSizeInBits(*RC);
4621 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4622 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4623 unsigned Opc = OpcTable[
Size == 64];
4624 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4629MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4631 MachineRegisterInfo *MRI = MIB.
getMRI();
4632 unsigned Opcode =
I.getOpcode();
4636 bool NeedsNegatedCarry =
4637 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4646 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4647 if (SrcMI ==
I.getPrevNode()) {
4649 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4650 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4651 CarrySrcMI->isUnsigned() &&
4652 CarrySrcMI->getCarryOutReg() == CarryReg &&
4653 selectAndRestoreState(*SrcMI))
4660 if (NeedsNegatedCarry) {
4663 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4667 auto Fns = select12BitValueWithLeftShift(1);
4668 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4671bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4672 MachineRegisterInfo &MRI) {
4677 emitCarryIn(
I, CarryInMI->getCarryInReg());
4681 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4682 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4684 Register CarryOutReg = CarryMI.getCarryOutReg();
4693 emitCSINC(CarryOutReg, ZReg, ZReg,
4694 getInvertedCondCode(OpAndCC.second), MIB);
4697 I.eraseFromParent();
4701std::pair<MachineInstr *, AArch64CC::CondCode>
4702AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4703 MachineOperand &
LHS,
4704 MachineOperand &
RHS,
4705 MachineIRBuilder &MIRBuilder)
const {
4709 case TargetOpcode::G_SADDO:
4711 case TargetOpcode::G_UADDO:
4713 case TargetOpcode::G_SSUBO:
4715 case TargetOpcode::G_USUBO:
4717 case TargetOpcode::G_SADDE:
4719 case TargetOpcode::G_UADDE:
4721 case TargetOpcode::G_SSUBE:
4723 case TargetOpcode::G_USUBE:
4744 unsigned Depth = 0) {
4751 MustBeFirst =
false;
4757 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4758 bool IsOR = Opcode == TargetOpcode::G_OR;
4770 if (MustBeFirstL && MustBeFirstR)
4776 if (!CanNegateL && !CanNegateR)
4780 CanNegate = WillNegate && CanNegateL && CanNegateR;
4783 MustBeFirst = !CanNegate;
4785 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4788 MustBeFirst = MustBeFirstL || MustBeFirstR;
4795MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4798 MachineIRBuilder &MIB)
const {
4799 auto &MRI = *MIB.
getMRI();
4802 std::optional<ValueAndVReg>
C;
4806 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4807 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4808 else if (
C->Value.ule(31))
4809 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4811 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4817 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4818 CCmpOpc = AArch64::FCCMPHrr;
4821 CCmpOpc = AArch64::FCCMPSrr;
4824 CCmpOpc = AArch64::FCCMPDrr;
4834 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4835 CCmp.
addImm(
C->Value.getZExtValue());
4836 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4837 CCmp.
addImm(
C->Value.abs().getZExtValue());
4845MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4849 auto &MRI = *MIB.
getMRI();
4867 MachineInstr *ExtraCmp;
4869 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4881 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4882 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4883 Cmp->getOperand(3).getReg(), MIB);
4890 bool IsOR = Opcode == TargetOpcode::G_OR;
4896 assert(ValidL &&
"Valid conjunction/disjunction tree");
4903 assert(ValidR &&
"Valid conjunction/disjunction tree");
4908 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4917 bool NegateAfterAll;
4918 if (Opcode == TargetOpcode::G_OR) {
4921 assert(CanNegateR &&
"at least one side must be negatable");
4922 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4926 NegateAfterR =
true;
4929 NegateR = CanNegateR;
4930 NegateAfterR = !CanNegateR;
4933 NegateAfterAll = !Negate;
4935 assert(Opcode == TargetOpcode::G_AND &&
4936 "Valid conjunction/disjunction tree");
4937 assert(!Negate &&
"Valid conjunction/disjunction tree");
4941 NegateAfterR =
false;
4942 NegateAfterAll =
false;
4947 MachineInstr *CmpR =
4958MachineInstr *AArch64InstructionSelector::emitConjunction(
4960 bool DummyCanNegate;
4961 bool DummyMustBeFirst;
4968bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4969 MachineInstr &CondMI) {
4980bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4981 MachineRegisterInfo &MRI = *MIB.
getMRI();
5000 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5009 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5015 unsigned CondOpc = CondDef->
getOpcode();
5016 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5017 if (tryOptSelectConjunction(
I, *CondDef))
5023 if (CondOpc == TargetOpcode::G_ICMP) {
5052 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5053 I.getOperand(3).getReg(), CondCode, MIB);
5054 I.eraseFromParent();
5058MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5059 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5060 MachineIRBuilder &MIRBuilder)
const {
5062 "Unexpected MachineOperand");
5063 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5086 if (
isCMN(RHSDef,
P, MRI))
5101 if (
isCMN(LHSDef,
P, MRI)) {
5118 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5121 if (!ValAndVReg || ValAndVReg->Value != 0)
5131bool AArch64InstructionSelector::selectShuffleVector(
5132 MachineInstr &
I, MachineRegisterInfo &MRI) {
5133 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5134 Register Src1Reg =
I.getOperand(1).getReg();
5135 Register Src2Reg =
I.getOperand(2).getReg();
5136 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5145 for (
int Val : Mask) {
5148 Val = Val < 0 ? 0 : Val;
5149 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5167 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5174 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5178 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5183 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5184 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5186 I.eraseFromParent();
5194 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5197 I.eraseFromParent();
5201MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5203 unsigned LaneIdx,
const RegisterBank &RB,
5204 MachineIRBuilder &MIRBuilder)
const {
5205 MachineInstr *InsElt =
nullptr;
5206 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5207 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5216 if (RB.
getID() == AArch64::FPRRegBankID) {
5217 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5220 .
addUse(InsSub->getOperand(0).getReg())
5232bool AArch64InstructionSelector::selectUSMovFromExtend(
5233 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5234 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5235 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5236 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5238 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5239 const Register DefReg =
MI.getOperand(0).getReg();
5240 const LLT DstTy = MRI.
getType(DefReg);
5243 if (DstSize != 32 && DstSize != 64)
5246 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5247 MI.getOperand(1).getReg(), MRI);
5253 const LLT VecTy = MRI.
getType(Src0);
5258 const MachineInstr *ScalarToVector = emitScalarToVector(
5259 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5260 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5266 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5268 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5270 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5272 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5274 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5282 MachineInstr *ExtI =
nullptr;
5283 if (DstSize == 64 && !IsSigned) {
5285 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5286 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5288 .
addImm(AArch64::sub_32);
5291 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5294 MI.eraseFromParent();
5298MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5299 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5301 if (DstSize == 128) {
5302 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5304 Op = AArch64::MOVIv16b_ns;
5306 Op = AArch64::MOVIv8b_ns;
5309 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5313 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5320MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5321 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5325 if (DstSize == 128) {
5326 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5328 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5330 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5333 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5350MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5351 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5355 if (DstSize == 128) {
5356 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5358 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5360 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5363 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5386MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5387 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5390 if (DstSize == 128) {
5391 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5393 Op = AArch64::MOVIv2d_ns;
5395 Op = AArch64::MOVID;
5398 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5401 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5408MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5409 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5413 if (DstSize == 128) {
5414 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5416 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5418 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5421 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5438MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5439 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5442 bool IsWide =
false;
5443 if (DstSize == 128) {
5444 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5446 Op = AArch64::FMOVv4f32_ns;
5449 Op = AArch64::FMOVv2f32_ns;
5452 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5458 Op = AArch64::FMOVv2f64_ns;
5462 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5467bool AArch64InstructionSelector::selectIndexedExtLoad(
5468 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5471 Register WriteBack = ExtLd.getWritebackReg();
5476 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5477 bool IsPre = ExtLd.isPre();
5479 unsigned InsertIntoSubReg = 0;
5485 if ((IsSExt && IsFPR) || Ty.
isVector())
5493 if (MemSizeBits == 8) {
5496 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5498 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5499 NewLdDstTy = IsDst64 ? s64 : s32;
5501 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5502 InsertIntoSubReg = AArch64::bsub;
5505 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5506 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5509 }
else if (MemSizeBits == 16) {
5512 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5514 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5515 NewLdDstTy = IsDst64 ? s64 : s32;
5517 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5518 InsertIntoSubReg = AArch64::hsub;
5521 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5522 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5525 }
else if (MemSizeBits == 32) {
5527 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5530 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5531 InsertIntoSubReg = AArch64::ssub;
5534 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5535 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5547 .addImm(Cst->getSExtValue());
5552 if (InsertIntoSubReg) {
5554 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5555 .addUse(LdMI.getReg(1))
5556 .
addImm(InsertIntoSubReg);
5559 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5566 MI.eraseFromParent();
5571bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5572 MachineRegisterInfo &MRI) {
5575 Register WriteBack = Ld.getWritebackReg();
5579 "Unexpected type for indexed load");
5580 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5583 return selectIndexedExtLoad(
MI, MRI);
5587 static constexpr unsigned GPROpcodes[] = {
5588 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5590 static constexpr unsigned FPROpcodes[] = {
5591 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5594 ? FPROpcodes[
Log2_32(MemSize)]
5595 : GPROpcodes[
Log2_32(MemSize)];
5598 static constexpr unsigned GPROpcodes[] = {
5599 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5601 static constexpr unsigned FPROpcodes[] = {
5602 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5603 AArch64::LDRDpost, AArch64::LDRQpost};
5605 ? FPROpcodes[
Log2_32(MemSize)]
5606 : GPROpcodes[
Log2_32(MemSize)];
5616 MI.eraseFromParent();
5620bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5621 MachineRegisterInfo &MRI) {
5627 "Unexpected type for indexed store");
5629 LocationSize MemSize =
I.getMMO().getSize();
5630 unsigned MemSizeInBytes = MemSize.
getValue();
5632 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5633 "Unexpected indexed store size");
5634 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5638 static constexpr unsigned GPROpcodes[] = {
5639 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5641 static constexpr unsigned FPROpcodes[] = {
5642 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5646 Opc = FPROpcodes[MemSizeLog2];
5648 Opc = GPROpcodes[MemSizeLog2];
5650 static constexpr unsigned GPROpcodes[] = {
5651 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5653 static constexpr unsigned FPROpcodes[] = {
5654 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5655 AArch64::STRDpost, AArch64::STRQpost};
5658 Opc = FPROpcodes[MemSizeLog2];
5660 Opc = GPROpcodes[MemSizeLog2];
5668 Str.cloneMemRefs(
I);
5670 I.eraseFromParent();
5675AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5676 MachineIRBuilder &MIRBuilder,
5677 MachineRegisterInfo &MRI) {
5680 assert((DstSize == 64 || DstSize == 128) &&
5681 "Unexpected vector constant size");
5684 if (DstSize == 128) {
5686 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5691 if (DstSize == 64) {
5694 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5697 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5704 APInt SplatValueAsInt =
5707 : SplatValue->getUniqueInteger();
5710 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5711 MachineInstr *NewOp;
5735 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5739 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5740 unsigned NegOpc) -> MachineInstr * {
5743 APInt NegBits(DstSize, 0);
5744 unsigned NumElts = DstSize / NumBits;
5745 for (
unsigned i = 0; i < NumElts; i++)
5746 NegBits |= Neg << (NumBits * i);
5747 NegBits = DefBits ^ NegBits;
5751 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5753 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5755 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5760 if ((R = TryWithFNeg(DefBits, 32,
5761 DstSize == 64 ? AArch64::FNEGv2f32
5762 : AArch64::FNEGv4f32)) ||
5763 (R = TryWithFNeg(DefBits, 64,
5764 DstSize == 64 ? AArch64::FNEGDr
5765 : AArch64::FNEGv2f64)) ||
5766 (STI.hasFullFP16() &&
5767 (R = TryWithFNeg(DefBits, 16,
5768 DstSize == 64 ? AArch64::FNEGv4f16
5769 : AArch64::FNEGv8f16))))
5775 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5779 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5781 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5785bool AArch64InstructionSelector::tryOptConstantBuildVec(
5786 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5787 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5789 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5795 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5796 Register OpReg =
I.getOperand(Idx).getReg();
5805 std::move(AnyConst->Value)));
5818 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5820 I.eraseFromParent();
5824bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5825 MachineInstr &
I, MachineRegisterInfo &MRI) {
5830 Register Dst =
I.getOperand(0).getReg();
5831 Register EltReg =
I.getOperand(1).getReg();
5832 LLT EltTy = MRI.
getType(EltReg);
5835 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5840 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5844 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5847 const TargetRegisterClass *DstRC =
5848 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5853 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5856 I.eraseFromParent();
5861bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5862 MachineRegisterInfo &MRI) {
5863 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5866 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5867 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5870 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5872 if (tryOptBuildVecToSubregToReg(
I, MRI))
5875 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5877 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5879 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5880 MachineInstr *ScalarToVec =
5882 I.getOperand(1).getReg(), MIB);
5891 MachineInstr *PrevMI = ScalarToVec;
5892 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5895 Register OpReg =
I.getOperand(i).getReg();
5898 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5905 if (DstSize < 128) {
5907 const TargetRegisterClass *RC =
5908 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5911 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5916 unsigned SubReg = 0;
5919 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5920 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5926 Register DstReg =
I.getOperand(0).getReg();
5928 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5929 MachineOperand &RegOp =
I.getOperand(1);
5949 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5950 const TargetRegisterClass *RC =
5951 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5960bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5963 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5965 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5966 auto &MRI = *MIB.
getMRI();
5967 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5970 "Destination must be 64 bits or 128 bits?");
5971 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5972 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5975 Load.cloneMemRefs(
I);
5977 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5978 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5979 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5980 .addReg(SelectedLoadDst, {}, SubReg + Idx);
5989bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5990 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5991 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5993 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5994 auto &MRI = *MIB.
getMRI();
5995 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5998 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6000 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6001 [](
auto MO) { return MO.getReg(); });
6005 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6020 .
addImm(LaneNo->getZExtValue())
6022 Load.cloneMemRefs(
I);
6024 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6025 unsigned SubReg = AArch64::qsub0;
6026 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6027 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6028 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6029 : DstOp(
I.getOperand(Idx).
getReg())},
6031 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6036 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6042void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6045 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6046 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6047 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6050 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6051 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6060bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6061 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6062 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6063 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6067 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6068 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6072 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6082 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6085 .
addImm(LaneNo->getZExtValue())
6092bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6093 MachineInstr &
I, MachineRegisterInfo &MRI) {
6106 case Intrinsic::aarch64_ldxp:
6107 case Intrinsic::aarch64_ldaxp: {
6109 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6110 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6116 case Intrinsic::aarch64_neon_ld1x2: {
6117 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6120 Opc = AArch64::LD1Twov8b;
6122 Opc = AArch64::LD1Twov16b;
6124 Opc = AArch64::LD1Twov4h;
6126 Opc = AArch64::LD1Twov8h;
6128 Opc = AArch64::LD1Twov2s;
6130 Opc = AArch64::LD1Twov4s;
6132 Opc = AArch64::LD1Twov2d;
6133 else if (Ty ==
S64 || Ty == P0)
6134 Opc = AArch64::LD1Twov1d;
6137 selectVectorLoadIntrinsic(
Opc, 2,
I);
6140 case Intrinsic::aarch64_neon_ld1x3: {
6141 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6144 Opc = AArch64::LD1Threev8b;
6146 Opc = AArch64::LD1Threev16b;
6148 Opc = AArch64::LD1Threev4h;
6150 Opc = AArch64::LD1Threev8h;
6152 Opc = AArch64::LD1Threev2s;
6154 Opc = AArch64::LD1Threev4s;
6156 Opc = AArch64::LD1Threev2d;
6157 else if (Ty ==
S64 || Ty == P0)
6158 Opc = AArch64::LD1Threev1d;
6161 selectVectorLoadIntrinsic(
Opc, 3,
I);
6164 case Intrinsic::aarch64_neon_ld1x4: {
6165 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6168 Opc = AArch64::LD1Fourv8b;
6170 Opc = AArch64::LD1Fourv16b;
6172 Opc = AArch64::LD1Fourv4h;
6174 Opc = AArch64::LD1Fourv8h;
6176 Opc = AArch64::LD1Fourv2s;
6178 Opc = AArch64::LD1Fourv4s;
6180 Opc = AArch64::LD1Fourv2d;
6181 else if (Ty ==
S64 || Ty == P0)
6182 Opc = AArch64::LD1Fourv1d;
6185 selectVectorLoadIntrinsic(
Opc, 4,
I);
6188 case Intrinsic::aarch64_neon_ld2: {
6189 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6192 Opc = AArch64::LD2Twov8b;
6194 Opc = AArch64::LD2Twov16b;
6196 Opc = AArch64::LD2Twov4h;
6198 Opc = AArch64::LD2Twov8h;
6200 Opc = AArch64::LD2Twov2s;
6202 Opc = AArch64::LD2Twov4s;
6204 Opc = AArch64::LD2Twov2d;
6205 else if (Ty ==
S64 || Ty == P0)
6206 Opc = AArch64::LD1Twov1d;
6209 selectVectorLoadIntrinsic(
Opc, 2,
I);
6212 case Intrinsic::aarch64_neon_ld2lane: {
6213 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6216 Opc = AArch64::LD2i8;
6218 Opc = AArch64::LD2i16;
6220 Opc = AArch64::LD2i32;
6223 Opc = AArch64::LD2i64;
6226 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6230 case Intrinsic::aarch64_neon_ld2r: {
6231 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6234 Opc = AArch64::LD2Rv8b;
6236 Opc = AArch64::LD2Rv16b;
6238 Opc = AArch64::LD2Rv4h;
6240 Opc = AArch64::LD2Rv8h;
6242 Opc = AArch64::LD2Rv2s;
6244 Opc = AArch64::LD2Rv4s;
6246 Opc = AArch64::LD2Rv2d;
6247 else if (Ty ==
S64 || Ty == P0)
6248 Opc = AArch64::LD2Rv1d;
6251 selectVectorLoadIntrinsic(
Opc, 2,
I);
6254 case Intrinsic::aarch64_neon_ld3: {
6255 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6258 Opc = AArch64::LD3Threev8b;
6260 Opc = AArch64::LD3Threev16b;
6262 Opc = AArch64::LD3Threev4h;
6264 Opc = AArch64::LD3Threev8h;
6266 Opc = AArch64::LD3Threev2s;
6268 Opc = AArch64::LD3Threev4s;
6270 Opc = AArch64::LD3Threev2d;
6271 else if (Ty ==
S64 || Ty == P0)
6272 Opc = AArch64::LD1Threev1d;
6275 selectVectorLoadIntrinsic(
Opc, 3,
I);
6278 case Intrinsic::aarch64_neon_ld3lane: {
6279 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6282 Opc = AArch64::LD3i8;
6284 Opc = AArch64::LD3i16;
6286 Opc = AArch64::LD3i32;
6289 Opc = AArch64::LD3i64;
6292 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6296 case Intrinsic::aarch64_neon_ld3r: {
6297 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6300 Opc = AArch64::LD3Rv8b;
6302 Opc = AArch64::LD3Rv16b;
6304 Opc = AArch64::LD3Rv4h;
6306 Opc = AArch64::LD3Rv8h;
6308 Opc = AArch64::LD3Rv2s;
6310 Opc = AArch64::LD3Rv4s;
6312 Opc = AArch64::LD3Rv2d;
6313 else if (Ty ==
S64 || Ty == P0)
6314 Opc = AArch64::LD3Rv1d;
6317 selectVectorLoadIntrinsic(
Opc, 3,
I);
6320 case Intrinsic::aarch64_neon_ld4: {
6321 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6324 Opc = AArch64::LD4Fourv8b;
6326 Opc = AArch64::LD4Fourv16b;
6328 Opc = AArch64::LD4Fourv4h;
6330 Opc = AArch64::LD4Fourv8h;
6332 Opc = AArch64::LD4Fourv2s;
6334 Opc = AArch64::LD4Fourv4s;
6336 Opc = AArch64::LD4Fourv2d;
6337 else if (Ty ==
S64 || Ty == P0)
6338 Opc = AArch64::LD1Fourv1d;
6341 selectVectorLoadIntrinsic(
Opc, 4,
I);
6344 case Intrinsic::aarch64_neon_ld4lane: {
6345 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6348 Opc = AArch64::LD4i8;
6350 Opc = AArch64::LD4i16;
6352 Opc = AArch64::LD4i32;
6355 Opc = AArch64::LD4i64;
6358 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6362 case Intrinsic::aarch64_neon_ld4r: {
6363 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6366 Opc = AArch64::LD4Rv8b;
6368 Opc = AArch64::LD4Rv16b;
6370 Opc = AArch64::LD4Rv4h;
6372 Opc = AArch64::LD4Rv8h;
6374 Opc = AArch64::LD4Rv2s;
6376 Opc = AArch64::LD4Rv4s;
6378 Opc = AArch64::LD4Rv2d;
6379 else if (Ty ==
S64 || Ty == P0)
6380 Opc = AArch64::LD4Rv1d;
6383 selectVectorLoadIntrinsic(
Opc, 4,
I);
6386 case Intrinsic::aarch64_neon_st1x2: {
6387 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6390 Opc = AArch64::ST1Twov8b;
6392 Opc = AArch64::ST1Twov16b;
6394 Opc = AArch64::ST1Twov4h;
6396 Opc = AArch64::ST1Twov8h;
6398 Opc = AArch64::ST1Twov2s;
6400 Opc = AArch64::ST1Twov4s;
6402 Opc = AArch64::ST1Twov2d;
6403 else if (Ty ==
S64 || Ty == P0)
6404 Opc = AArch64::ST1Twov1d;
6407 selectVectorStoreIntrinsic(
I, 2,
Opc);
6410 case Intrinsic::aarch64_neon_st1x3: {
6411 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6414 Opc = AArch64::ST1Threev8b;
6416 Opc = AArch64::ST1Threev16b;
6418 Opc = AArch64::ST1Threev4h;
6420 Opc = AArch64::ST1Threev8h;
6422 Opc = AArch64::ST1Threev2s;
6424 Opc = AArch64::ST1Threev4s;
6426 Opc = AArch64::ST1Threev2d;
6427 else if (Ty ==
S64 || Ty == P0)
6428 Opc = AArch64::ST1Threev1d;
6431 selectVectorStoreIntrinsic(
I, 3,
Opc);
6434 case Intrinsic::aarch64_neon_st1x4: {
6435 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6438 Opc = AArch64::ST1Fourv8b;
6440 Opc = AArch64::ST1Fourv16b;
6442 Opc = AArch64::ST1Fourv4h;
6444 Opc = AArch64::ST1Fourv8h;
6446 Opc = AArch64::ST1Fourv2s;
6448 Opc = AArch64::ST1Fourv4s;
6450 Opc = AArch64::ST1Fourv2d;
6451 else if (Ty ==
S64 || Ty == P0)
6452 Opc = AArch64::ST1Fourv1d;
6455 selectVectorStoreIntrinsic(
I, 4,
Opc);
6458 case Intrinsic::aarch64_neon_st2: {
6459 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6462 Opc = AArch64::ST2Twov8b;
6464 Opc = AArch64::ST2Twov16b;
6466 Opc = AArch64::ST2Twov4h;
6468 Opc = AArch64::ST2Twov8h;
6470 Opc = AArch64::ST2Twov2s;
6472 Opc = AArch64::ST2Twov4s;
6474 Opc = AArch64::ST2Twov2d;
6475 else if (Ty ==
S64 || Ty == P0)
6476 Opc = AArch64::ST1Twov1d;
6479 selectVectorStoreIntrinsic(
I, 2,
Opc);
6482 case Intrinsic::aarch64_neon_st3: {
6483 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6486 Opc = AArch64::ST3Threev8b;
6488 Opc = AArch64::ST3Threev16b;
6490 Opc = AArch64::ST3Threev4h;
6492 Opc = AArch64::ST3Threev8h;
6494 Opc = AArch64::ST3Threev2s;
6496 Opc = AArch64::ST3Threev4s;
6498 Opc = AArch64::ST3Threev2d;
6499 else if (Ty ==
S64 || Ty == P0)
6500 Opc = AArch64::ST1Threev1d;
6503 selectVectorStoreIntrinsic(
I, 3,
Opc);
6506 case Intrinsic::aarch64_neon_st4: {
6507 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6510 Opc = AArch64::ST4Fourv8b;
6512 Opc = AArch64::ST4Fourv16b;
6514 Opc = AArch64::ST4Fourv4h;
6516 Opc = AArch64::ST4Fourv8h;
6518 Opc = AArch64::ST4Fourv2s;
6520 Opc = AArch64::ST4Fourv4s;
6522 Opc = AArch64::ST4Fourv2d;
6523 else if (Ty ==
S64 || Ty == P0)
6524 Opc = AArch64::ST1Fourv1d;
6527 selectVectorStoreIntrinsic(
I, 4,
Opc);
6530 case Intrinsic::aarch64_neon_st2lane: {
6531 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6534 Opc = AArch64::ST2i8;
6536 Opc = AArch64::ST2i16;
6538 Opc = AArch64::ST2i32;
6541 Opc = AArch64::ST2i64;
6544 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6548 case Intrinsic::aarch64_neon_st3lane: {
6549 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6552 Opc = AArch64::ST3i8;
6554 Opc = AArch64::ST3i16;
6556 Opc = AArch64::ST3i32;
6559 Opc = AArch64::ST3i64;
6562 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6566 case Intrinsic::aarch64_neon_st4lane: {
6567 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6570 Opc = AArch64::ST4i8;
6572 Opc = AArch64::ST4i16;
6574 Opc = AArch64::ST4i32;
6577 Opc = AArch64::ST4i64;
6580 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6584 case Intrinsic::aarch64_mops_memset_tag: {
6597 Register DstDef =
I.getOperand(0).getReg();
6599 Register DstUse =
I.getOperand(2).getReg();
6600 Register ValUse =
I.getOperand(3).getReg();
6601 Register SizeUse =
I.getOperand(4).getReg();
6608 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6609 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6614 case Intrinsic::ptrauth_resign_load_relative: {
6615 Register DstReg =
I.getOperand(0).getReg();
6616 Register ValReg =
I.getOperand(2).getReg();
6617 uint64_t AUTKey =
I.getOperand(3).getImm();
6618 Register AUTDisc =
I.getOperand(4).getReg();
6619 uint64_t PACKey =
I.getOperand(5).getImm();
6620 Register PACDisc =
I.getOperand(6).getReg();
6621 int64_t Addend =
I.getOperand(7).getImm();
6624 uint16_t AUTConstDiscC = 0;
6625 std::tie(AUTConstDiscC, AUTAddrDisc) =
6629 uint16_t PACConstDiscC = 0;
6630 std::tie(PACConstDiscC, PACAddrDisc) =
6633 MIB.
buildCopy({AArch64::X16}, {ValReg});
6647 I.eraseFromParent();
6652 I.eraseFromParent();
6656bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6657 MachineRegisterInfo &MRI) {
6663 case Intrinsic::ptrauth_resign: {
6664 Register DstReg =
I.getOperand(0).getReg();
6665 Register ValReg =
I.getOperand(2).getReg();
6666 uint64_t AUTKey =
I.getOperand(3).getImm();
6667 Register AUTDisc =
I.getOperand(4).getReg();
6668 uint64_t PACKey =
I.getOperand(5).getImm();
6669 Register PACDisc =
I.getOperand(6).getReg();
6672 uint16_t AUTConstDiscC = 0;
6673 std::tie(AUTConstDiscC, AUTAddrDisc) =
6677 uint16_t PACConstDiscC = 0;
6678 std::tie(PACConstDiscC, PACAddrDisc) =
6681 MIB.
buildCopy({AArch64::X16}, {ValReg});
6682 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6694 I.eraseFromParent();
6697 case Intrinsic::ptrauth_auth: {
6698 Register DstReg =
I.getOperand(0).getReg();
6699 Register ValReg =
I.getOperand(2).getReg();
6700 uint64_t AUTKey =
I.getOperand(3).getImm();
6701 Register AUTDisc =
I.getOperand(4).getReg();
6704 uint16_t AUTConstDiscC = 0;
6705 std::tie(AUTConstDiscC, AUTAddrDisc) =
6709 MIB.
buildCopy({AArch64::X16}, {ValReg});
6710 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6731 I.eraseFromParent();
6734 case Intrinsic::frameaddress:
6735 case Intrinsic::returnaddress: {
6736 MachineFunction &MF = *
I.getParent()->getParent();
6739 unsigned Depth =
I.getOperand(2).getImm();
6740 Register DstReg =
I.getOperand(0).getReg();
6743 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6744 if (!MFReturnAddr) {
6749 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6752 if (STI.hasPAuth()) {
6753 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6760 I.eraseFromParent();
6769 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6771 FrameAddr = NextFrame;
6774 if (IntrinID == Intrinsic::frameaddress)
6779 if (STI.hasPAuth()) {
6781 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6782 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6791 I.eraseFromParent();
6794 case Intrinsic::aarch64_neon_tbl2:
6795 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6797 case Intrinsic::aarch64_neon_tbl3:
6798 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6801 case Intrinsic::aarch64_neon_tbl4:
6802 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6804 case Intrinsic::aarch64_neon_tbx2:
6805 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6807 case Intrinsic::aarch64_neon_tbx3:
6808 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6810 case Intrinsic::aarch64_neon_tbx4:
6811 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6813 case Intrinsic::swift_async_context_addr:
6814 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6821 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6822 I.eraseFromParent();
6857bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6858 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6859 Register DefReg =
I.getOperand(0).getReg();
6860 Register Addr =
I.getOperand(1).getReg();
6861 uint64_t
Key =
I.getOperand(2).getImm();
6862 Register AddrDisc =
I.getOperand(3).getReg();
6863 uint64_t Disc =
I.getOperand(4).getImm();
6873 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6889 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6901 const GlobalValue *GV;
6912 MachineIRBuilder MIB(
I);
6918 "unsupported non-GOT op flags on ptrauth global reference");
6920 "unsupported non-GOT reference to weak ptrauth global");
6923 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6930 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6931 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6932 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6935 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6940 I.eraseFromParent();
6952 "unsupported non-zero offset in weak ptrauth global reference");
6957 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6958 .addGlobalAddress(GV,
Offset)
6963 I.eraseFromParent();
6967void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6968 MachineRegisterInfo &MRI,
6969 unsigned NumVec,
unsigned Opc1,
6970 unsigned Opc2,
bool isExt) {
6971 Register DstReg =
I.getOperand(0).getReg();
6976 for (
unsigned i = 0; i < NumVec; i++)
6977 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6980 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6981 MachineInstrBuilder
Instr;
6988 I.eraseFromParent();
6991InstructionSelector::ComplexRendererFns
6992AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6994 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6995 return std::nullopt;
6996 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6997 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7000InstructionSelector::ComplexRendererFns
7001AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7003 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7004 return std::nullopt;
7005 uint64_t Enc = 31 - *MaybeImmed;
7006 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7009InstructionSelector::ComplexRendererFns
7010AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7012 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7013 return std::nullopt;
7014 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7015 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7018InstructionSelector::ComplexRendererFns
7019AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7021 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7022 return std::nullopt;
7023 uint64_t Enc = 63 - *MaybeImmed;
7024 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7032InstructionSelector::ComplexRendererFns
7033AArch64InstructionSelector::select12BitValueWithLeftShift(
7034 uint64_t Immed)
const {
7036 if (Immed >> 12 == 0) {
7038 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7040 Immed = Immed >> 12;
7042 return std::nullopt;
7046 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7047 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7054InstructionSelector::ComplexRendererFns
7055AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7062 if (MaybeImmed == std::nullopt)
7063 return std::nullopt;
7064 return select12BitValueWithLeftShift(*MaybeImmed);
7069InstructionSelector::ComplexRendererFns
7070AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7074 return std::nullopt;
7076 if (MaybeImmed == std::nullopt)
7077 return std::nullopt;
7078 uint64_t Immed = *MaybeImmed;
7084 return std::nullopt;
7090 Immed = ~((uint32_t)Immed) + 1;
7092 Immed = ~Immed + 1ULL;
7094 if (Immed & 0xFFFFFFFFFF000000ULL)
7095 return std::nullopt;
7097 Immed &= 0xFFFFFFULL;
7098 return select12BitValueWithLeftShift(Immed);
7115std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7116 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7117 if (
MI.getOpcode() == AArch64::G_SHL) {
7121 MI.getOperand(2).getReg(), MRI)) {
7122 const APInt ShiftVal = ValAndVeg->Value;
7125 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7128 return std::nullopt;
7136bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7137 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7138 bool IsAddrOperand)
const {
7143 MI.getParent()->getParent()->getFunction().hasOptSize())
7146 if (IsAddrOperand) {
7148 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7152 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7153 MachineInstr *OffsetInst =
7159 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7170 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7173InstructionSelector::ComplexRendererFns
7174AArch64InstructionSelector::selectExtendedSHL(
7175 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7176 unsigned SizeInBytes,
bool WantsExt)
const {
7177 assert(
Base.isReg() &&
"Expected base to be a register operand");
7178 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7183 unsigned OffsetOpc = OffsetInst->
getOpcode();
7184 bool LookedThroughZExt =
false;
7185 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7187 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7188 return std::nullopt;
7192 LookedThroughZExt =
true;
7194 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7195 return std::nullopt;
7198 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7199 if (LegalShiftVal == 0)
7200 return std::nullopt;
7201 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7202 return std::nullopt;
7213 if (OffsetOpc == TargetOpcode::G_SHL)
7214 return std::nullopt;
7220 return std::nullopt;
7225 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7229 if (OffsetOpc == TargetOpcode::G_MUL) {
7231 return std::nullopt;
7237 if ((ImmVal & 0x7) != ImmVal)
7238 return std::nullopt;
7242 if (ImmVal != LegalShiftVal)
7243 return std::nullopt;
7245 unsigned SignExtend = 0;
7249 if (!LookedThroughZExt) {
7251 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7253 return std::nullopt;
7258 return std::nullopt;
7264 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7269 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7270 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7271 [=](MachineInstrBuilder &MIB) {
7274 MIB.addImm(SignExtend);
7287InstructionSelector::ComplexRendererFns
7288AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7289 MachineOperand &Root,
unsigned SizeInBytes)
const {
7291 return std::nullopt;
7306 MachineInstr *PtrAdd =
7308 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7309 return std::nullopt;
7313 MachineInstr *OffsetInst =
7315 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7328InstructionSelector::ComplexRendererFns
7329AArch64InstructionSelector::selectAddrModeRegisterOffset(
7330 MachineOperand &Root)
const {
7335 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7336 return std::nullopt;
7342 return std::nullopt;
7345 return {{[=](MachineInstrBuilder &MIB) {
7348 [=](MachineInstrBuilder &MIB) {
7351 [=](MachineInstrBuilder &MIB) {
7361InstructionSelector::ComplexRendererFns
7362AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7363 unsigned SizeInBytes)
const {
7366 return std::nullopt;
7367 MachineInstr *PtrAdd =
7370 return std::nullopt;
7388 unsigned Scale =
Log2_32(SizeInBytes);
7389 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7393 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7394 ImmOff < (0x1000 << Scale))
7395 return std::nullopt;
7400 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7404 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7410 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7411 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7416 return std::nullopt;
7420 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7426 return selectAddrModeRegisterOffset(Root);
7435InstructionSelector::ComplexRendererFns
7436AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7437 unsigned SizeInBytes)
const {
7440 MachineInstr *PtrAdd =
7442 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7443 return std::nullopt;
7464 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7473 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7474 return std::nullopt;
7478 getExtendTypeForInst(*OffsetInst, MRI,
true);
7480 return std::nullopt;
7483 MachineIRBuilder MIB(*PtrAdd);
7485 AArch64::GPR32RegClass, MIB);
7489 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7490 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7491 [=](MachineInstrBuilder &MIB) {
7492 MIB.addImm(SignExtend);
7502InstructionSelector::ComplexRendererFns
7503AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7504 unsigned Size)
const {
7505 MachineRegisterInfo &MRI =
7509 return std::nullopt;
7511 if (!isBaseWithConstantOffset(Root, MRI))
7512 return std::nullopt;
7516 MachineOperand &OffImm = RootDef->
getOperand(2);
7517 if (!OffImm.
isReg())
7518 return std::nullopt;
7520 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7521 return std::nullopt;
7523 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7525 return std::nullopt;
7528 if (RHSC >= -256 && RHSC < 256) {
7531 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7532 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7535 return std::nullopt;
7538InstructionSelector::ComplexRendererFns
7539AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7541 MachineRegisterInfo &MRI)
const {
7542 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7543 return std::nullopt;
7546 return std::nullopt;
7551 return std::nullopt;
7555 return std::nullopt;
7559 return std::nullopt;
7562 MachineIRBuilder MIRBuilder(RootDef);
7564 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7565 [=](MachineInstrBuilder &MIB) {
7566 MIB.addGlobalAddress(GV,
Offset,
7575InstructionSelector::ComplexRendererFns
7576AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7577 unsigned Size)
const {
7582 return std::nullopt;
7585 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7587 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7588 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7596 MachineInstr *RootParent = Root.
getParent();
7598 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7600 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7605 if (isBaseWithConstantOffset(Root, MRI)) {
7613 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7614 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7616 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7617 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7621 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7622 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7629 if (selectAddrModeUnscaled(Root,
Size))
7630 return std::nullopt;
7633 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7634 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7641 switch (
MI.getOpcode()) {
7644 case TargetOpcode::G_SHL:
7646 case TargetOpcode::G_LSHR:
7648 case TargetOpcode::G_ASHR:
7650 case TargetOpcode::G_ROTR:
7657InstructionSelector::ComplexRendererFns
7658AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7659 bool AllowROR)
const {
7661 return std::nullopt;
7662 MachineRegisterInfo &MRI =
7670 return std::nullopt;
7672 return std::nullopt;
7673 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7674 return std::nullopt;
7677 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7680 return std::nullopt;
7684 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7688 unsigned Val = *Immed & (NumBits - 1);
7691 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7692 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7696 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7697 unsigned Opc =
MI.getOpcode();
7700 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7702 if (
Opc == TargetOpcode::G_SEXT)
7705 Size =
MI.getOperand(2).getImm();
7706 assert(
Size != 64 &&
"Extend from 64 bits?");
7719 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7721 assert(
Size != 64 &&
"Extend from 64 bits?");
7736 if (
Opc != TargetOpcode::G_AND)
7742 uint64_t AndMask = *MaybeAndMask;
7755Register AArch64InstructionSelector::moveScalarRegClass(
7756 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7757 MachineRegisterInfo &MRI = *MIB.
getMRI();
7767 return Copy.getReg(0);
7772InstructionSelector::ComplexRendererFns
7773AArch64InstructionSelector::selectArithExtendedRegister(
7774 MachineOperand &Root)
const {
7776 return std::nullopt;
7777 MachineRegisterInfo &MRI =
7780 uint64_t ShiftVal = 0;
7785 return std::nullopt;
7787 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7788 return std::nullopt;
7791 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7796 return std::nullopt;
7797 ShiftVal = *MaybeShiftVal;
7799 return std::nullopt;
7804 return std::nullopt;
7805 Ext = getExtendTypeForInst(*ExtDef, MRI);
7807 return std::nullopt;
7811 Ext = getExtendTypeForInst(*RootDef, MRI);
7813 return std::nullopt;
7821 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7822 if (isDef32(*ExtInst))
7823 return std::nullopt;
7829 MachineIRBuilder MIB(*RootDef);
7830 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7832 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7833 [=](MachineInstrBuilder &MIB) {
7834 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7838InstructionSelector::ComplexRendererFns
7839AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7841 return std::nullopt;
7842 MachineRegisterInfo &MRI =
7846 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7851 return std::nullopt;
7854 if (Unmerge->getNumDefs() == 2 &&
7856 Register ExtReg = Unmerge->getSourceReg();
7857 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7861 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7865 LaneIdx->Value.getSExtValue() == 1) {
7866 Register ExtReg = ExtElt->getVectorReg();
7867 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7871 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7872 auto LaneIdx = Subvec->getIndexImm();
7874 Register ExtReg = Subvec->getSrcVec();
7875 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7879 return std::nullopt;
7882InstructionSelector::ComplexRendererFns
7883AArch64InstructionSelector::selectCVTFixedPointVecBase(
7884 const MachineOperand &Root,
bool isReciprocal)
const {
7886 return std::nullopt;
7887 const MachineRegisterInfo &MRI =
7892 return std::nullopt;
7893 std::optional<ValueAndVReg> CstVal =
7896 return std::nullopt;
7902 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7905 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7908 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7911 return std::nullopt;
7913 if (
unsigned FBits =
7915 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7917 return std::nullopt;
7920InstructionSelector::ComplexRendererFns
7921AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
7922 return selectCVTFixedPointVecBase(Root,
false);
7925InstructionSelector::ComplexRendererFns
7926AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
7927 MachineOperand &Root)
const {
7928 return selectCVTFixedPointVecBase(Root,
true);
7931void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
7932 const MachineInstr &
MI,
7937 InstructionSelector::ComplexRendererFns Renderer =
7938 selectCVTFixedPointVecBase(
MI.getOperand(2),
false);
7939 assert((Renderer && Renderer->size() == 1) &&
7940 "Expected selectCVTFixedPointVec to provide a function\n");
7941 (Renderer->front())(MIB);
7944void AArch64InstructionSelector::renderFixedPointRecipXForm(
7945 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7946 InstructionSelector::ComplexRendererFns Renderer =
7947 selectCVTFixedPointVecBase(
MI.getOperand(2),
true);
7948 assert((Renderer && Renderer->size() == 1) &&
7949 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
7950 (Renderer->front())(MIB);
7953void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7954 const MachineInstr &
MI,
7956 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
7957 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7958 "Expected G_CONSTANT");
7959 std::optional<int64_t> CstVal =
7961 assert(CstVal &&
"Expected constant value");
7965void AArch64InstructionSelector::renderLogicalImm32(
7966 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7967 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7968 "Expected G_CONSTANT");
7969 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7974void AArch64InstructionSelector::renderLogicalImm64(
7975 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7976 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7977 "Expected G_CONSTANT");
7978 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7983void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7984 const MachineInstr &
MI,
7986 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7987 "Expected G_UBSANTRAP");
7988 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7991void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7992 const MachineInstr &
MI,
7994 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7995 "Expected G_FCONSTANT");
8000void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8001 const MachineInstr &
MI,
8003 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8004 "Expected G_FCONSTANT");
8009void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8010 const MachineInstr &
MI,
8012 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8013 "Expected G_FCONSTANT");
8018void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8019 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8020 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8021 "Expected G_FCONSTANT");
8029bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8030 const MachineInstr &
MI,
unsigned NumBytes)
const {
8031 if (!
MI.mayLoadOrStore())
8034 "Expected load/store to have only one mem op!");
8035 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8038bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8039 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8047 switch (
MI.getOpcode()) {
8050 case TargetOpcode::COPY:
8051 case TargetOpcode::G_BITCAST:
8052 case TargetOpcode::G_TRUNC:
8053 case TargetOpcode::G_PHI:
8063 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8066 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8084 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8089 MO.setReg(Copy.getReg(0));
8094void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8098 for (
auto &BB : MF) {
8099 for (
auto &
MI : BB) {
8100 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8105 for (
auto *
MI : Phis) {
8127 bool HasGPROp =
false, HasFPROp =
false;
8131 const LLT &Ty = MRI.
getType(MO.getReg());
8141 if (RB->
getID() == AArch64::GPRRegBankID)
8147 if (HasGPROp && HasFPROp)
8153InstructionSelector *
8157 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.
LLVM_ABI 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
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.