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;
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);
2151 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2152 I.getOperand(1).setCImm(
2157 I.getOperand(0).setReg(WideReg);
2166 if (PtrSize != 32 && PtrSize != 64)
2172 case TargetOpcode::G_STORE: {
2173 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2174 MachineOperand &SrcOp =
I.getOperand(0);
2187 case TargetOpcode::G_PTR_ADD: {
2191 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2193 return convertPtrAddToAdd(
I, MRI);
2195 case TargetOpcode::G_LOAD: {
2200 Register DstReg =
I.getOperand(0).getReg();
2201 const LLT DstTy = MRI.
getType(DstReg);
2207 case AArch64::G_DUP: {
2209 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2213 MRI.
setType(
I.getOperand(0).getReg(),
2215 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2216 I.getOperand(1).setReg(NewSrc.getReg(0));
2219 case AArch64::G_INSERT_VECTOR_ELT: {
2220 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2221 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2225 MRI.
setType(
I.getOperand(1).getReg(),
2227 MRI.
setType(
I.getOperand(0).getReg(),
2229 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2230 I.getOperand(2).setReg(NewSrc.getReg(0));
2234 Register EltReg =
I.getOperand(2).getReg();
2235 LLT EltTy = MRI.
getType(EltReg);
2241 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2242 I.getOperand(2).setReg(NewElt.getReg(0));
2247 case TargetOpcode::G_UITOFP:
2248 case TargetOpcode::G_SITOFP: {
2253 Register SrcReg =
I.getOperand(1).getReg();
2254 LLT SrcTy = MRI.
getType(SrcReg);
2255 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2264 I.getOperand(1).setReg(
Copy.getReg(0));
2266 getRegClassForTypeOnBank(
2267 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2269 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2270 I.setDesc(
TII.get(AArch64::G_SITOF));
2272 I.setDesc(
TII.get(AArch64::G_UITOF));
2290bool AArch64InstructionSelector::convertPtrAddToAdd(
2291 MachineInstr &
I, MachineRegisterInfo &MRI) {
2292 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2293 Register DstReg =
I.getOperand(0).getReg();
2294 Register AddOp1Reg =
I.getOperand(1).getReg();
2295 const LLT PtrTy = MRI.
getType(DstReg);
2299 const LLT CastPtrTy = PtrTy.
isVector()
2311 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2312 MRI.
setType(DstReg, CastPtrTy);
2313 I.getOperand(1).setReg(PtrToInt.getReg(0));
2314 if (!select(*PtrToInt)) {
2315 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2324 I.getOperand(2).setReg(NegatedReg);
2325 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2329bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2330 MachineRegisterInfo &MRI) {
2334 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2335 const auto &MO =
I.getOperand(2);
2340 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2344 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2345 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2347 if (!Imm1Fn || !Imm2Fn)
2351 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2352 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2354 for (
auto &RenderFn : *Imm1Fn)
2356 for (
auto &RenderFn : *Imm2Fn)
2359 I.eraseFromParent();
2364bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2365 MachineInstr &
I, MachineRegisterInfo &MRI) {
2366 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2384 LLT DefDstTy = MRI.
getType(DefDstReg);
2385 Register StoreSrcReg =
I.getOperand(0).getReg();
2386 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2402 I.getOperand(0).setReg(DefDstReg);
2406bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2407 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2408 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2414 switch (
I.getOpcode()) {
2415 case AArch64::G_DUP: {
2418 Register Src =
I.getOperand(1).getReg();
2420 Src, MRI,
true,
true);
2424 Register Dst =
I.getOperand(0).getReg();
2430 if (!emitConstantVector(Dst, CV, MIB, MRI))
2432 I.eraseFromParent();
2435 case TargetOpcode::G_SEXT:
2438 if (selectUSMovFromExtend(
I, MRI))
2441 case TargetOpcode::G_BR:
2443 case TargetOpcode::G_SHL:
2444 return earlySelectSHL(
I, MRI);
2445 case TargetOpcode::G_CONSTANT: {
2446 bool IsZero =
false;
2447 if (
I.getOperand(1).isCImm())
2448 IsZero =
I.getOperand(1).getCImm()->isZero();
2449 else if (
I.getOperand(1).isImm())
2450 IsZero =
I.getOperand(1).getImm() == 0;
2455 Register DefReg =
I.getOperand(0).getReg();
2458 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2461 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2466 I.setDesc(
TII.get(TargetOpcode::COPY));
2470 case TargetOpcode::G_ADD: {
2479 Register AddDst =
I.getOperand(0).getReg();
2480 Register AddLHS =
I.getOperand(1).getReg();
2481 Register AddRHS =
I.getOperand(2).getReg();
2491 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2512 MachineInstr *
Cmp = MatchCmp(AddRHS);
2516 Cmp = MatchCmp(AddRHS);
2520 auto &PredOp =
Cmp->getOperand(1);
2522 emitIntegerCompare(
Cmp->getOperand(2),
2523 Cmp->getOperand(3), PredOp, MIB);
2527 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2528 I.eraseFromParent();
2531 case TargetOpcode::G_OR: {
2535 Register Dst =
I.getOperand(0).getReg();
2555 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2558 int64_t Immr =
Size - ShiftImm;
2559 int64_t Imms =
Size - ShiftImm - 1;
2560 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2561 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2562 I.eraseFromParent();
2565 case TargetOpcode::G_FENCE: {
2566 if (
I.getOperand(1).getImm() == 0)
2570 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2571 I.eraseFromParent();
2579bool AArch64InstructionSelector::select(MachineInstr &
I) {
2580 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2581 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2587 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2588 if (Subtarget->requiresStrictAlign()) {
2590 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2596 unsigned Opcode =
I.getOpcode();
2598 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2601 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2606 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2607 const Register DefReg =
I.getOperand(0).getReg();
2608 const LLT DefTy = MRI.
getType(DefReg);
2621 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2628 I.setDesc(
TII.get(TargetOpcode::PHI));
2636 if (
I.isDebugInstr())
2643 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2645 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2652 if (preISelLower(
I)) {
2653 Opcode =
I.getOpcode();
2664 if (selectImpl(
I, *CoverageInfo))
2668 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2671 case TargetOpcode::G_SBFX:
2672 case TargetOpcode::G_UBFX: {
2673 static const unsigned OpcTable[2][2] = {
2674 {AArch64::UBFMWri, AArch64::UBFMXri},
2675 {AArch64::SBFMWri, AArch64::SBFMXri}};
2676 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2678 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2681 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2684 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2685 auto LSB = Cst1->Value.getZExtValue();
2686 auto Width = Cst2->Value.getZExtValue();
2690 .
addImm(LSB + Width - 1);
2691 I.eraseFromParent();
2695 case TargetOpcode::G_BRCOND:
2696 return selectCompareBranch(
I, MF, MRI);
2698 case TargetOpcode::G_BRINDIRECT: {
2700 if (std::optional<uint16_t> BADisc =
2702 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2705 MI.addReg(AArch64::XZR);
2706 I.eraseFromParent();
2710 I.setDesc(
TII.get(AArch64::BR));
2715 case TargetOpcode::G_BRJT:
2716 return selectBrJT(
I, MRI);
2718 case AArch64::G_ADD_LOW: {
2723 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2724 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2725 I.setDesc(
TII.get(AArch64::ADDXri));
2731 "Expected small code model");
2733 auto Op2 =
I.getOperand(2);
2734 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2735 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2736 Op1.getTargetFlags())
2738 Op2.getTargetFlags());
2739 I.eraseFromParent();
2744 case TargetOpcode::G_FCONSTANT: {
2745 const Register DefReg =
I.getOperand(0).getReg();
2746 const LLT DefTy = MRI.
getType(DefReg);
2757 bool OptForSize = shouldOptForSize(&MF);
2761 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2768 auto *FPImm =
I.getOperand(1).getFPImm();
2771 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2774 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2775 I.eraseFromParent();
2780 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2783 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2784 MachineOperand &RegOp =
I.getOperand(0);
2790 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2794 MachineOperand &ImmOp =
I.getOperand(1);
2798 const unsigned MovOpc =
2799 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2800 I.setDesc(
TII.get(MovOpc));
2804 case TargetOpcode::G_EXTRACT: {
2805 Register DstReg =
I.getOperand(0).getReg();
2806 Register SrcReg =
I.getOperand(1).getReg();
2807 LLT SrcTy = MRI.
getType(SrcReg);
2808 LLT DstTy = MRI.
getType(DstReg);
2820 unsigned Offset =
I.getOperand(2).getImm();
2825 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2826 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2829 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2831 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2833 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2835 AArch64::GPR64RegClass, NewI->getOperand(0));
2836 I.eraseFromParent();
2842 unsigned LaneIdx =
Offset / 64;
2843 MachineInstr *Extract = emitExtractVectorElt(
2844 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2847 I.eraseFromParent();
2851 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2852 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2857 "unexpected G_EXTRACT types");
2864 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2865 .addReg(DstReg, {}, AArch64::sub_32);
2867 AArch64::GPR32RegClass, MRI);
2868 I.getOperand(0).setReg(DstReg);
2874 case TargetOpcode::G_INSERT: {
2875 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2876 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2883 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2884 unsigned LSB =
I.getOperand(3).getImm();
2886 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2887 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2891 "unexpected G_INSERT types");
2898 TII.get(AArch64::SUBREG_TO_REG))
2900 .
addUse(
I.getOperand(2).getReg())
2901 .
addImm(AArch64::sub_32);
2903 AArch64::GPR32RegClass, MRI);
2904 I.getOperand(2).setReg(SrcReg);
2909 case TargetOpcode::G_FRAME_INDEX: {
2916 I.setDesc(
TII.get(AArch64::ADDXri));
2926 case TargetOpcode::G_GLOBAL_VALUE: {
2927 const GlobalValue *GV =
nullptr;
2929 if (
I.getOperand(1).isSymbol()) {
2930 OpFlags =
I.getOperand(1).getTargetFlags();
2939 return selectTLSGlobalValue(
I, MRI);
2945 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2946 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2947 I.getOperand(1).setTargetFlags(OpFlags);
2948 I.addImplicitDefUseOperands(MF);
2952 materializeLargeCMVal(
I, GV, OpFlags);
2953 I.eraseFromParent();
2956 I.setDesc(
TII.get(AArch64::ADR));
2957 I.getOperand(1).setTargetFlags(OpFlags);
2959 I.setDesc(
TII.get(AArch64::MOVaddr));
2961 MachineInstrBuilder MIB(MF,
I);
2962 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2969 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2970 return selectPtrAuthGlobalValue(
I, MRI);
2972 case TargetOpcode::G_ZEXTLOAD:
2973 case TargetOpcode::G_LOAD:
2974 case TargetOpcode::G_STORE: {
2976 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2991 assert(MemSizeInBytes <= 8 &&
2992 "128-bit atomics should already be custom-legalized");
2995 static constexpr unsigned LDAPROpcodes[] = {
2996 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2997 static constexpr unsigned LDAROpcodes[] = {
2998 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2999 ArrayRef<unsigned> Opcodes =
3000 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
3003 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
3005 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
3006 AArch64::STLRW, AArch64::STLRX};
3011 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
3012 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
3013 I.getOperand(0).setReg(NewVal);
3015 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
3023 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
3026 "Load/Store pointer operand isn't a GPR");
3028 "Load/Store pointer operand isn't a pointer");
3033 LLT ValTy = MRI.
getType(ValReg);
3040 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3046 .addReg(ValReg, {}, SubReg)
3053 if (RB.
getID() == AArch64::FPRRegBankID) {
3056 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3066 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3069 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3078 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3080 const unsigned NewOpc =
3082 if (NewOpc ==
I.getOpcode())
3086 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3089 I.setDesc(
TII.get(NewOpc));
3095 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3096 Register CurValReg =
I.getOperand(0).getReg();
3097 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3098 NewInst.cloneMemRefs(
I);
3099 for (
auto &Fn : *AddrModeFns)
3101 I.eraseFromParent();
3105 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3110 if (Opcode == TargetOpcode::G_STORE) {
3112 LoadStore->getOperand(0).getReg(), MRI);
3113 if (CVal && CVal->Value == 0) {
3115 case AArch64::STRWui:
3116 case AArch64::STRHHui:
3117 case AArch64::STRBBui:
3118 LoadStore->getOperand(0).setReg(AArch64::WZR);
3120 case AArch64::STRXui:
3121 LoadStore->getOperand(0).setReg(AArch64::XZR);
3127 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3128 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3140 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3142 .
addImm(AArch64::sub_32);
3151 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3152 case TargetOpcode::G_INDEXED_SEXTLOAD:
3153 return selectIndexedExtLoad(
I, MRI);
3154 case TargetOpcode::G_INDEXED_LOAD:
3155 return selectIndexedLoad(
I, MRI);
3156 case TargetOpcode::G_INDEXED_STORE:
3159 case TargetOpcode::G_LSHR:
3160 case TargetOpcode::G_ASHR:
3162 return selectVectorAshrLshr(
I, MRI);
3164 case TargetOpcode::G_SHL:
3165 if (Opcode == TargetOpcode::G_SHL &&
3167 return selectVectorSHL(
I, MRI);
3174 Register SrcReg =
I.getOperand(1).getReg();
3175 Register ShiftReg =
I.getOperand(2).getReg();
3176 const LLT ShiftTy = MRI.
getType(ShiftReg);
3177 const LLT SrcTy = MRI.
getType(SrcReg);
3182 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3183 .addReg(ShiftReg, {}, AArch64::sub_32);
3185 I.getOperand(2).setReg(Trunc.getReg(0));
3189 case TargetOpcode::G_OR: {
3196 const Register DefReg =
I.getOperand(0).getReg();
3200 if (NewOpc ==
I.getOpcode())
3203 I.setDesc(
TII.get(NewOpc));
3212 case TargetOpcode::G_PTR_ADD: {
3213 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3214 I.eraseFromParent();
3218 case TargetOpcode::G_SADDE:
3219 case TargetOpcode::G_UADDE:
3220 case TargetOpcode::G_SSUBE:
3221 case TargetOpcode::G_USUBE:
3222 case TargetOpcode::G_SADDO:
3223 case TargetOpcode::G_UADDO:
3224 case TargetOpcode::G_SSUBO:
3225 case TargetOpcode::G_USUBO:
3226 return selectOverflowOp(
I, MRI);
3228 case TargetOpcode::G_PTRMASK: {
3229 Register MaskReg =
I.getOperand(2).getReg();
3235 uint64_t
Mask = *MaskVal;
3236 I.setDesc(
TII.get(AArch64::ANDXri));
3237 I.getOperand(2).ChangeToImmediate(
3243 case TargetOpcode::G_PTRTOINT:
3244 case TargetOpcode::G_TRUNC: {
3245 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3246 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3248 const Register DstReg =
I.getOperand(0).getReg();
3249 const Register SrcReg =
I.getOperand(1).getReg();
3251 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3252 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3256 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3260 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3271 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3275 if (DstRC == SrcRC) {
3277 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3281 }
else if (DstRC == &AArch64::GPR32RegClass &&
3282 SrcRC == &AArch64::GPR64RegClass) {
3283 I.getOperand(1).setSubReg(AArch64::sub_32);
3286 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3290 I.setDesc(
TII.get(TargetOpcode::COPY));
3292 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3295 I.setDesc(
TII.get(AArch64::XTNv4i16));
3301 MachineInstr *Extract = emitExtractVectorElt(
3305 I.eraseFromParent();
3310 if (Opcode == TargetOpcode::G_PTRTOINT) {
3311 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3312 I.setDesc(
TII.get(TargetOpcode::COPY));
3320 case TargetOpcode::G_ANYEXT: {
3321 if (selectUSMovFromExtend(
I, MRI))
3324 const Register DstReg =
I.getOperand(0).getReg();
3325 const Register SrcReg =
I.getOperand(1).getReg();
3327 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3328 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3330 <<
", expected: GPR\n");
3334 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3335 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3337 <<
", expected: GPR\n");
3344 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3348 if (DstSize != 64 && DstSize > 32) {
3350 <<
", expected: 32 or 64\n");
3360 .
addImm(AArch64::sub_32);
3361 I.getOperand(1).setReg(ExtSrc);
3366 case TargetOpcode::G_ZEXT:
3367 case TargetOpcode::G_SEXT_INREG:
3368 case TargetOpcode::G_SEXT: {
3369 if (selectUSMovFromExtend(
I, MRI))
3372 unsigned Opcode =
I.getOpcode();
3373 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3374 const Register DefReg =
I.getOperand(0).getReg();
3375 Register SrcReg =
I.getOperand(1).getReg();
3376 const LLT DstTy = MRI.
getType(DefReg);
3377 const LLT SrcTy = MRI.
getType(SrcReg);
3383 if (Opcode == TargetOpcode::G_SEXT_INREG)
3384 SrcSize =
I.getOperand(2).getImm();
3390 AArch64::GPRRegBankID &&
3391 "Unexpected ext regbank");
3402 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3405 if (LoadMI && IsGPR) {
3406 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3407 unsigned BytesLoaded = MemOp->getSize().getValue();
3414 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3417 const Register ZReg = AArch64::WZR;
3418 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3421 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3422 .addUse(SubregToRegSrc)
3423 .
addImm(AArch64::sub_32);
3427 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3437 I.eraseFromParent();
3442 if (DstSize == 64) {
3443 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3451 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3452 {&AArch64::GPR64RegClass}, {})
3458 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3462 }
else if (DstSize <= 32) {
3463 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3472 I.eraseFromParent();
3476 case TargetOpcode::G_FREEZE:
3479 case TargetOpcode::G_INTTOPTR:
3484 case TargetOpcode::G_BITCAST:
3492 case TargetOpcode::G_SELECT: {
3494 const Register CondReg = Sel.getCondReg();
3496 const Register FReg = Sel.getFalseReg();
3498 if (tryOptSelect(Sel))
3504 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3509 Sel.eraseFromParent();
3512 case TargetOpcode::G_ICMP: {
3522 auto &PredOp =
I.getOperand(1);
3523 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3527 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3528 AArch64::WZR, InvCC, MIB);
3529 I.eraseFromParent();
3533 case TargetOpcode::G_FCMP: {
3536 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3538 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3540 I.eraseFromParent();
3543 case TargetOpcode::G_VASTART:
3545 : selectVaStartAAPCS(
I, MF, MRI);
3546 case TargetOpcode::G_INTRINSIC:
3547 return selectIntrinsic(
I, MRI);
3548 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3549 return selectIntrinsicWithSideEffects(
I, MRI);
3550 case TargetOpcode::G_IMPLICIT_DEF: {
3551 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3552 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3553 const Register DstReg =
I.getOperand(0).getReg();
3554 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3559 case TargetOpcode::G_BLOCK_ADDR: {
3560 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3561 if (std::optional<uint16_t> BADisc =
3563 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3564 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3573 AArch64::GPR64RegClass, MRI);
3574 I.eraseFromParent();
3578 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3579 I.eraseFromParent();
3582 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3583 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3584 I.getOperand(0).getReg())
3588 I.getOperand(1).getBlockAddress(), 0,
3590 I.eraseFromParent();
3595 case AArch64::G_DUP: {
3602 AArch64::GPRRegBankID)
3604 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3606 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3608 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3610 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3612 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3618 case TargetOpcode::G_BUILD_VECTOR:
3619 return selectBuildVector(
I, MRI);
3620 case TargetOpcode::G_MERGE_VALUES:
3622 case TargetOpcode::G_UNMERGE_VALUES:
3624 case TargetOpcode::G_SHUFFLE_VECTOR:
3625 return selectShuffleVector(
I, MRI);
3626 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3627 return selectExtractElt(
I, MRI);
3628 case TargetOpcode::G_CONCAT_VECTORS:
3629 return selectConcatVectors(
I, MRI);
3630 case TargetOpcode::G_JUMP_TABLE:
3631 return selectJumpTable(
I, MRI);
3632 case TargetOpcode::G_MEMCPY:
3633 case TargetOpcode::G_MEMCPY_INLINE:
3634 case TargetOpcode::G_MEMMOVE:
3635 case TargetOpcode::G_MEMSET:
3636 case TargetOpcode::G_MEMSET_INLINE:
3637 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3638 return selectMOPS(
I, MRI);
3644bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3645 MachineIRBuilderState OldMIBState = MIB.
getState();
3651bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3652 MachineRegisterInfo &MRI) {
3655 case TargetOpcode::G_MEMCPY:
3656 case TargetOpcode::G_MEMCPY_INLINE:
3657 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3659 case TargetOpcode::G_MEMMOVE:
3660 Mopcode = AArch64::MOPSMemoryMovePseudo;
3662 case TargetOpcode::G_MEMSET:
3663 case TargetOpcode::G_MEMSET_INLINE:
3665 Mopcode = AArch64::MOPSMemorySetPseudo;
3678 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3679 const auto &SrcValRegClass =
3680 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3698 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3699 {DstPtrCopy, SizeCopy, SrcValCopy});
3702 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3703 {DstPtrCopy, SrcValCopy, SizeCopy});
3710bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3711 MachineRegisterInfo &MRI) {
3712 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3713 Register JTAddr =
I.getOperand(0).getReg();
3714 unsigned JTI =
I.getOperand(1).getIndex();
3717 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3729 "jump table hardening only supported on MachO/ELF");
3737 I.eraseFromParent();
3744 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3745 {TargetReg, ScratchReg}, {JTAddr,
Index})
3746 .addJumpTableIndex(JTI);
3748 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3749 {
static_cast<int64_t
>(JTI)});
3751 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3752 I.eraseFromParent();
3757bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3758 MachineRegisterInfo &MRI) {
3759 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3760 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3762 Register DstReg =
I.getOperand(0).getReg();
3763 unsigned JTI =
I.getOperand(1).getIndex();
3766 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3769 I.eraseFromParent();
3774bool AArch64InstructionSelector::selectTLSGlobalValue(
3775 MachineInstr &
I, MachineRegisterInfo &MRI) {
3778 MachineFunction &MF = *
I.getParent()->getParent();
3781 const auto &GlobalOp =
I.getOperand(1);
3782 assert(GlobalOp.getOffset() == 0 &&
3783 "Shouldn't have an offset on TLS globals!");
3784 const GlobalValue &GV = *GlobalOp.getGlobal();
3787 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3790 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3791 {LoadGOT.getReg(0)})
3802 assert(Opcode == AArch64::BLR);
3803 Opcode = AArch64::BLRAAZ;
3807 .addUse(AArch64::X0, RegState::Implicit)
3808 .
addDef(AArch64::X0, RegState::Implicit)
3814 I.eraseFromParent();
3818MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3820 MachineIRBuilder &MIRBuilder)
const {
3821 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3823 auto BuildFn = [&](
unsigned SubregIndex) {
3827 .addImm(SubregIndex);
3835 return BuildFn(AArch64::bsub);
3837 return BuildFn(AArch64::hsub);
3839 return BuildFn(AArch64::ssub);
3841 return BuildFn(AArch64::dsub);
3848AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3849 MachineIRBuilder &MIB,
3850 MachineRegisterInfo &MRI)
const {
3851 LLT DstTy = MRI.
getType(DstReg);
3853 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3854 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3858 unsigned SubReg = 0;
3861 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3867 .addReg(SrcReg, {}, SubReg);
3872bool AArch64InstructionSelector::selectMergeValues(
3873 MachineInstr &
I, MachineRegisterInfo &MRI) {
3874 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3875 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3876 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3878 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3880 if (
I.getNumOperands() != 3)
3887 Register DstReg =
I.getOperand(0).getReg();
3888 Register Src1Reg =
I.getOperand(1).getReg();
3889 Register Src2Reg =
I.getOperand(2).getReg();
3890 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3891 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3895 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3896 Src2Reg, 1, RB, MIB);
3901 I.eraseFromParent();
3905 if (RB.
getID() != AArch64::GPRRegBankID)
3911 auto *DstRC = &AArch64::GPR64RegClass;
3913 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3914 TII.get(TargetOpcode::SUBREG_TO_REG))
3916 .
addUse(
I.getOperand(1).getReg())
3917 .
addImm(AArch64::sub_32);
3920 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3921 TII.get(TargetOpcode::SUBREG_TO_REG))
3923 .
addUse(
I.getOperand(2).getReg())
3924 .
addImm(AArch64::sub_32);
3926 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3927 .
addDef(
I.getOperand(0).getReg())
3935 I.eraseFromParent();
3940 const unsigned EltSize) {
3945 CopyOpc = AArch64::DUPi8;
3946 ExtractSubReg = AArch64::bsub;
3949 CopyOpc = AArch64::DUPi16;
3950 ExtractSubReg = AArch64::hsub;
3953 CopyOpc = AArch64::DUPi32;
3954 ExtractSubReg = AArch64::ssub;
3957 CopyOpc = AArch64::DUPi64;
3958 ExtractSubReg = AArch64::dsub;
3962 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3968MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3969 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3970 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3971 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3972 unsigned CopyOpc = 0;
3973 unsigned ExtractSubReg = 0;
3976 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3981 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3983 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3987 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3988 const LLT &VecTy = MRI.
getType(VecReg);
3990 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3992 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4002 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4003 .addReg(VecReg, {}, ExtractSubReg);
4012 MachineInstr *ScalarToVector = emitScalarToVector(
4013 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4014 if (!ScalarToVector)
4019 MachineInstr *LaneCopyMI =
4020 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4028bool AArch64InstructionSelector::selectExtractElt(
4029 MachineInstr &
I, MachineRegisterInfo &MRI) {
4030 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4031 "unexpected opcode!");
4032 Register DstReg =
I.getOperand(0).getReg();
4033 const LLT NarrowTy = MRI.
getType(DstReg);
4034 const Register SrcReg =
I.getOperand(1).getReg();
4035 const LLT WideTy = MRI.
getType(SrcReg);
4037 "source register size too small!");
4038 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4041 MachineOperand &LaneIdxOp =
I.getOperand(2);
4042 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4048 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4050 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4051 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4055 Opcode = AArch64::UMOVvi8;
4058 Opcode = AArch64::UMOVvi16;
4061 Opcode = AArch64::UMOVvi32;
4068 MachineInstr *ScalarToVector = emitScalarToVector(
4069 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4070 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4074 I.setDesc(
TII.get(Opcode));
4075 I.getOperand(2).ChangeToImmediate(LaneIdx);
4080 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4085 I.eraseFromParent();
4089bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4090 MachineInstr &
I, MachineRegisterInfo &MRI) {
4091 unsigned NumElts =
I.getNumOperands() - 1;
4092 Register SrcReg =
I.getOperand(NumElts).getReg();
4093 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4094 const LLT SrcTy = MRI.
getType(SrcReg);
4096 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4098 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4104 const RegisterBank &DstRB =
4108 MachineInstr *Extract =
4109 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4113 I.eraseFromParent();
4117bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4118 MachineRegisterInfo &MRI) {
4119 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4120 "unexpected opcode");
4124 AArch64::FPRRegBankID ||
4126 AArch64::FPRRegBankID) {
4127 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4128 "currently unsupported.\n");
4134 unsigned NumElts =
I.getNumOperands() - 1;
4135 Register SrcReg =
I.getOperand(NumElts).getReg();
4136 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4137 const LLT WideTy = MRI.
getType(SrcReg);
4140 "source register size too small!");
4143 return selectSplitVectorUnmerge(
I, MRI);
4147 unsigned CopyOpc = 0;
4148 unsigned ExtractSubReg = 0;
4159 unsigned NumInsertRegs = NumElts - 1;
4165 InsertRegs.
assign(NumInsertRegs, SrcReg);
4174 unsigned SubReg = 0;
4177 assert(Found &&
"expected to find last operand's subeg idx");
4178 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4180 MachineInstr &ImpDefMI =
4181 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4186 MachineInstr &InsMI =
4188 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4205 Register CopyTo =
I.getOperand(0).getReg();
4206 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4207 .addReg(InsertRegs[0], {}, ExtractSubReg);
4211 unsigned LaneIdx = 1;
4212 for (
Register InsReg : InsertRegs) {
4213 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4214 MachineInstr &CopyInst =
4233 I.eraseFromParent();
4237bool AArch64InstructionSelector::selectConcatVectors(
4238 MachineInstr &
I, MachineRegisterInfo &MRI) {
4239 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4240 "Unexpected opcode");
4241 Register Dst =
I.getOperand(0).getReg();
4242 Register Op1 =
I.getOperand(1).getReg();
4243 Register Op2 =
I.getOperand(2).getReg();
4244 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4247 I.eraseFromParent();
4252AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4253 MachineFunction &MF)
const {
4261MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4262 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4269 RC = &AArch64::FPR128RegClass;
4270 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4273 RC = &AArch64::FPR64RegClass;
4274 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4277 RC = &AArch64::FPR32RegClass;
4278 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4281 RC = &AArch64::FPR16RegClass;
4282 Opc = AArch64::LDRHui;
4285 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4290 MachineInstr *LoadMI =
nullptr;
4291 auto &MF = MIRBuilder.
getMF();
4292 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4293 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4295 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4298 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4302 .addConstantPoolIndex(
4318static std::pair<unsigned, unsigned>
4320 unsigned Opc, SubregIdx;
4321 if (RB.
getID() == AArch64::GPRRegBankID) {
4323 Opc = AArch64::INSvi8gpr;
4324 SubregIdx = AArch64::bsub;
4325 }
else if (EltSize == 16) {
4326 Opc = AArch64::INSvi16gpr;
4327 SubregIdx = AArch64::ssub;
4328 }
else if (EltSize == 32) {
4329 Opc = AArch64::INSvi32gpr;
4330 SubregIdx = AArch64::ssub;
4331 }
else if (EltSize == 64) {
4332 Opc = AArch64::INSvi64gpr;
4333 SubregIdx = AArch64::dsub;
4339 Opc = AArch64::INSvi8lane;
4340 SubregIdx = AArch64::bsub;
4341 }
else if (EltSize == 16) {
4342 Opc = AArch64::INSvi16lane;
4343 SubregIdx = AArch64::hsub;
4344 }
else if (EltSize == 32) {
4345 Opc = AArch64::INSvi32lane;
4346 SubregIdx = AArch64::ssub;
4347 }
else if (EltSize == 64) {
4348 Opc = AArch64::INSvi64lane;
4349 SubregIdx = AArch64::dsub;
4354 return std::make_pair(
Opc, SubregIdx);
4357MachineInstr *AArch64InstructionSelector::emitInstr(
4358 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4359 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4360 const ComplexRendererFns &RenderFns)
const {
4361 assert(Opcode &&
"Expected an opcode?");
4363 "Function should only be used to produce selected instructions!");
4364 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4366 for (
auto &Fn : *RenderFns)
4372MachineInstr *AArch64InstructionSelector::emitAddSub(
4373 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4375 MachineIRBuilder &MIRBuilder)
const {
4377 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4381 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4382 bool Is32Bit =
Size == 32;
4385 if (
auto Fns = selectArithImmed(
RHS))
4386 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4390 if (
auto Fns = selectNegArithImmed(
RHS))
4391 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4395 if (
auto Fns = selectArithExtendedRegister(
RHS))
4396 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4400 if (
auto Fns = selectShiftedRegister(
RHS))
4401 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4403 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4408AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4409 MachineOperand &
RHS,
4410 MachineIRBuilder &MIRBuilder)
const {
4411 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4412 {{AArch64::ADDXri, AArch64::ADDWri},
4413 {AArch64::ADDXrs, AArch64::ADDWrs},
4414 {AArch64::ADDXrr, AArch64::ADDWrr},
4415 {AArch64::SUBXri, AArch64::SUBWri},
4416 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4417 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4421AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4422 MachineOperand &
RHS,
4423 MachineIRBuilder &MIRBuilder)
const {
4424 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4425 {{AArch64::ADDSXri, AArch64::ADDSWri},
4426 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4427 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4428 {AArch64::SUBSXri, AArch64::SUBSWri},
4429 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4430 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4434AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4435 MachineOperand &
RHS,
4436 MachineIRBuilder &MIRBuilder)
const {
4437 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4438 {{AArch64::SUBSXri, AArch64::SUBSWri},
4439 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4440 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4441 {AArch64::ADDSXri, AArch64::ADDSWri},
4442 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4443 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4447AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4448 MachineOperand &
RHS,
4449 MachineIRBuilder &MIRBuilder)
const {
4450 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4451 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4453 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4454 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4458AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4459 MachineOperand &
RHS,
4460 MachineIRBuilder &MIRBuilder)
const {
4461 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4462 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4464 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4465 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4469AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4470 MachineIRBuilder &MIRBuilder)
const {
4473 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4478AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4479 MachineIRBuilder &MIRBuilder)
const {
4482 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4487AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4488 MachineIRBuilder &MIRBuilder)
const {
4489 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4493 bool Is32Bit = (
RegSize == 32);
4494 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4495 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4496 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4500 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4503 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4510 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4511 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4512 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4515MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4516 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4517 MachineIRBuilder &MIRBuilder)
const {
4518 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4525 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4527 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4529 return emitCMP(
LHS,
RHS, MIRBuilder);
4532MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4534 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4538 "Expected a 32-bit scalar register?");
4540 const Register ZReg = AArch64::WZR;
4545 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4551 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4552 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4553 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4558MachineInstr *AArch64InstructionSelector::emitFPCompare(
4560 std::optional<CmpInst::Predicate> Pred)
const {
4561 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4566 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4577 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4581 ShouldUseImm =
true;
4585 unsigned CmpOpcTbl[2][3] = {
4586 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4587 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4589 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4601MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4603 MachineIRBuilder &MIRBuilder)
const {
4610 const LLT Op1Ty = MRI.
getType(Op1);
4611 const LLT Op2Ty = MRI.
getType(Op2);
4613 if (Op1Ty != Op2Ty) {
4614 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4617 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4620 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4631 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4635 MachineInstr *WidenedOp1 =
4636 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4637 MachineInstr *WidenedOp2 =
4638 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4639 if (!WidenedOp1 || !WidenedOp2) {
4640 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4645 unsigned InsertOpc, InsSubRegIdx;
4646 std::tie(InsertOpc, InsSubRegIdx) =
4664 MachineIRBuilder &MIRBuilder)
const {
4665 auto &MRI = *MIRBuilder.
getMRI();
4671 Size =
TRI.getRegSizeInBits(*RC);
4675 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4676 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4677 unsigned Opc = OpcTable[
Size == 64];
4678 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4683MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4685 MachineRegisterInfo *MRI = MIB.
getMRI();
4686 unsigned Opcode =
I.getOpcode();
4690 bool NeedsNegatedCarry =
4691 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4700 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4701 if (SrcMI ==
I.getPrevNode()) {
4703 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4704 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4705 CarrySrcMI->isUnsigned() &&
4706 CarrySrcMI->getCarryOutReg() == CarryReg &&
4707 selectAndRestoreState(*SrcMI))
4714 if (NeedsNegatedCarry) {
4717 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4721 auto Fns = select12BitValueWithLeftShift(1);
4722 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4725bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4726 MachineRegisterInfo &MRI) {
4731 emitCarryIn(
I, CarryInMI->getCarryInReg());
4735 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4736 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4738 Register CarryOutReg = CarryMI.getCarryOutReg();
4747 emitCSINC(CarryOutReg, ZReg, ZReg,
4748 getInvertedCondCode(OpAndCC.second), MIB);
4751 I.eraseFromParent();
4755std::pair<MachineInstr *, AArch64CC::CondCode>
4756AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4757 MachineOperand &
LHS,
4758 MachineOperand &
RHS,
4759 MachineIRBuilder &MIRBuilder)
const {
4763 case TargetOpcode::G_SADDO:
4765 case TargetOpcode::G_UADDO:
4767 case TargetOpcode::G_SSUBO:
4769 case TargetOpcode::G_USUBO:
4771 case TargetOpcode::G_SADDE:
4773 case TargetOpcode::G_UADDE:
4775 case TargetOpcode::G_SSUBE:
4777 case TargetOpcode::G_USUBE:
4798 unsigned Depth = 0) {
4805 MustBeFirst =
false;
4811 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4812 bool IsOR = Opcode == TargetOpcode::G_OR;
4824 if (MustBeFirstL && MustBeFirstR)
4830 if (!CanNegateL && !CanNegateR)
4834 CanNegate = WillNegate && CanNegateL && CanNegateR;
4837 MustBeFirst = !CanNegate;
4839 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4842 MustBeFirst = MustBeFirstL || MustBeFirstR;
4849MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4852 MachineIRBuilder &MIB)
const {
4853 auto &MRI = *MIB.
getMRI();
4856 std::optional<ValueAndVReg>
C;
4860 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4861 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4862 else if (
C->Value.ule(31))
4863 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4865 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4871 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4872 CCmpOpc = AArch64::FCCMPHrr;
4875 CCmpOpc = AArch64::FCCMPSrr;
4878 CCmpOpc = AArch64::FCCMPDrr;
4888 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4889 CCmp.
addImm(
C->Value.getZExtValue());
4890 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4891 CCmp.
addImm(
C->Value.abs().getZExtValue());
4899MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4903 auto &MRI = *MIB.
getMRI();
4921 MachineInstr *ExtraCmp;
4923 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4935 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4936 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4937 Cmp->getOperand(3).getReg(), MIB);
4944 bool IsOR = Opcode == TargetOpcode::G_OR;
4950 assert(ValidL &&
"Valid conjunction/disjunction tree");
4957 assert(ValidR &&
"Valid conjunction/disjunction tree");
4962 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4971 bool NegateAfterAll;
4972 if (Opcode == TargetOpcode::G_OR) {
4975 assert(CanNegateR &&
"at least one side must be negatable");
4976 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4980 NegateAfterR =
true;
4983 NegateR = CanNegateR;
4984 NegateAfterR = !CanNegateR;
4987 NegateAfterAll = !Negate;
4989 assert(Opcode == TargetOpcode::G_AND &&
4990 "Valid conjunction/disjunction tree");
4991 assert(!Negate &&
"Valid conjunction/disjunction tree");
4995 NegateAfterR =
false;
4996 NegateAfterAll =
false;
5001 MachineInstr *CmpR =
5012MachineInstr *AArch64InstructionSelector::emitConjunction(
5014 bool DummyCanNegate;
5015 bool DummyMustBeFirst;
5022bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5023 MachineInstr &CondMI) {
5034bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5035 MachineRegisterInfo &MRI = *MIB.
getMRI();
5054 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5063 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5069 unsigned CondOpc = CondDef->
getOpcode();
5070 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5071 if (tryOptSelectConjunction(
I, *CondDef))
5077 if (CondOpc == TargetOpcode::G_ICMP) {
5106 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5107 I.getOperand(3).getReg(), CondCode, MIB);
5108 I.eraseFromParent();
5112MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5113 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5114 MachineIRBuilder &MIRBuilder)
const {
5116 "Unexpected MachineOperand");
5117 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5140 if (
isCMN(RHSDef,
P, MRI))
5155 if (
isCMN(LHSDef,
P, MRI)) {
5172 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5175 if (!ValAndVReg || ValAndVReg->Value != 0)
5185bool AArch64InstructionSelector::selectShuffleVector(
5186 MachineInstr &
I, MachineRegisterInfo &MRI) {
5187 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5188 Register Src1Reg =
I.getOperand(1).getReg();
5189 Register Src2Reg =
I.getOperand(2).getReg();
5190 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5192 "Expected equal shuffle types during selection");
5201 SmallVector<int> NewMask;
5202 bool FirstUsed =
false;
5203 bool SecondUsed =
false;
5204 for (
int M : Mask) {
5206 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5209 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5214 FirstUsed |=
M < NumElts;
5215 SecondUsed |=
M >= NumElts;
5216 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5225 for (
int &M : NewMask) {
5227 assert(M >= ByteLanes && M < 2 * ByteLanes);
5237 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5238 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5251 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5258 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5262 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5267 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5268 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5270 I.eraseFromParent();
5275 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5278 I.eraseFromParent();
5286 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5289 I.eraseFromParent();
5293MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5295 unsigned LaneIdx,
const RegisterBank &RB,
5296 MachineIRBuilder &MIRBuilder)
const {
5297 MachineInstr *InsElt =
nullptr;
5299 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5308 if (RB.
getID() == AArch64::FPRRegBankID) {
5309 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5312 .
addUse(InsSub->getOperand(0).getReg())
5324bool AArch64InstructionSelector::selectUSMovFromExtend(
5325 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5326 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5327 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5328 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5330 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5331 const Register DefReg =
MI.getOperand(0).getReg();
5332 const LLT DstTy = MRI.
getType(DefReg);
5335 if (DstSize != 32 && DstSize != 64)
5338 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5339 MI.getOperand(1).getReg(), MRI);
5345 const LLT VecTy = MRI.
getType(Src0);
5350 const MachineInstr *ScalarToVector = emitScalarToVector(
5351 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5352 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5358 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5360 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5362 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5364 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5366 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5374 MachineInstr *ExtI =
nullptr;
5375 if (DstSize == 64 && !IsSigned) {
5377 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5378 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5380 .
addImm(AArch64::sub_32);
5383 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5386 MI.eraseFromParent();
5390MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5391 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5393 if (DstSize == 128) {
5394 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5396 Op = AArch64::MOVIv16b_ns;
5398 Op = AArch64::MOVIv8b_ns;
5401 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5405 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5412MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5413 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5417 if (DstSize == 128) {
5418 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5420 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5422 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5425 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5442MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5443 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5447 if (DstSize == 128) {
5448 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5450 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5452 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5455 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5478MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5479 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5482 if (DstSize == 128) {
5483 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5485 Op = AArch64::MOVIv2d_ns;
5487 Op = AArch64::MOVID;
5490 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5493 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5500MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5501 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5505 if (DstSize == 128) {
5506 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5508 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5510 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5513 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5530MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5531 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5534 bool IsWide =
false;
5535 if (DstSize == 128) {
5536 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5538 Op = AArch64::FMOVv4f32_ns;
5541 Op = AArch64::FMOVv2f32_ns;
5544 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5550 Op = AArch64::FMOVv2f64_ns;
5554 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5559bool AArch64InstructionSelector::selectIndexedExtLoad(
5560 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5563 Register WriteBack = ExtLd.getWritebackReg();
5568 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5569 bool IsPre = ExtLd.isPre();
5571 unsigned InsertIntoSubReg = 0;
5577 if ((IsSExt && IsFPR) || Ty.
isVector())
5585 if (MemSizeBits == 8) {
5588 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5590 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5591 NewLdDstTy = IsDst64 ? s64 : s32;
5593 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5594 InsertIntoSubReg = AArch64::bsub;
5597 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5598 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5601 }
else if (MemSizeBits == 16) {
5604 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5606 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5607 NewLdDstTy = IsDst64 ? s64 : s32;
5609 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5610 InsertIntoSubReg = AArch64::hsub;
5613 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5614 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5617 }
else if (MemSizeBits == 32) {
5619 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5622 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5623 InsertIntoSubReg = AArch64::ssub;
5626 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5627 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5639 .addImm(Cst->getSExtValue());
5644 if (InsertIntoSubReg) {
5646 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5647 .addUse(LdMI.getReg(1))
5648 .
addImm(InsertIntoSubReg);
5651 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5658 MI.eraseFromParent();
5663bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5664 MachineRegisterInfo &MRI) {
5667 Register WriteBack = Ld.getWritebackReg();
5671 "Unexpected type for indexed load");
5672 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5675 return selectIndexedExtLoad(
MI, MRI);
5679 static constexpr unsigned GPROpcodes[] = {
5680 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5682 static constexpr unsigned FPROpcodes[] = {
5683 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5686 ? FPROpcodes[
Log2_32(MemSize)]
5687 : GPROpcodes[
Log2_32(MemSize)];
5690 static constexpr unsigned GPROpcodes[] = {
5691 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5693 static constexpr unsigned FPROpcodes[] = {
5694 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5695 AArch64::LDRDpost, AArch64::LDRQpost};
5697 ? FPROpcodes[
Log2_32(MemSize)]
5698 : GPROpcodes[
Log2_32(MemSize)];
5708 MI.eraseFromParent();
5712bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5713 MachineRegisterInfo &MRI) {
5719 "Unexpected type for indexed store");
5721 LocationSize MemSize =
I.getMMO().getSize();
5722 unsigned MemSizeInBytes = MemSize.
getValue();
5724 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5725 "Unexpected indexed store size");
5726 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5730 static constexpr unsigned GPROpcodes[] = {
5731 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5733 static constexpr unsigned FPROpcodes[] = {
5734 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5738 Opc = FPROpcodes[MemSizeLog2];
5740 Opc = GPROpcodes[MemSizeLog2];
5742 static constexpr unsigned GPROpcodes[] = {
5743 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5745 static constexpr unsigned FPROpcodes[] = {
5746 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5747 AArch64::STRDpost, AArch64::STRQpost};
5750 Opc = FPROpcodes[MemSizeLog2];
5752 Opc = GPROpcodes[MemSizeLog2];
5760 Str.cloneMemRefs(
I);
5762 I.eraseFromParent();
5767AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5768 MachineIRBuilder &MIRBuilder,
5769 MachineRegisterInfo &MRI) {
5772 assert((DstSize == 64 || DstSize == 128) &&
5773 "Unexpected vector constant size");
5776 if (DstSize == 128) {
5778 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5783 if (DstSize == 64) {
5786 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5789 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5796 APInt SplatValueAsInt =
5799 : SplatValue->getUniqueInteger();
5802 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5803 MachineInstr *NewOp;
5827 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5831 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5832 unsigned NegOpc) -> MachineInstr * {
5835 APInt NegBits(DstSize, 0);
5836 unsigned NumElts = DstSize / NumBits;
5837 for (
unsigned i = 0; i < NumElts; i++)
5838 NegBits |= Neg << (NumBits * i);
5839 NegBits = DefBits ^ NegBits;
5843 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5845 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5847 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5852 if ((R = TryWithFNeg(DefBits, 32,
5853 DstSize == 64 ? AArch64::FNEGv2f32
5854 : AArch64::FNEGv4f32)) ||
5855 (R = TryWithFNeg(DefBits, 64,
5856 DstSize == 64 ? AArch64::FNEGDr
5857 : AArch64::FNEGv2f64)) ||
5858 (STI.hasFullFP16() &&
5859 (R = TryWithFNeg(DefBits, 16,
5860 DstSize == 64 ? AArch64::FNEGv4f16
5861 : AArch64::FNEGv8f16))))
5867 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5871 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5873 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5877bool AArch64InstructionSelector::tryOptConstantBuildVec(
5878 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5879 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5881 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5887 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5888 Register OpReg =
I.getOperand(Idx).getReg();
5897 std::move(AnyConst->Value)));
5910 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5912 I.eraseFromParent();
5916bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5917 MachineInstr &
I, MachineRegisterInfo &MRI) {
5922 Register Dst =
I.getOperand(0).getReg();
5923 Register EltReg =
I.getOperand(1).getReg();
5924 LLT EltTy = MRI.
getType(EltReg);
5927 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5932 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5940 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5945 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5948 I.eraseFromParent();
5953bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5954 MachineRegisterInfo &MRI) {
5955 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5958 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5959 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5962 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5964 if (tryOptBuildVecToSubregToReg(
I, MRI))
5967 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5969 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5972 MachineInstr *ScalarToVec =
5974 I.getOperand(1).getReg(), MIB);
5983 MachineInstr *PrevMI = ScalarToVec;
5984 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5987 Register OpReg =
I.getOperand(i).getReg();
5990 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5997 if (DstSize < 128) {
6000 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6003 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
6008 unsigned SubReg = 0;
6011 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
6012 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
6018 Register DstReg =
I.getOperand(0).getReg();
6020 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
6021 MachineOperand &RegOp =
I.getOperand(1);
6041 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6043 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6052bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6055 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6057 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6058 auto &MRI = *MIB.
getMRI();
6059 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6062 "Destination must be 64 bits or 128 bits?");
6063 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6064 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6069 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6070 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6071 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6072 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6081bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6082 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6083 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6085 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6086 auto &MRI = *MIB.
getMRI();
6087 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6090 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6092 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6093 [](
auto MO) { return MO.getReg(); });
6097 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6112 .
addImm(LaneNo->getZExtValue())
6116 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6117 unsigned SubReg = AArch64::qsub0;
6118 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6119 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6120 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6121 : DstOp(
I.getOperand(Idx).
getReg())},
6123 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6128 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6134void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6137 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6138 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6139 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6142 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6143 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6152bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6153 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6154 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6155 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6159 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6160 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6164 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6174 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6177 .
addImm(LaneNo->getZExtValue())
6184bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6185 MachineInstr &
I, MachineRegisterInfo &MRI) {
6198 case Intrinsic::aarch64_ldxp:
6199 case Intrinsic::aarch64_ldaxp: {
6201 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6202 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6208 case Intrinsic::aarch64_neon_ld1x2: {
6209 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6212 Opc = AArch64::LD1Twov8b;
6214 Opc = AArch64::LD1Twov16b;
6216 Opc = AArch64::LD1Twov4h;
6218 Opc = AArch64::LD1Twov8h;
6220 Opc = AArch64::LD1Twov2s;
6222 Opc = AArch64::LD1Twov4s;
6224 Opc = AArch64::LD1Twov2d;
6225 else if (Ty ==
S64 || Ty == P0)
6226 Opc = AArch64::LD1Twov1d;
6229 selectVectorLoadIntrinsic(
Opc, 2,
I);
6232 case Intrinsic::aarch64_neon_ld1x3: {
6233 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6236 Opc = AArch64::LD1Threev8b;
6238 Opc = AArch64::LD1Threev16b;
6240 Opc = AArch64::LD1Threev4h;
6242 Opc = AArch64::LD1Threev8h;
6244 Opc = AArch64::LD1Threev2s;
6246 Opc = AArch64::LD1Threev4s;
6248 Opc = AArch64::LD1Threev2d;
6249 else if (Ty ==
S64 || Ty == P0)
6250 Opc = AArch64::LD1Threev1d;
6253 selectVectorLoadIntrinsic(
Opc, 3,
I);
6256 case Intrinsic::aarch64_neon_ld1x4: {
6257 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6260 Opc = AArch64::LD1Fourv8b;
6262 Opc = AArch64::LD1Fourv16b;
6264 Opc = AArch64::LD1Fourv4h;
6266 Opc = AArch64::LD1Fourv8h;
6268 Opc = AArch64::LD1Fourv2s;
6270 Opc = AArch64::LD1Fourv4s;
6272 Opc = AArch64::LD1Fourv2d;
6273 else if (Ty ==
S64 || Ty == P0)
6274 Opc = AArch64::LD1Fourv1d;
6277 selectVectorLoadIntrinsic(
Opc, 4,
I);
6280 case Intrinsic::aarch64_neon_ld2: {
6281 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6284 Opc = AArch64::LD2Twov8b;
6286 Opc = AArch64::LD2Twov16b;
6288 Opc = AArch64::LD2Twov4h;
6290 Opc = AArch64::LD2Twov8h;
6292 Opc = AArch64::LD2Twov2s;
6294 Opc = AArch64::LD2Twov4s;
6296 Opc = AArch64::LD2Twov2d;
6297 else if (Ty ==
S64 || Ty == P0)
6298 Opc = AArch64::LD1Twov1d;
6301 selectVectorLoadIntrinsic(
Opc, 2,
I);
6304 case Intrinsic::aarch64_neon_ld2lane: {
6305 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6308 Opc = AArch64::LD2i8;
6310 Opc = AArch64::LD2i16;
6312 Opc = AArch64::LD2i32;
6315 Opc = AArch64::LD2i64;
6318 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6322 case Intrinsic::aarch64_neon_ld2r: {
6323 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6326 Opc = AArch64::LD2Rv8b;
6328 Opc = AArch64::LD2Rv16b;
6330 Opc = AArch64::LD2Rv4h;
6332 Opc = AArch64::LD2Rv8h;
6334 Opc = AArch64::LD2Rv2s;
6336 Opc = AArch64::LD2Rv4s;
6338 Opc = AArch64::LD2Rv2d;
6339 else if (Ty ==
S64 || Ty == P0)
6340 Opc = AArch64::LD2Rv1d;
6343 selectVectorLoadIntrinsic(
Opc, 2,
I);
6346 case Intrinsic::aarch64_neon_ld3: {
6347 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6350 Opc = AArch64::LD3Threev8b;
6352 Opc = AArch64::LD3Threev16b;
6354 Opc = AArch64::LD3Threev4h;
6356 Opc = AArch64::LD3Threev8h;
6358 Opc = AArch64::LD3Threev2s;
6360 Opc = AArch64::LD3Threev4s;
6362 Opc = AArch64::LD3Threev2d;
6363 else if (Ty ==
S64 || Ty == P0)
6364 Opc = AArch64::LD1Threev1d;
6367 selectVectorLoadIntrinsic(
Opc, 3,
I);
6370 case Intrinsic::aarch64_neon_ld3lane: {
6371 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6374 Opc = AArch64::LD3i8;
6376 Opc = AArch64::LD3i16;
6378 Opc = AArch64::LD3i32;
6381 Opc = AArch64::LD3i64;
6384 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6388 case Intrinsic::aarch64_neon_ld3r: {
6389 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6392 Opc = AArch64::LD3Rv8b;
6394 Opc = AArch64::LD3Rv16b;
6396 Opc = AArch64::LD3Rv4h;
6398 Opc = AArch64::LD3Rv8h;
6400 Opc = AArch64::LD3Rv2s;
6402 Opc = AArch64::LD3Rv4s;
6404 Opc = AArch64::LD3Rv2d;
6405 else if (Ty ==
S64 || Ty == P0)
6406 Opc = AArch64::LD3Rv1d;
6409 selectVectorLoadIntrinsic(
Opc, 3,
I);
6412 case Intrinsic::aarch64_neon_ld4: {
6413 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6416 Opc = AArch64::LD4Fourv8b;
6418 Opc = AArch64::LD4Fourv16b;
6420 Opc = AArch64::LD4Fourv4h;
6422 Opc = AArch64::LD4Fourv8h;
6424 Opc = AArch64::LD4Fourv2s;
6426 Opc = AArch64::LD4Fourv4s;
6428 Opc = AArch64::LD4Fourv2d;
6429 else if (Ty ==
S64 || Ty == P0)
6430 Opc = AArch64::LD1Fourv1d;
6433 selectVectorLoadIntrinsic(
Opc, 4,
I);
6436 case Intrinsic::aarch64_neon_ld4lane: {
6437 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6440 Opc = AArch64::LD4i8;
6442 Opc = AArch64::LD4i16;
6444 Opc = AArch64::LD4i32;
6447 Opc = AArch64::LD4i64;
6450 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6454 case Intrinsic::aarch64_neon_ld4r: {
6455 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6458 Opc = AArch64::LD4Rv8b;
6460 Opc = AArch64::LD4Rv16b;
6462 Opc = AArch64::LD4Rv4h;
6464 Opc = AArch64::LD4Rv8h;
6466 Opc = AArch64::LD4Rv2s;
6468 Opc = AArch64::LD4Rv4s;
6470 Opc = AArch64::LD4Rv2d;
6471 else if (Ty ==
S64 || Ty == P0)
6472 Opc = AArch64::LD4Rv1d;
6475 selectVectorLoadIntrinsic(
Opc, 4,
I);
6478 case Intrinsic::aarch64_neon_st1x2: {
6479 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6482 Opc = AArch64::ST1Twov8b;
6484 Opc = AArch64::ST1Twov16b;
6486 Opc = AArch64::ST1Twov4h;
6488 Opc = AArch64::ST1Twov8h;
6490 Opc = AArch64::ST1Twov2s;
6492 Opc = AArch64::ST1Twov4s;
6494 Opc = AArch64::ST1Twov2d;
6495 else if (Ty ==
S64 || Ty == P0)
6496 Opc = AArch64::ST1Twov1d;
6499 selectVectorStoreIntrinsic(
I, 2,
Opc);
6502 case Intrinsic::aarch64_neon_st1x3: {
6503 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6506 Opc = AArch64::ST1Threev8b;
6508 Opc = AArch64::ST1Threev16b;
6510 Opc = AArch64::ST1Threev4h;
6512 Opc = AArch64::ST1Threev8h;
6514 Opc = AArch64::ST1Threev2s;
6516 Opc = AArch64::ST1Threev4s;
6518 Opc = AArch64::ST1Threev2d;
6519 else if (Ty ==
S64 || Ty == P0)
6520 Opc = AArch64::ST1Threev1d;
6523 selectVectorStoreIntrinsic(
I, 3,
Opc);
6526 case Intrinsic::aarch64_neon_st1x4: {
6527 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6530 Opc = AArch64::ST1Fourv8b;
6532 Opc = AArch64::ST1Fourv16b;
6534 Opc = AArch64::ST1Fourv4h;
6536 Opc = AArch64::ST1Fourv8h;
6538 Opc = AArch64::ST1Fourv2s;
6540 Opc = AArch64::ST1Fourv4s;
6542 Opc = AArch64::ST1Fourv2d;
6543 else if (Ty ==
S64 || Ty == P0)
6544 Opc = AArch64::ST1Fourv1d;
6547 selectVectorStoreIntrinsic(
I, 4,
Opc);
6550 case Intrinsic::aarch64_neon_st2: {
6551 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6554 Opc = AArch64::ST2Twov8b;
6556 Opc = AArch64::ST2Twov16b;
6558 Opc = AArch64::ST2Twov4h;
6560 Opc = AArch64::ST2Twov8h;
6562 Opc = AArch64::ST2Twov2s;
6564 Opc = AArch64::ST2Twov4s;
6566 Opc = AArch64::ST2Twov2d;
6567 else if (Ty ==
S64 || Ty == P0)
6568 Opc = AArch64::ST1Twov1d;
6571 selectVectorStoreIntrinsic(
I, 2,
Opc);
6574 case Intrinsic::aarch64_neon_st3: {
6575 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6578 Opc = AArch64::ST3Threev8b;
6580 Opc = AArch64::ST3Threev16b;
6582 Opc = AArch64::ST3Threev4h;
6584 Opc = AArch64::ST3Threev8h;
6586 Opc = AArch64::ST3Threev2s;
6588 Opc = AArch64::ST3Threev4s;
6590 Opc = AArch64::ST3Threev2d;
6591 else if (Ty ==
S64 || Ty == P0)
6592 Opc = AArch64::ST1Threev1d;
6595 selectVectorStoreIntrinsic(
I, 3,
Opc);
6598 case Intrinsic::aarch64_neon_st4: {
6599 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6602 Opc = AArch64::ST4Fourv8b;
6604 Opc = AArch64::ST4Fourv16b;
6606 Opc = AArch64::ST4Fourv4h;
6608 Opc = AArch64::ST4Fourv8h;
6610 Opc = AArch64::ST4Fourv2s;
6612 Opc = AArch64::ST4Fourv4s;
6614 Opc = AArch64::ST4Fourv2d;
6615 else if (Ty ==
S64 || Ty == P0)
6616 Opc = AArch64::ST1Fourv1d;
6619 selectVectorStoreIntrinsic(
I, 4,
Opc);
6622 case Intrinsic::aarch64_neon_st2lane: {
6623 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6626 Opc = AArch64::ST2i8;
6628 Opc = AArch64::ST2i16;
6630 Opc = AArch64::ST2i32;
6633 Opc = AArch64::ST2i64;
6636 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6640 case Intrinsic::aarch64_neon_st3lane: {
6641 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6644 Opc = AArch64::ST3i8;
6646 Opc = AArch64::ST3i16;
6648 Opc = AArch64::ST3i32;
6651 Opc = AArch64::ST3i64;
6654 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6658 case Intrinsic::aarch64_neon_st4lane: {
6659 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6662 Opc = AArch64::ST4i8;
6664 Opc = AArch64::ST4i16;
6666 Opc = AArch64::ST4i32;
6669 Opc = AArch64::ST4i64;
6672 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6676 case Intrinsic::aarch64_mops_memset_tag: {
6689 Register DstDef =
I.getOperand(0).getReg();
6691 Register DstUse =
I.getOperand(2).getReg();
6692 Register ValUse =
I.getOperand(3).getReg();
6693 Register SizeUse =
I.getOperand(4).getReg();
6700 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6701 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6706 case Intrinsic::ptrauth_resign_load_relative: {
6707 Register DstReg =
I.getOperand(0).getReg();
6708 Register ValReg =
I.getOperand(2).getReg();
6709 uint64_t AUTKey =
I.getOperand(3).getImm();
6710 Register AUTDisc =
I.getOperand(4).getReg();
6711 uint64_t PACKey =
I.getOperand(5).getImm();
6712 Register PACDisc =
I.getOperand(6).getReg();
6713 int64_t Addend =
I.getOperand(7).getImm();
6716 uint16_t AUTConstDiscC = 0;
6717 std::tie(AUTConstDiscC, AUTAddrDisc) =
6721 uint16_t PACConstDiscC = 0;
6722 std::tie(PACConstDiscC, PACAddrDisc) =
6725 MIB.
buildCopy({AArch64::X16}, {ValReg});
6739 I.eraseFromParent();
6744 I.eraseFromParent();
6748bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6749 MachineRegisterInfo &MRI) {
6755 case Intrinsic::ptrauth_resign: {
6756 Register DstReg =
I.getOperand(0).getReg();
6757 Register ValReg =
I.getOperand(2).getReg();
6758 uint64_t AUTKey =
I.getOperand(3).getImm();
6759 Register AUTDisc =
I.getOperand(4).getReg();
6760 uint64_t PACKey =
I.getOperand(5).getImm();
6761 Register PACDisc =
I.getOperand(6).getReg();
6764 uint16_t AUTConstDiscC = 0;
6765 std::tie(AUTConstDiscC, AUTAddrDisc) =
6769 uint16_t PACConstDiscC = 0;
6770 std::tie(PACConstDiscC, PACAddrDisc) =
6773 MIB.
buildCopy({AArch64::X16}, {ValReg});
6774 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6786 I.eraseFromParent();
6789 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6790 Register DstReg =
I.getOperand(0).getReg();
6791 Register ValReg =
I.getOperand(2).getReg();
6792 uint64_t AUTKey =
I.getOperand(3).getImm();
6793 Register AUTDisc =
I.getOperand(4).getReg();
6794 Register AUTPC =
I.getOperand(5).getReg();
6795 uint64_t PACKey =
I.getOperand(6).getImm();
6796 Register PACDisc =
I.getOperand(7).getReg();
6799 "auth_with_pc_and_resign only supports IA and IB keys");
6801 uint16_t PACConstDiscC = 0;
6803 std::tie(PACConstDiscC, PACAddrDisc) =
6806 if (PACAddrDisc == AArch64::NoRegister)
6807 PACAddrDisc = AArch64::XZR;
6809 MIB.
buildCopy({AArch64::X17}, {ValReg});
6810 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6822 I.eraseFromParent();
6825 case Intrinsic::ptrauth_auth: {
6826 Register DstReg =
I.getOperand(0).getReg();
6827 Register ValReg =
I.getOperand(2).getReg();
6828 uint64_t AUTKey =
I.getOperand(3).getImm();
6829 Register AUTDisc =
I.getOperand(4).getReg();
6832 uint16_t AUTConstDiscC = 0;
6833 std::tie(AUTConstDiscC, AUTAddrDisc) =
6837 MIB.
buildCopy({AArch64::X16}, {ValReg});
6838 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6859 I.eraseFromParent();
6862 case Intrinsic::frameaddress:
6863 case Intrinsic::returnaddress: {
6864 MachineFunction &MF = *
I.getParent()->getParent();
6867 unsigned Depth =
I.getOperand(2).getImm();
6868 Register DstReg =
I.getOperand(0).getReg();
6871 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6872 if (!MFReturnAddr) {
6877 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6880 if (STI.hasPAuth()) {
6881 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6888 I.eraseFromParent();
6897 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6899 FrameAddr = NextFrame;
6902 if (IntrinID == Intrinsic::frameaddress)
6907 if (STI.hasPAuth()) {
6909 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6910 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6919 I.eraseFromParent();
6922 case Intrinsic::aarch64_neon_tbl2:
6923 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6925 case Intrinsic::aarch64_neon_tbl3:
6926 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6929 case Intrinsic::aarch64_neon_tbl4:
6930 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6932 case Intrinsic::aarch64_neon_tbx2:
6933 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6935 case Intrinsic::aarch64_neon_tbx3:
6936 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6938 case Intrinsic::aarch64_neon_tbx4:
6939 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6941 case Intrinsic::swift_async_context_addr:
6942 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6949 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6950 I.eraseFromParent();
6985bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6986 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6987 Register DefReg =
I.getOperand(0).getReg();
6988 Register Addr =
I.getOperand(1).getReg();
6989 uint64_t
Key =
I.getOperand(2).getImm();
6990 Register AddrDisc =
I.getOperand(3).getReg();
6991 uint64_t Disc =
I.getOperand(4).getImm();
7001 "constant discriminator in ptrauth global out of range [0, 0xffff]");
7017 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
7029 const GlobalValue *GV;
7040 MachineIRBuilder MIB(
I);
7046 "unsupported non-GOT op flags on ptrauth global reference");
7048 "unsupported non-GOT reference to weak ptrauth global");
7051 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7058 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7059 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7060 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7063 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7068 I.eraseFromParent();
7080 "unsupported non-zero offset in weak ptrauth global reference");
7085 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7086 .addGlobalAddress(GV,
Offset)
7091 I.eraseFromParent();
7095void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7096 MachineRegisterInfo &MRI,
7097 unsigned NumVec,
unsigned Opc1,
7098 unsigned Opc2,
bool isExt) {
7099 Register DstReg =
I.getOperand(0).getReg();
7104 for (
unsigned i = 0; i < NumVec; i++)
7105 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7108 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7109 MachineInstrBuilder
Instr;
7116 I.eraseFromParent();
7119InstructionSelector::ComplexRendererFns
7120AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7122 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7123 return std::nullopt;
7124 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7125 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7128InstructionSelector::ComplexRendererFns
7129AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7131 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7132 return std::nullopt;
7133 uint64_t Enc = 31 - *MaybeImmed;
7134 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7137InstructionSelector::ComplexRendererFns
7138AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7140 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7141 return std::nullopt;
7142 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7143 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7146InstructionSelector::ComplexRendererFns
7147AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7149 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7150 return std::nullopt;
7151 uint64_t Enc = 63 - *MaybeImmed;
7152 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7160InstructionSelector::ComplexRendererFns
7161AArch64InstructionSelector::select12BitValueWithLeftShift(
7162 uint64_t Immed)
const {
7164 if (Immed >> 12 == 0) {
7166 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7168 Immed = Immed >> 12;
7170 return std::nullopt;
7174 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7175 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7182InstructionSelector::ComplexRendererFns
7183AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7190 if (MaybeImmed == std::nullopt)
7191 return std::nullopt;
7192 return select12BitValueWithLeftShift(*MaybeImmed);
7197InstructionSelector::ComplexRendererFns
7198AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7202 return std::nullopt;
7204 if (MaybeImmed == std::nullopt)
7205 return std::nullopt;
7206 uint64_t Immed = *MaybeImmed;
7212 return std::nullopt;
7218 Immed = ~((uint32_t)Immed) + 1;
7220 Immed = ~Immed + 1ULL;
7222 if (Immed & 0xFFFFFFFFFF000000ULL)
7223 return std::nullopt;
7225 Immed &= 0xFFFFFFULL;
7226 return select12BitValueWithLeftShift(Immed);
7243std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7244 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7245 if (
MI.getOpcode() == AArch64::G_SHL) {
7249 MI.getOperand(2).getReg(), MRI)) {
7250 const APInt ShiftVal = ValAndVeg->Value;
7253 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7256 return std::nullopt;
7264bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7265 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7266 bool IsAddrOperand)
const {
7271 MI.getParent()->getParent()->getFunction().hasOptSize())
7274 if (IsAddrOperand) {
7276 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7280 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7281 MachineInstr *OffsetInst =
7287 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7298 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7301InstructionSelector::ComplexRendererFns
7302AArch64InstructionSelector::selectExtendedSHL(
7303 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7304 unsigned SizeInBytes,
bool WantsExt)
const {
7305 assert(
Base.isReg() &&
"Expected base to be a register operand");
7306 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7311 unsigned OffsetOpc = OffsetInst->
getOpcode();
7312 bool LookedThroughZExt =
false;
7313 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7315 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7316 return std::nullopt;
7320 LookedThroughZExt =
true;
7322 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7323 return std::nullopt;
7326 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7327 if (LegalShiftVal == 0)
7328 return std::nullopt;
7329 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7330 return std::nullopt;
7341 if (OffsetOpc == TargetOpcode::G_SHL)
7342 return std::nullopt;
7348 return std::nullopt;
7353 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7357 if (OffsetOpc == TargetOpcode::G_MUL) {
7359 return std::nullopt;
7365 if ((ImmVal & 0x7) != ImmVal)
7366 return std::nullopt;
7370 if (ImmVal != LegalShiftVal)
7371 return std::nullopt;
7373 unsigned SignExtend = 0;
7377 if (!LookedThroughZExt) {
7379 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7381 return std::nullopt;
7386 return std::nullopt;
7392 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7397 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7398 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7399 [=](MachineInstrBuilder &MIB) {
7402 MIB.addImm(SignExtend);
7415InstructionSelector::ComplexRendererFns
7416AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7417 MachineOperand &Root,
unsigned SizeInBytes)
const {
7419 return std::nullopt;
7434 MachineInstr *PtrAdd =
7436 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7437 return std::nullopt;
7441 MachineInstr *OffsetInst =
7443 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7456InstructionSelector::ComplexRendererFns
7457AArch64InstructionSelector::selectAddrModeRegisterOffset(
7458 MachineOperand &Root)
const {
7463 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7464 return std::nullopt;
7470 return std::nullopt;
7473 return {{[=](MachineInstrBuilder &MIB) {
7476 [=](MachineInstrBuilder &MIB) {
7479 [=](MachineInstrBuilder &MIB) {
7489InstructionSelector::ComplexRendererFns
7490AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7491 unsigned SizeInBytes)
const {
7494 return std::nullopt;
7495 MachineInstr *PtrAdd =
7498 return std::nullopt;
7516 unsigned Scale =
Log2_32(SizeInBytes);
7517 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7521 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7522 ImmOff < (0x1000 << Scale))
7523 return std::nullopt;
7528 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7532 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7538 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7539 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7544 return std::nullopt;
7548 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7554 return selectAddrModeRegisterOffset(Root);
7563InstructionSelector::ComplexRendererFns
7564AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7565 unsigned SizeInBytes)
const {
7568 MachineInstr *PtrAdd =
7570 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7571 return std::nullopt;
7592 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7601 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7602 return std::nullopt;
7606 getExtendTypeForInst(*OffsetInst, MRI,
true);
7608 return std::nullopt;
7611 MachineIRBuilder MIB(*PtrAdd);
7613 AArch64::GPR32RegClass, MIB);
7617 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7618 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7619 [=](MachineInstrBuilder &MIB) {
7620 MIB.addImm(SignExtend);
7630InstructionSelector::ComplexRendererFns
7631AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7632 unsigned Size)
const {
7633 MachineRegisterInfo &MRI =
7637 return std::nullopt;
7639 if (!isBaseWithConstantOffset(Root, MRI))
7640 return std::nullopt;
7644 MachineOperand &OffImm = RootDef->
getOperand(2);
7645 if (!OffImm.
isReg())
7646 return std::nullopt;
7648 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7649 return std::nullopt;
7651 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7653 return std::nullopt;
7656 if (RHSC >= -256 && RHSC < 256) {
7659 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7660 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7663 return std::nullopt;
7666InstructionSelector::ComplexRendererFns
7667AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7669 MachineRegisterInfo &MRI)
const {
7670 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7671 return std::nullopt;
7674 return std::nullopt;
7679 return std::nullopt;
7683 return std::nullopt;
7687 return std::nullopt;
7690 MachineIRBuilder MIRBuilder(RootDef);
7692 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7693 [=](MachineInstrBuilder &MIB) {
7694 MIB.addGlobalAddress(GV,
Offset,
7703InstructionSelector::ComplexRendererFns
7704AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7705 unsigned Size)
const {
7710 return std::nullopt;
7713 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7715 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7716 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7724 MachineInstr *RootParent = Root.
getParent();
7726 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7728 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7733 if (isBaseWithConstantOffset(Root, MRI)) {
7741 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7742 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7744 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7745 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7749 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7750 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7757 if (selectAddrModeUnscaled(Root,
Size))
7758 return std::nullopt;
7761 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7762 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7769 switch (
MI.getOpcode()) {
7772 case TargetOpcode::G_SHL:
7774 case TargetOpcode::G_LSHR:
7776 case TargetOpcode::G_ASHR:
7778 case TargetOpcode::G_ROTR:
7785InstructionSelector::ComplexRendererFns
7786AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7787 bool AllowROR)
const {
7789 return std::nullopt;
7790 MachineRegisterInfo &MRI =
7798 return std::nullopt;
7800 return std::nullopt;
7801 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7802 return std::nullopt;
7805 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7808 return std::nullopt;
7812 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7816 unsigned Val = *Immed & (NumBits - 1);
7819 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7820 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7824 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7825 unsigned Opc =
MI.getOpcode();
7828 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7830 if (
Opc == TargetOpcode::G_SEXT)
7833 Size =
MI.getOperand(2).getImm();
7834 assert(
Size != 64 &&
"Extend from 64 bits?");
7847 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7849 assert(
Size != 64 &&
"Extend from 64 bits?");
7864 if (
Opc != TargetOpcode::G_AND)
7870 uint64_t AndMask = *MaybeAndMask;
7883Register AArch64InstructionSelector::moveScalarRegClass(
7885 MachineRegisterInfo &MRI = *MIB.
getMRI();
7895 return Copy.getReg(0);
7900InstructionSelector::ComplexRendererFns
7901AArch64InstructionSelector::selectArithExtendedRegister(
7902 MachineOperand &Root)
const {
7904 return std::nullopt;
7905 MachineRegisterInfo &MRI =
7908 uint64_t ShiftVal = 0;
7913 return std::nullopt;
7915 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7916 return std::nullopt;
7919 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7924 return std::nullopt;
7925 ShiftVal = *MaybeShiftVal;
7927 return std::nullopt;
7932 return std::nullopt;
7933 Ext = getExtendTypeForInst(*ExtDef, MRI);
7935 return std::nullopt;
7939 Ext = getExtendTypeForInst(*RootDef, MRI);
7941 return std::nullopt;
7949 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7950 if (isDef32(*ExtInst))
7951 return std::nullopt;
7957 MachineIRBuilder MIB(*RootDef);
7958 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7960 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7961 [=](MachineInstrBuilder &MIB) {
7962 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7966InstructionSelector::ComplexRendererFns
7967AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7969 return std::nullopt;
7970 MachineRegisterInfo &MRI =
7974 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7979 return std::nullopt;
7982 if (Unmerge->getNumDefs() == 2 &&
7984 Register ExtReg = Unmerge->getSourceReg();
7985 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7989 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7993 LaneIdx->Value.getSExtValue() == 1) {
7994 Register ExtReg = ExtElt->getVectorReg();
7995 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7999 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
8000 auto LaneIdx = Subvec->getIndexImm();
8002 Register ExtReg = Subvec->getSrcVec();
8003 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8007 return std::nullopt;
8010InstructionSelector::ComplexRendererFns
8011AArch64InstructionSelector::selectCVTFixedPointVecBase(
8012 const MachineOperand &Root,
bool isReciprocal)
const {
8014 return std::nullopt;
8015 const MachineRegisterInfo &MRI =
8020 return std::nullopt;
8021 std::optional<ValueAndVReg> CstVal =
8024 return std::nullopt;
8030 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
8033 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8036 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8039 return std::nullopt;
8041 if (
unsigned FBits =
8043 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8045 return std::nullopt;
8048InstructionSelector::ComplexRendererFns
8049AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8050 return selectCVTFixedPointVecBase(Root,
false);
8053InstructionSelector::ComplexRendererFns
8054AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8055 MachineOperand &Root)
const {
8056 return selectCVTFixedPointVecBase(Root,
true);
8059void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8060 const MachineInstr &
MI,
8065 InstructionSelector::ComplexRendererFns Renderer =
8066 selectCVTFixedPointVecBase(
MI.getOperand(
OpIdx),
false);
8067 assert((Renderer && Renderer->size() == 1) &&
8068 "Expected selectCVTFixedPointVec to provide a function\n");
8069 (Renderer->front())(MIB);
8072void AArch64InstructionSelector::renderFixedPointRecipXForm(
8073 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8074 InstructionSelector::ComplexRendererFns Renderer =
8075 selectCVTFixedPointVecBase(
MI.getOperand(
OpIdx),
true);
8076 assert((Renderer && Renderer->size() == 1) &&
8077 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
8078 (Renderer->front())(MIB);
8081void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8082 const MachineInstr &
MI,
8084 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8085 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8086 "Expected G_CONSTANT");
8087 std::optional<int64_t> CstVal =
8089 assert(CstVal &&
"Expected constant value");
8093void AArch64InstructionSelector::renderLogicalImm32(
8094 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8095 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8096 "Expected G_CONSTANT");
8097 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8102void AArch64InstructionSelector::renderLogicalImm64(
8103 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8104 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8105 "Expected G_CONSTANT");
8106 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8111void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8112 const MachineInstr &
MI,
8114 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
8115 "Expected G_UBSANTRAP");
8116 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8119void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8120 const MachineInstr &
MI,
8122 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8123 "Expected G_FCONSTANT");
8128void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8129 const MachineInstr &
MI,
8131 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8132 "Expected G_FCONSTANT");
8137void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8138 const MachineInstr &
MI,
8140 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8141 "Expected G_FCONSTANT");
8146void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8147 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8148 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8149 "Expected G_FCONSTANT");
8157bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8158 const MachineInstr &
MI,
unsigned NumBytes)
const {
8159 if (!
MI.mayLoadOrStore())
8162 "Expected load/store to have only one mem op!");
8163 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8166bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8167 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8175 switch (
MI.getOpcode()) {
8178 case TargetOpcode::COPY:
8179 case TargetOpcode::G_BITCAST:
8180 case TargetOpcode::G_TRUNC:
8181 case TargetOpcode::G_PHI:
8191 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8194 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8212 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8217 MO.setReg(Copy.getReg(0));
8222void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8226 for (
auto &BB : MF) {
8227 for (
auto &
MI : BB) {
8228 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8233 for (
auto *
MI : Phis) {
8255 bool HasGPROp =
false, HasFPROp =
false;
8259 const LLT &Ty = MRI.
getType(MO.getReg());
8269 if (RB->
getID() == AArch64::GPRRegBankID)
8275 if (HasGPROp && HasFPROp)
8281InstructionSelector *
8285 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
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.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
void assign(size_type NumElts, ValueParamT Elt)
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.
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.
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...
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
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.
@ O1
Optimize quickly without destroying debuggability.
@ O0
Disable as many optimizations as possible.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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.
MCRegisterClass TargetRegisterClass
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.