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);
2149 if (PtrSize != 32 && PtrSize != 64)
2155 case TargetOpcode::G_STORE: {
2156 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2157 MachineOperand &SrcOp =
I.getOperand(0);
2170 case TargetOpcode::G_PTR_ADD: {
2174 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2176 return convertPtrAddToAdd(
I, MRI);
2178 case TargetOpcode::G_LOAD: {
2183 Register DstReg =
I.getOperand(0).getReg();
2184 const LLT DstTy = MRI.
getType(DstReg);
2190 case AArch64::G_DUP: {
2192 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2196 MRI.
setType(
I.getOperand(0).getReg(),
2198 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2199 I.getOperand(1).setReg(NewSrc.getReg(0));
2202 case AArch64::G_INSERT_VECTOR_ELT: {
2203 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2204 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2208 MRI.
setType(
I.getOperand(1).getReg(),
2210 MRI.
setType(
I.getOperand(0).getReg(),
2212 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2213 I.getOperand(2).setReg(NewSrc.getReg(0));
2217 Register EltReg =
I.getOperand(2).getReg();
2218 LLT EltTy = MRI.
getType(EltReg);
2224 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2225 I.getOperand(2).setReg(NewElt.getReg(0));
2230 case TargetOpcode::G_UITOFP:
2231 case TargetOpcode::G_SITOFP: {
2236 Register SrcReg =
I.getOperand(1).getReg();
2237 LLT SrcTy = MRI.
getType(SrcReg);
2238 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2247 I.getOperand(1).setReg(
Copy.getReg(0));
2249 getRegClassForTypeOnBank(
2250 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2252 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2253 I.setDesc(
TII.get(AArch64::G_SITOF));
2255 I.setDesc(
TII.get(AArch64::G_UITOF));
2273bool AArch64InstructionSelector::convertPtrAddToAdd(
2274 MachineInstr &
I, MachineRegisterInfo &MRI) {
2275 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2276 Register DstReg =
I.getOperand(0).getReg();
2277 Register AddOp1Reg =
I.getOperand(1).getReg();
2278 const LLT PtrTy = MRI.
getType(DstReg);
2282 const LLT CastPtrTy = PtrTy.
isVector()
2294 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2295 MRI.
setType(DstReg, CastPtrTy);
2296 I.getOperand(1).setReg(PtrToInt.getReg(0));
2297 if (!select(*PtrToInt)) {
2298 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2307 I.getOperand(2).setReg(NegatedReg);
2308 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2312bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2313 MachineRegisterInfo &MRI) {
2317 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2318 const auto &MO =
I.getOperand(2);
2323 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2327 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2328 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2330 if (!Imm1Fn || !Imm2Fn)
2334 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2335 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2337 for (
auto &RenderFn : *Imm1Fn)
2339 for (
auto &RenderFn : *Imm2Fn)
2342 I.eraseFromParent();
2347bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2348 MachineInstr &
I, MachineRegisterInfo &MRI) {
2349 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2367 LLT DefDstTy = MRI.
getType(DefDstReg);
2368 Register StoreSrcReg =
I.getOperand(0).getReg();
2369 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2385 I.getOperand(0).setReg(DefDstReg);
2389bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2390 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2391 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2397 switch (
I.getOpcode()) {
2398 case AArch64::G_DUP: {
2401 Register Src =
I.getOperand(1).getReg();
2403 Src, MRI,
true,
true);
2407 Register Dst =
I.getOperand(0).getReg();
2413 if (!emitConstantVector(Dst, CV, MIB, MRI))
2415 I.eraseFromParent();
2418 case TargetOpcode::G_SEXT:
2421 if (selectUSMovFromExtend(
I, MRI))
2424 case TargetOpcode::G_BR:
2426 case TargetOpcode::G_SHL:
2427 return earlySelectSHL(
I, MRI);
2428 case TargetOpcode::G_CONSTANT: {
2429 bool IsZero =
false;
2430 if (
I.getOperand(1).isCImm())
2431 IsZero =
I.getOperand(1).getCImm()->isZero();
2432 else if (
I.getOperand(1).isImm())
2433 IsZero =
I.getOperand(1).getImm() == 0;
2438 Register DefReg =
I.getOperand(0).getReg();
2441 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2444 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2449 I.setDesc(
TII.get(TargetOpcode::COPY));
2453 case TargetOpcode::G_ADD: {
2462 Register AddDst =
I.getOperand(0).getReg();
2463 Register AddLHS =
I.getOperand(1).getReg();
2464 Register AddRHS =
I.getOperand(2).getReg();
2474 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2495 MachineInstr *
Cmp = MatchCmp(AddRHS);
2499 Cmp = MatchCmp(AddRHS);
2503 auto &PredOp =
Cmp->getOperand(1);
2505 emitIntegerCompare(
Cmp->getOperand(2),
2506 Cmp->getOperand(3), PredOp, MIB);
2510 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2511 I.eraseFromParent();
2514 case TargetOpcode::G_OR: {
2518 Register Dst =
I.getOperand(0).getReg();
2538 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2541 int64_t Immr =
Size - ShiftImm;
2542 int64_t Imms =
Size - ShiftImm - 1;
2543 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2544 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2545 I.eraseFromParent();
2548 case TargetOpcode::G_FENCE: {
2549 if (
I.getOperand(1).getImm() == 0)
2553 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2554 I.eraseFromParent();
2562bool AArch64InstructionSelector::select(MachineInstr &
I) {
2563 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2564 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2570 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2571 if (Subtarget->requiresStrictAlign()) {
2573 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2579 unsigned Opcode =
I.getOpcode();
2581 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2584 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2589 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2590 const Register DefReg =
I.getOperand(0).getReg();
2591 const LLT DefTy = MRI.
getType(DefReg);
2604 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2611 I.setDesc(
TII.get(TargetOpcode::PHI));
2619 if (
I.isDebugInstr())
2626 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2628 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2635 if (preISelLower(
I)) {
2636 Opcode =
I.getOpcode();
2647 if (selectImpl(
I, *CoverageInfo))
2651 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2654 case TargetOpcode::G_SBFX:
2655 case TargetOpcode::G_UBFX: {
2656 static const unsigned OpcTable[2][2] = {
2657 {AArch64::UBFMWri, AArch64::UBFMXri},
2658 {AArch64::SBFMWri, AArch64::SBFMXri}};
2659 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2661 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2664 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2667 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2668 auto LSB = Cst1->Value.getZExtValue();
2669 auto Width = Cst2->Value.getZExtValue();
2673 .
addImm(LSB + Width - 1);
2674 I.eraseFromParent();
2678 case TargetOpcode::G_BRCOND:
2679 return selectCompareBranch(
I, MF, MRI);
2681 case TargetOpcode::G_BRINDIRECT: {
2683 if (std::optional<uint16_t> BADisc =
2685 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2688 MI.addReg(AArch64::XZR);
2689 I.eraseFromParent();
2693 I.setDesc(
TII.get(AArch64::BR));
2698 case TargetOpcode::G_BRJT:
2699 return selectBrJT(
I, MRI);
2701 case AArch64::G_ADD_LOW: {
2706 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2707 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2708 I.setDesc(
TII.get(AArch64::ADDXri));
2714 "Expected small code model");
2716 auto Op2 =
I.getOperand(2);
2717 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2718 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2719 Op1.getTargetFlags())
2721 Op2.getTargetFlags());
2722 I.eraseFromParent();
2727 case TargetOpcode::G_FCONSTANT: {
2728 const Register DefReg =
I.getOperand(0).getReg();
2729 const LLT DefTy = MRI.
getType(DefReg);
2740 bool OptForSize = shouldOptForSize(&MF);
2744 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2751 auto *FPImm =
I.getOperand(1).getFPImm();
2754 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2757 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2758 I.eraseFromParent();
2763 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2766 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2767 MachineOperand &RegOp =
I.getOperand(0);
2773 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2777 MachineOperand &ImmOp =
I.getOperand(1);
2781 const unsigned MovOpc =
2782 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2783 I.setDesc(
TII.get(MovOpc));
2787 case TargetOpcode::G_EXTRACT: {
2788 Register DstReg =
I.getOperand(0).getReg();
2789 Register SrcReg =
I.getOperand(1).getReg();
2790 LLT SrcTy = MRI.
getType(SrcReg);
2791 LLT DstTy = MRI.
getType(DstReg);
2803 unsigned Offset =
I.getOperand(2).getImm();
2808 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2809 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2812 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2814 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2816 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2818 AArch64::GPR64RegClass, NewI->getOperand(0));
2819 I.eraseFromParent();
2825 unsigned LaneIdx =
Offset / 64;
2826 MachineInstr *Extract = emitExtractVectorElt(
2827 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2830 I.eraseFromParent();
2834 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2835 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2840 "unexpected G_EXTRACT types");
2847 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2848 .addReg(DstReg, {}, AArch64::sub_32);
2850 AArch64::GPR32RegClass, MRI);
2851 I.getOperand(0).setReg(DstReg);
2857 case TargetOpcode::G_INSERT: {
2858 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2859 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2866 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2867 unsigned LSB =
I.getOperand(3).getImm();
2869 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2870 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2874 "unexpected G_INSERT types");
2881 TII.get(AArch64::SUBREG_TO_REG))
2883 .
addUse(
I.getOperand(2).getReg())
2884 .
addImm(AArch64::sub_32);
2886 AArch64::GPR32RegClass, MRI);
2887 I.getOperand(2).setReg(SrcReg);
2892 case TargetOpcode::G_FRAME_INDEX: {
2899 I.setDesc(
TII.get(AArch64::ADDXri));
2909 case TargetOpcode::G_GLOBAL_VALUE: {
2910 const GlobalValue *GV =
nullptr;
2912 if (
I.getOperand(1).isSymbol()) {
2913 OpFlags =
I.getOperand(1).getTargetFlags();
2922 return selectTLSGlobalValue(
I, MRI);
2928 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2929 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2930 I.getOperand(1).setTargetFlags(OpFlags);
2931 I.addImplicitDefUseOperands(MF);
2935 materializeLargeCMVal(
I, GV, OpFlags);
2936 I.eraseFromParent();
2939 I.setDesc(
TII.get(AArch64::ADR));
2940 I.getOperand(1).setTargetFlags(OpFlags);
2942 I.setDesc(
TII.get(AArch64::MOVaddr));
2944 MachineInstrBuilder MIB(MF,
I);
2945 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2952 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2953 return selectPtrAuthGlobalValue(
I, MRI);
2955 case TargetOpcode::G_ZEXTLOAD:
2956 case TargetOpcode::G_LOAD:
2957 case TargetOpcode::G_STORE: {
2959 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2974 assert(MemSizeInBytes <= 8 &&
2975 "128-bit atomics should already be custom-legalized");
2978 static constexpr unsigned LDAPROpcodes[] = {
2979 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2980 static constexpr unsigned LDAROpcodes[] = {
2981 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2982 ArrayRef<unsigned> Opcodes =
2983 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2986 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2988 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2989 AArch64::STLRW, AArch64::STLRX};
2994 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2995 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2996 I.getOperand(0).setReg(NewVal);
2998 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
3006 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
3009 "Load/Store pointer operand isn't a GPR");
3011 "Load/Store pointer operand isn't a pointer");
3016 LLT ValTy = MRI.
getType(ValReg);
3023 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3029 .addReg(ValReg, {}, SubReg)
3036 if (RB.
getID() == AArch64::FPRRegBankID) {
3039 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3049 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3052 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3061 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3063 const unsigned NewOpc =
3065 if (NewOpc ==
I.getOpcode())
3069 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3072 I.setDesc(
TII.get(NewOpc));
3078 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3079 Register CurValReg =
I.getOperand(0).getReg();
3080 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3081 NewInst.cloneMemRefs(
I);
3082 for (
auto &Fn : *AddrModeFns)
3084 I.eraseFromParent();
3088 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3093 if (Opcode == TargetOpcode::G_STORE) {
3095 LoadStore->getOperand(0).getReg(), MRI);
3096 if (CVal && CVal->Value == 0) {
3098 case AArch64::STRWui:
3099 case AArch64::STRHHui:
3100 case AArch64::STRBBui:
3101 LoadStore->getOperand(0).setReg(AArch64::WZR);
3103 case AArch64::STRXui:
3104 LoadStore->getOperand(0).setReg(AArch64::XZR);
3110 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3111 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3123 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3125 .
addImm(AArch64::sub_32);
3134 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3135 case TargetOpcode::G_INDEXED_SEXTLOAD:
3136 return selectIndexedExtLoad(
I, MRI);
3137 case TargetOpcode::G_INDEXED_LOAD:
3138 return selectIndexedLoad(
I, MRI);
3139 case TargetOpcode::G_INDEXED_STORE:
3142 case TargetOpcode::G_LSHR:
3143 case TargetOpcode::G_ASHR:
3145 return selectVectorAshrLshr(
I, MRI);
3147 case TargetOpcode::G_SHL:
3148 if (Opcode == TargetOpcode::G_SHL &&
3150 return selectVectorSHL(
I, MRI);
3157 Register SrcReg =
I.getOperand(1).getReg();
3158 Register ShiftReg =
I.getOperand(2).getReg();
3159 const LLT ShiftTy = MRI.
getType(ShiftReg);
3160 const LLT SrcTy = MRI.
getType(SrcReg);
3165 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3166 .addReg(ShiftReg, {}, AArch64::sub_32);
3168 I.getOperand(2).setReg(Trunc.getReg(0));
3172 case TargetOpcode::G_OR: {
3179 const Register DefReg =
I.getOperand(0).getReg();
3183 if (NewOpc ==
I.getOpcode())
3186 I.setDesc(
TII.get(NewOpc));
3195 case TargetOpcode::G_PTR_ADD: {
3196 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3197 I.eraseFromParent();
3201 case TargetOpcode::G_SADDE:
3202 case TargetOpcode::G_UADDE:
3203 case TargetOpcode::G_SSUBE:
3204 case TargetOpcode::G_USUBE:
3205 case TargetOpcode::G_SADDO:
3206 case TargetOpcode::G_UADDO:
3207 case TargetOpcode::G_SSUBO:
3208 case TargetOpcode::G_USUBO:
3209 return selectOverflowOp(
I, MRI);
3211 case TargetOpcode::G_PTRMASK: {
3212 Register MaskReg =
I.getOperand(2).getReg();
3218 uint64_t
Mask = *MaskVal;
3219 I.setDesc(
TII.get(AArch64::ANDXri));
3220 I.getOperand(2).ChangeToImmediate(
3226 case TargetOpcode::G_PTRTOINT:
3227 case TargetOpcode::G_TRUNC: {
3228 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3229 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3231 const Register DstReg =
I.getOperand(0).getReg();
3232 const Register SrcReg =
I.getOperand(1).getReg();
3234 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3235 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3239 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3243 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3254 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3258 if (DstRC == SrcRC) {
3260 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3264 }
else if (DstRC == &AArch64::GPR32RegClass &&
3265 SrcRC == &AArch64::GPR64RegClass) {
3266 I.getOperand(1).setSubReg(AArch64::sub_32);
3269 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3273 I.setDesc(
TII.get(TargetOpcode::COPY));
3275 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3278 I.setDesc(
TII.get(AArch64::XTNv4i16));
3284 MachineInstr *Extract = emitExtractVectorElt(
3288 I.eraseFromParent();
3293 if (Opcode == TargetOpcode::G_PTRTOINT) {
3294 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3295 I.setDesc(
TII.get(TargetOpcode::COPY));
3303 case TargetOpcode::G_ANYEXT: {
3304 if (selectUSMovFromExtend(
I, MRI))
3307 const Register DstReg =
I.getOperand(0).getReg();
3308 const Register SrcReg =
I.getOperand(1).getReg();
3310 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3311 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3313 <<
", expected: GPR\n");
3317 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3318 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3320 <<
", expected: GPR\n");
3327 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3331 if (DstSize != 64 && DstSize > 32) {
3333 <<
", expected: 32 or 64\n");
3343 .
addImm(AArch64::sub_32);
3344 I.getOperand(1).setReg(ExtSrc);
3349 case TargetOpcode::G_ZEXT:
3350 case TargetOpcode::G_SEXT_INREG:
3351 case TargetOpcode::G_SEXT: {
3352 if (selectUSMovFromExtend(
I, MRI))
3355 unsigned Opcode =
I.getOpcode();
3356 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3357 const Register DefReg =
I.getOperand(0).getReg();
3358 Register SrcReg =
I.getOperand(1).getReg();
3359 const LLT DstTy = MRI.
getType(DefReg);
3360 const LLT SrcTy = MRI.
getType(SrcReg);
3366 if (Opcode == TargetOpcode::G_SEXT_INREG)
3367 SrcSize =
I.getOperand(2).getImm();
3373 AArch64::GPRRegBankID &&
3374 "Unexpected ext regbank");
3385 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3388 if (LoadMI && IsGPR) {
3389 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3390 unsigned BytesLoaded = MemOp->getSize().getValue();
3397 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3400 const Register ZReg = AArch64::WZR;
3401 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3404 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3405 .addUse(SubregToRegSrc)
3406 .
addImm(AArch64::sub_32);
3410 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3420 I.eraseFromParent();
3425 if (DstSize == 64) {
3426 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3434 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3435 {&AArch64::GPR64RegClass}, {})
3441 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3445 }
else if (DstSize <= 32) {
3446 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3455 I.eraseFromParent();
3459 case TargetOpcode::G_FREEZE:
3462 case TargetOpcode::G_INTTOPTR:
3467 case TargetOpcode::G_BITCAST:
3475 case TargetOpcode::G_SELECT: {
3477 const Register CondReg = Sel.getCondReg();
3479 const Register FReg = Sel.getFalseReg();
3481 if (tryOptSelect(Sel))
3487 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3492 Sel.eraseFromParent();
3495 case TargetOpcode::G_ICMP: {
3505 auto &PredOp =
I.getOperand(1);
3506 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3510 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3511 AArch64::WZR, InvCC, MIB);
3512 I.eraseFromParent();
3516 case TargetOpcode::G_FCMP: {
3519 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3521 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3523 I.eraseFromParent();
3526 case TargetOpcode::G_VASTART:
3528 : selectVaStartAAPCS(
I, MF, MRI);
3529 case TargetOpcode::G_INTRINSIC:
3530 return selectIntrinsic(
I, MRI);
3531 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3532 return selectIntrinsicWithSideEffects(
I, MRI);
3533 case TargetOpcode::G_IMPLICIT_DEF: {
3534 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3535 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3536 const Register DstReg =
I.getOperand(0).getReg();
3537 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3542 case TargetOpcode::G_BLOCK_ADDR: {
3543 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3544 if (std::optional<uint16_t> BADisc =
3546 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3547 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3556 AArch64::GPR64RegClass, MRI);
3557 I.eraseFromParent();
3561 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3562 I.eraseFromParent();
3565 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3566 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3567 I.getOperand(0).getReg())
3571 I.getOperand(1).getBlockAddress(), 0,
3573 I.eraseFromParent();
3578 case AArch64::G_DUP: {
3585 AArch64::GPRRegBankID)
3587 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3589 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3591 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3593 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3595 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3601 case TargetOpcode::G_BUILD_VECTOR:
3602 return selectBuildVector(
I, MRI);
3603 case TargetOpcode::G_MERGE_VALUES:
3605 case TargetOpcode::G_UNMERGE_VALUES:
3607 case TargetOpcode::G_SHUFFLE_VECTOR:
3608 return selectShuffleVector(
I, MRI);
3609 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3610 return selectExtractElt(
I, MRI);
3611 case TargetOpcode::G_CONCAT_VECTORS:
3612 return selectConcatVectors(
I, MRI);
3613 case TargetOpcode::G_JUMP_TABLE:
3614 return selectJumpTable(
I, MRI);
3615 case TargetOpcode::G_MEMCPY:
3616 case TargetOpcode::G_MEMCPY_INLINE:
3617 case TargetOpcode::G_MEMMOVE:
3618 case TargetOpcode::G_MEMSET:
3619 case TargetOpcode::G_MEMSET_INLINE:
3620 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3621 return selectMOPS(
I, MRI);
3627bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3628 MachineIRBuilderState OldMIBState = MIB.
getState();
3634bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3635 MachineRegisterInfo &MRI) {
3638 case TargetOpcode::G_MEMCPY:
3639 case TargetOpcode::G_MEMCPY_INLINE:
3640 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3642 case TargetOpcode::G_MEMMOVE:
3643 Mopcode = AArch64::MOPSMemoryMovePseudo;
3645 case TargetOpcode::G_MEMSET:
3646 case TargetOpcode::G_MEMSET_INLINE:
3648 Mopcode = AArch64::MOPSMemorySetPseudo;
3661 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3662 const auto &SrcValRegClass =
3663 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3681 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3682 {DstPtrCopy, SizeCopy, SrcValCopy});
3685 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3686 {DstPtrCopy, SrcValCopy, SizeCopy});
3693bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3694 MachineRegisterInfo &MRI) {
3695 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3696 Register JTAddr =
I.getOperand(0).getReg();
3697 unsigned JTI =
I.getOperand(1).getIndex();
3700 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3712 "jump table hardening only supported on MachO/ELF");
3720 I.eraseFromParent();
3727 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3728 {TargetReg, ScratchReg}, {JTAddr,
Index})
3729 .addJumpTableIndex(JTI);
3731 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3732 {
static_cast<int64_t
>(JTI)});
3734 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3735 I.eraseFromParent();
3740bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3741 MachineRegisterInfo &MRI) {
3742 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3743 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3745 Register DstReg =
I.getOperand(0).getReg();
3746 unsigned JTI =
I.getOperand(1).getIndex();
3749 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3752 I.eraseFromParent();
3757bool AArch64InstructionSelector::selectTLSGlobalValue(
3758 MachineInstr &
I, MachineRegisterInfo &MRI) {
3761 MachineFunction &MF = *
I.getParent()->getParent();
3764 const auto &GlobalOp =
I.getOperand(1);
3765 assert(GlobalOp.getOffset() == 0 &&
3766 "Shouldn't have an offset on TLS globals!");
3767 const GlobalValue &GV = *GlobalOp.getGlobal();
3770 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3773 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3774 {LoadGOT.getReg(0)})
3785 assert(Opcode == AArch64::BLR);
3786 Opcode = AArch64::BLRAAZ;
3790 .addUse(AArch64::X0, RegState::Implicit)
3791 .
addDef(AArch64::X0, RegState::Implicit)
3797 I.eraseFromParent();
3801MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3803 MachineIRBuilder &MIRBuilder)
const {
3804 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3806 auto BuildFn = [&](
unsigned SubregIndex) {
3810 .addImm(SubregIndex);
3818 return BuildFn(AArch64::bsub);
3820 return BuildFn(AArch64::hsub);
3822 return BuildFn(AArch64::ssub);
3824 return BuildFn(AArch64::dsub);
3831AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3832 MachineIRBuilder &MIB,
3833 MachineRegisterInfo &MRI)
const {
3834 LLT DstTy = MRI.
getType(DstReg);
3836 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3837 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3841 unsigned SubReg = 0;
3844 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3850 .addReg(SrcReg, {}, SubReg);
3855bool AArch64InstructionSelector::selectMergeValues(
3856 MachineInstr &
I, MachineRegisterInfo &MRI) {
3857 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3858 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3859 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3861 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3863 if (
I.getNumOperands() != 3)
3870 Register DstReg =
I.getOperand(0).getReg();
3871 Register Src1Reg =
I.getOperand(1).getReg();
3872 Register Src2Reg =
I.getOperand(2).getReg();
3873 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3874 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3878 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3879 Src2Reg, 1, RB, MIB);
3884 I.eraseFromParent();
3888 if (RB.
getID() != AArch64::GPRRegBankID)
3894 auto *DstRC = &AArch64::GPR64RegClass;
3896 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3897 TII.get(TargetOpcode::SUBREG_TO_REG))
3899 .
addUse(
I.getOperand(1).getReg())
3900 .
addImm(AArch64::sub_32);
3903 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3904 TII.get(TargetOpcode::SUBREG_TO_REG))
3906 .
addUse(
I.getOperand(2).getReg())
3907 .
addImm(AArch64::sub_32);
3909 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3910 .
addDef(
I.getOperand(0).getReg())
3918 I.eraseFromParent();
3923 const unsigned EltSize) {
3928 CopyOpc = AArch64::DUPi8;
3929 ExtractSubReg = AArch64::bsub;
3932 CopyOpc = AArch64::DUPi16;
3933 ExtractSubReg = AArch64::hsub;
3936 CopyOpc = AArch64::DUPi32;
3937 ExtractSubReg = AArch64::ssub;
3940 CopyOpc = AArch64::DUPi64;
3941 ExtractSubReg = AArch64::dsub;
3945 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3951MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3952 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3953 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3954 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3955 unsigned CopyOpc = 0;
3956 unsigned ExtractSubReg = 0;
3959 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3964 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3966 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3970 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3971 const LLT &VecTy = MRI.
getType(VecReg);
3973 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3975 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3985 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3986 .addReg(VecReg, {}, ExtractSubReg);
3995 MachineInstr *ScalarToVector = emitScalarToVector(
3996 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3997 if (!ScalarToVector)
4002 MachineInstr *LaneCopyMI =
4003 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4011bool AArch64InstructionSelector::selectExtractElt(
4012 MachineInstr &
I, MachineRegisterInfo &MRI) {
4013 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4014 "unexpected opcode!");
4015 Register DstReg =
I.getOperand(0).getReg();
4016 const LLT NarrowTy = MRI.
getType(DstReg);
4017 const Register SrcReg =
I.getOperand(1).getReg();
4018 const LLT WideTy = MRI.
getType(SrcReg);
4020 "source register size too small!");
4021 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4024 MachineOperand &LaneIdxOp =
I.getOperand(2);
4025 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4031 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4033 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4034 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4038 Opcode = AArch64::UMOVvi8;
4041 Opcode = AArch64::UMOVvi16;
4044 Opcode = AArch64::UMOVvi32;
4051 MachineInstr *ScalarToVector = emitScalarToVector(
4052 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4053 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4057 I.setDesc(
TII.get(Opcode));
4058 I.getOperand(2).ChangeToImmediate(LaneIdx);
4063 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4068 I.eraseFromParent();
4072bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4073 MachineInstr &
I, MachineRegisterInfo &MRI) {
4074 unsigned NumElts =
I.getNumOperands() - 1;
4075 Register SrcReg =
I.getOperand(NumElts).getReg();
4076 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4077 const LLT SrcTy = MRI.
getType(SrcReg);
4079 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4081 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4087 const RegisterBank &DstRB =
4091 MachineInstr *Extract =
4092 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4096 I.eraseFromParent();
4100bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4101 MachineRegisterInfo &MRI) {
4102 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4103 "unexpected opcode");
4107 AArch64::FPRRegBankID ||
4109 AArch64::FPRRegBankID) {
4110 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4111 "currently unsupported.\n");
4117 unsigned NumElts =
I.getNumOperands() - 1;
4118 Register SrcReg =
I.getOperand(NumElts).getReg();
4119 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4120 const LLT WideTy = MRI.
getType(SrcReg);
4123 "source register size too small!");
4126 return selectSplitVectorUnmerge(
I, MRI);
4130 unsigned CopyOpc = 0;
4131 unsigned ExtractSubReg = 0;
4142 unsigned NumInsertRegs = NumElts - 1;
4148 InsertRegs.
assign(NumInsertRegs, SrcReg);
4157 unsigned SubReg = 0;
4160 assert(Found &&
"expected to find last operand's subeg idx");
4161 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4163 MachineInstr &ImpDefMI =
4164 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4169 MachineInstr &InsMI =
4171 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4188 Register CopyTo =
I.getOperand(0).getReg();
4189 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4190 .addReg(InsertRegs[0], {}, ExtractSubReg);
4194 unsigned LaneIdx = 1;
4195 for (
Register InsReg : InsertRegs) {
4196 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4197 MachineInstr &CopyInst =
4216 I.eraseFromParent();
4220bool AArch64InstructionSelector::selectConcatVectors(
4221 MachineInstr &
I, MachineRegisterInfo &MRI) {
4222 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4223 "Unexpected opcode");
4224 Register Dst =
I.getOperand(0).getReg();
4225 Register Op1 =
I.getOperand(1).getReg();
4226 Register Op2 =
I.getOperand(2).getReg();
4227 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4230 I.eraseFromParent();
4235AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4236 MachineFunction &MF)
const {
4244MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4245 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4252 RC = &AArch64::FPR128RegClass;
4253 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4256 RC = &AArch64::FPR64RegClass;
4257 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4260 RC = &AArch64::FPR32RegClass;
4261 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4264 RC = &AArch64::FPR16RegClass;
4265 Opc = AArch64::LDRHui;
4268 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4273 MachineInstr *LoadMI =
nullptr;
4274 auto &MF = MIRBuilder.
getMF();
4275 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4276 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4278 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4281 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4285 .addConstantPoolIndex(
4301static std::pair<unsigned, unsigned>
4303 unsigned Opc, SubregIdx;
4304 if (RB.
getID() == AArch64::GPRRegBankID) {
4306 Opc = AArch64::INSvi8gpr;
4307 SubregIdx = AArch64::bsub;
4308 }
else if (EltSize == 16) {
4309 Opc = AArch64::INSvi16gpr;
4310 SubregIdx = AArch64::ssub;
4311 }
else if (EltSize == 32) {
4312 Opc = AArch64::INSvi32gpr;
4313 SubregIdx = AArch64::ssub;
4314 }
else if (EltSize == 64) {
4315 Opc = AArch64::INSvi64gpr;
4316 SubregIdx = AArch64::dsub;
4322 Opc = AArch64::INSvi8lane;
4323 SubregIdx = AArch64::bsub;
4324 }
else if (EltSize == 16) {
4325 Opc = AArch64::INSvi16lane;
4326 SubregIdx = AArch64::hsub;
4327 }
else if (EltSize == 32) {
4328 Opc = AArch64::INSvi32lane;
4329 SubregIdx = AArch64::ssub;
4330 }
else if (EltSize == 64) {
4331 Opc = AArch64::INSvi64lane;
4332 SubregIdx = AArch64::dsub;
4337 return std::make_pair(
Opc, SubregIdx);
4340MachineInstr *AArch64InstructionSelector::emitInstr(
4341 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4342 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4343 const ComplexRendererFns &RenderFns)
const {
4344 assert(Opcode &&
"Expected an opcode?");
4346 "Function should only be used to produce selected instructions!");
4347 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4349 for (
auto &Fn : *RenderFns)
4355MachineInstr *AArch64InstructionSelector::emitAddSub(
4356 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4358 MachineIRBuilder &MIRBuilder)
const {
4360 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4364 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4365 bool Is32Bit =
Size == 32;
4368 if (
auto Fns = selectArithImmed(
RHS))
4369 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4373 if (
auto Fns = selectNegArithImmed(
RHS))
4374 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4378 if (
auto Fns = selectArithExtendedRegister(
RHS))
4379 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4383 if (
auto Fns = selectShiftedRegister(
RHS))
4384 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4386 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4391AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4392 MachineOperand &
RHS,
4393 MachineIRBuilder &MIRBuilder)
const {
4394 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4395 {{AArch64::ADDXri, AArch64::ADDWri},
4396 {AArch64::ADDXrs, AArch64::ADDWrs},
4397 {AArch64::ADDXrr, AArch64::ADDWrr},
4398 {AArch64::SUBXri, AArch64::SUBWri},
4399 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4400 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4404AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4405 MachineOperand &
RHS,
4406 MachineIRBuilder &MIRBuilder)
const {
4407 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4408 {{AArch64::ADDSXri, AArch64::ADDSWri},
4409 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4410 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4411 {AArch64::SUBSXri, AArch64::SUBSWri},
4412 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4413 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4417AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4418 MachineOperand &
RHS,
4419 MachineIRBuilder &MIRBuilder)
const {
4420 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4421 {{AArch64::SUBSXri, AArch64::SUBSWri},
4422 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4423 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4424 {AArch64::ADDSXri, AArch64::ADDSWri},
4425 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4426 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4430AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4431 MachineOperand &
RHS,
4432 MachineIRBuilder &MIRBuilder)
const {
4433 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4434 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4436 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4437 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4441AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4442 MachineOperand &
RHS,
4443 MachineIRBuilder &MIRBuilder)
const {
4444 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4445 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4447 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4448 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4452AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4453 MachineIRBuilder &MIRBuilder)
const {
4456 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4461AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4462 MachineIRBuilder &MIRBuilder)
const {
4465 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4470AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4471 MachineIRBuilder &MIRBuilder)
const {
4472 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4476 bool Is32Bit = (
RegSize == 32);
4477 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4478 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4479 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4483 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4486 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4493 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4494 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4495 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4498MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4499 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4500 MachineIRBuilder &MIRBuilder)
const {
4501 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4508 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4510 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4512 return emitCMP(
LHS,
RHS, MIRBuilder);
4515MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4517 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4521 "Expected a 32-bit scalar register?");
4523 const Register ZReg = AArch64::WZR;
4528 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4534 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4535 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4536 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4541MachineInstr *AArch64InstructionSelector::emitFPCompare(
4543 std::optional<CmpInst::Predicate> Pred)
const {
4544 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4549 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4560 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4564 ShouldUseImm =
true;
4568 unsigned CmpOpcTbl[2][3] = {
4569 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4570 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4572 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4584MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4586 MachineIRBuilder &MIRBuilder)
const {
4593 const LLT Op1Ty = MRI.
getType(Op1);
4594 const LLT Op2Ty = MRI.
getType(Op2);
4596 if (Op1Ty != Op2Ty) {
4597 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4600 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4603 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4614 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4618 MachineInstr *WidenedOp1 =
4619 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4620 MachineInstr *WidenedOp2 =
4621 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4622 if (!WidenedOp1 || !WidenedOp2) {
4623 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4628 unsigned InsertOpc, InsSubRegIdx;
4629 std::tie(InsertOpc, InsSubRegIdx) =
4647 MachineIRBuilder &MIRBuilder)
const {
4648 auto &MRI = *MIRBuilder.
getMRI();
4654 Size =
TRI.getRegSizeInBits(*RC);
4658 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4659 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4660 unsigned Opc = OpcTable[
Size == 64];
4661 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4666MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4668 MachineRegisterInfo *MRI = MIB.
getMRI();
4669 unsigned Opcode =
I.getOpcode();
4673 bool NeedsNegatedCarry =
4674 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4683 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4684 if (SrcMI ==
I.getPrevNode()) {
4686 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4687 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4688 CarrySrcMI->isUnsigned() &&
4689 CarrySrcMI->getCarryOutReg() == CarryReg &&
4690 selectAndRestoreState(*SrcMI))
4697 if (NeedsNegatedCarry) {
4700 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4704 auto Fns = select12BitValueWithLeftShift(1);
4705 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4708bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4709 MachineRegisterInfo &MRI) {
4714 emitCarryIn(
I, CarryInMI->getCarryInReg());
4718 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4719 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4721 Register CarryOutReg = CarryMI.getCarryOutReg();
4730 emitCSINC(CarryOutReg, ZReg, ZReg,
4731 getInvertedCondCode(OpAndCC.second), MIB);
4734 I.eraseFromParent();
4738std::pair<MachineInstr *, AArch64CC::CondCode>
4739AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4740 MachineOperand &
LHS,
4741 MachineOperand &
RHS,
4742 MachineIRBuilder &MIRBuilder)
const {
4746 case TargetOpcode::G_SADDO:
4748 case TargetOpcode::G_UADDO:
4750 case TargetOpcode::G_SSUBO:
4752 case TargetOpcode::G_USUBO:
4754 case TargetOpcode::G_SADDE:
4756 case TargetOpcode::G_UADDE:
4758 case TargetOpcode::G_SSUBE:
4760 case TargetOpcode::G_USUBE:
4781 unsigned Depth = 0) {
4788 MustBeFirst =
false;
4794 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4795 bool IsOR = Opcode == TargetOpcode::G_OR;
4807 if (MustBeFirstL && MustBeFirstR)
4813 if (!CanNegateL && !CanNegateR)
4817 CanNegate = WillNegate && CanNegateL && CanNegateR;
4820 MustBeFirst = !CanNegate;
4822 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4825 MustBeFirst = MustBeFirstL || MustBeFirstR;
4832MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4835 MachineIRBuilder &MIB)
const {
4836 auto &MRI = *MIB.
getMRI();
4839 std::optional<ValueAndVReg>
C;
4843 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4844 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4845 else if (
C->Value.ule(31))
4846 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4848 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4854 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4855 CCmpOpc = AArch64::FCCMPHrr;
4858 CCmpOpc = AArch64::FCCMPSrr;
4861 CCmpOpc = AArch64::FCCMPDrr;
4871 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4872 CCmp.
addImm(
C->Value.getZExtValue());
4873 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4874 CCmp.
addImm(
C->Value.abs().getZExtValue());
4882MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4886 auto &MRI = *MIB.
getMRI();
4904 MachineInstr *ExtraCmp;
4906 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4918 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4919 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4920 Cmp->getOperand(3).getReg(), MIB);
4927 bool IsOR = Opcode == TargetOpcode::G_OR;
4933 assert(ValidL &&
"Valid conjunction/disjunction tree");
4940 assert(ValidR &&
"Valid conjunction/disjunction tree");
4945 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4954 bool NegateAfterAll;
4955 if (Opcode == TargetOpcode::G_OR) {
4958 assert(CanNegateR &&
"at least one side must be negatable");
4959 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4963 NegateAfterR =
true;
4966 NegateR = CanNegateR;
4967 NegateAfterR = !CanNegateR;
4970 NegateAfterAll = !Negate;
4972 assert(Opcode == TargetOpcode::G_AND &&
4973 "Valid conjunction/disjunction tree");
4974 assert(!Negate &&
"Valid conjunction/disjunction tree");
4978 NegateAfterR =
false;
4979 NegateAfterAll =
false;
4984 MachineInstr *CmpR =
4995MachineInstr *AArch64InstructionSelector::emitConjunction(
4997 bool DummyCanNegate;
4998 bool DummyMustBeFirst;
5005bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5006 MachineInstr &CondMI) {
5017bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5018 MachineRegisterInfo &MRI = *MIB.
getMRI();
5037 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5046 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5052 unsigned CondOpc = CondDef->
getOpcode();
5053 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5054 if (tryOptSelectConjunction(
I, *CondDef))
5060 if (CondOpc == TargetOpcode::G_ICMP) {
5089 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5090 I.getOperand(3).getReg(), CondCode, MIB);
5091 I.eraseFromParent();
5095MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5096 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5097 MachineIRBuilder &MIRBuilder)
const {
5099 "Unexpected MachineOperand");
5100 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5123 if (
isCMN(RHSDef,
P, MRI))
5138 if (
isCMN(LHSDef,
P, MRI)) {
5155 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5158 if (!ValAndVReg || ValAndVReg->Value != 0)
5168bool AArch64InstructionSelector::selectShuffleVector(
5169 MachineInstr &
I, MachineRegisterInfo &MRI) {
5170 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5171 Register Src1Reg =
I.getOperand(1).getReg();
5172 Register Src2Reg =
I.getOperand(2).getReg();
5173 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5175 "Expected equal shuffle types during selection");
5184 SmallVector<int> NewMask;
5185 bool FirstUsed =
false;
5186 bool SecondUsed =
false;
5187 for (
int M : Mask) {
5189 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5192 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5197 FirstUsed |=
M < NumElts;
5198 SecondUsed |=
M >= NumElts;
5199 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5208 for (
int &M : NewMask) {
5210 assert(M >= ByteLanes && M < 2 * ByteLanes);
5220 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5221 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5234 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5241 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5245 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5250 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5251 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5253 I.eraseFromParent();
5258 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5261 I.eraseFromParent();
5269 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5272 I.eraseFromParent();
5276MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5278 unsigned LaneIdx,
const RegisterBank &RB,
5279 MachineIRBuilder &MIRBuilder)
const {
5280 MachineInstr *InsElt =
nullptr;
5282 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5291 if (RB.
getID() == AArch64::FPRRegBankID) {
5292 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5295 .
addUse(InsSub->getOperand(0).getReg())
5307bool AArch64InstructionSelector::selectUSMovFromExtend(
5308 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5309 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5310 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5311 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5313 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5314 const Register DefReg =
MI.getOperand(0).getReg();
5315 const LLT DstTy = MRI.
getType(DefReg);
5318 if (DstSize != 32 && DstSize != 64)
5321 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5322 MI.getOperand(1).getReg(), MRI);
5328 const LLT VecTy = MRI.
getType(Src0);
5333 const MachineInstr *ScalarToVector = emitScalarToVector(
5334 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5335 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5341 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5343 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5345 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5347 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5349 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5357 MachineInstr *ExtI =
nullptr;
5358 if (DstSize == 64 && !IsSigned) {
5360 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5361 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5363 .
addImm(AArch64::sub_32);
5366 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5369 MI.eraseFromParent();
5373MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5374 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5376 if (DstSize == 128) {
5377 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5379 Op = AArch64::MOVIv16b_ns;
5381 Op = AArch64::MOVIv8b_ns;
5384 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5388 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5395MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5396 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5400 if (DstSize == 128) {
5401 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5403 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5405 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5408 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5425MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5426 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5430 if (DstSize == 128) {
5431 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5433 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5435 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5438 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5461MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5462 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5465 if (DstSize == 128) {
5466 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5468 Op = AArch64::MOVIv2d_ns;
5470 Op = AArch64::MOVID;
5473 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5476 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5483MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5484 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5488 if (DstSize == 128) {
5489 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5491 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5493 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5496 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5513MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5514 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5517 bool IsWide =
false;
5518 if (DstSize == 128) {
5519 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5521 Op = AArch64::FMOVv4f32_ns;
5524 Op = AArch64::FMOVv2f32_ns;
5527 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5533 Op = AArch64::FMOVv2f64_ns;
5537 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5542bool AArch64InstructionSelector::selectIndexedExtLoad(
5543 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5546 Register WriteBack = ExtLd.getWritebackReg();
5551 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5552 bool IsPre = ExtLd.isPre();
5554 unsigned InsertIntoSubReg = 0;
5560 if ((IsSExt && IsFPR) || Ty.
isVector())
5568 if (MemSizeBits == 8) {
5571 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5573 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5574 NewLdDstTy = IsDst64 ? s64 : s32;
5576 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5577 InsertIntoSubReg = AArch64::bsub;
5580 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5581 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5584 }
else if (MemSizeBits == 16) {
5587 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5589 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5590 NewLdDstTy = IsDst64 ? s64 : s32;
5592 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5593 InsertIntoSubReg = AArch64::hsub;
5596 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5597 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5600 }
else if (MemSizeBits == 32) {
5602 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5605 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5606 InsertIntoSubReg = AArch64::ssub;
5609 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5610 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5622 .addImm(Cst->getSExtValue());
5627 if (InsertIntoSubReg) {
5629 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5630 .addUse(LdMI.getReg(1))
5631 .
addImm(InsertIntoSubReg);
5634 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5641 MI.eraseFromParent();
5646bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5647 MachineRegisterInfo &MRI) {
5650 Register WriteBack = Ld.getWritebackReg();
5654 "Unexpected type for indexed load");
5655 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5658 return selectIndexedExtLoad(
MI, MRI);
5662 static constexpr unsigned GPROpcodes[] = {
5663 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5665 static constexpr unsigned FPROpcodes[] = {
5666 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5669 ? FPROpcodes[
Log2_32(MemSize)]
5670 : GPROpcodes[
Log2_32(MemSize)];
5673 static constexpr unsigned GPROpcodes[] = {
5674 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5676 static constexpr unsigned FPROpcodes[] = {
5677 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5678 AArch64::LDRDpost, AArch64::LDRQpost};
5680 ? FPROpcodes[
Log2_32(MemSize)]
5681 : GPROpcodes[
Log2_32(MemSize)];
5691 MI.eraseFromParent();
5695bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5696 MachineRegisterInfo &MRI) {
5702 "Unexpected type for indexed store");
5704 LocationSize MemSize =
I.getMMO().getSize();
5705 unsigned MemSizeInBytes = MemSize.
getValue();
5707 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5708 "Unexpected indexed store size");
5709 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5713 static constexpr unsigned GPROpcodes[] = {
5714 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5716 static constexpr unsigned FPROpcodes[] = {
5717 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5721 Opc = FPROpcodes[MemSizeLog2];
5723 Opc = GPROpcodes[MemSizeLog2];
5725 static constexpr unsigned GPROpcodes[] = {
5726 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5728 static constexpr unsigned FPROpcodes[] = {
5729 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5730 AArch64::STRDpost, AArch64::STRQpost};
5733 Opc = FPROpcodes[MemSizeLog2];
5735 Opc = GPROpcodes[MemSizeLog2];
5743 Str.cloneMemRefs(
I);
5745 I.eraseFromParent();
5750AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5751 MachineIRBuilder &MIRBuilder,
5752 MachineRegisterInfo &MRI) {
5755 assert((DstSize == 64 || DstSize == 128) &&
5756 "Unexpected vector constant size");
5759 if (DstSize == 128) {
5761 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5766 if (DstSize == 64) {
5769 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5772 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5779 APInt SplatValueAsInt =
5782 : SplatValue->getUniqueInteger();
5785 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5786 MachineInstr *NewOp;
5810 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5814 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5815 unsigned NegOpc) -> MachineInstr * {
5818 APInt NegBits(DstSize, 0);
5819 unsigned NumElts = DstSize / NumBits;
5820 for (
unsigned i = 0; i < NumElts; i++)
5821 NegBits |= Neg << (NumBits * i);
5822 NegBits = DefBits ^ NegBits;
5826 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5828 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5830 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5835 if ((R = TryWithFNeg(DefBits, 32,
5836 DstSize == 64 ? AArch64::FNEGv2f32
5837 : AArch64::FNEGv4f32)) ||
5838 (R = TryWithFNeg(DefBits, 64,
5839 DstSize == 64 ? AArch64::FNEGDr
5840 : AArch64::FNEGv2f64)) ||
5841 (STI.hasFullFP16() &&
5842 (R = TryWithFNeg(DefBits, 16,
5843 DstSize == 64 ? AArch64::FNEGv4f16
5844 : AArch64::FNEGv8f16))))
5850 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5854 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5856 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5860bool AArch64InstructionSelector::tryOptConstantBuildVec(
5861 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5862 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5864 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5870 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5871 Register OpReg =
I.getOperand(Idx).getReg();
5880 std::move(AnyConst->Value)));
5893 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5895 I.eraseFromParent();
5899bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5900 MachineInstr &
I, MachineRegisterInfo &MRI) {
5905 Register Dst =
I.getOperand(0).getReg();
5906 Register EltReg =
I.getOperand(1).getReg();
5907 LLT EltTy = MRI.
getType(EltReg);
5910 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5915 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5923 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5928 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5931 I.eraseFromParent();
5936bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5937 MachineRegisterInfo &MRI) {
5938 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5941 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5942 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5945 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5947 if (tryOptBuildVecToSubregToReg(
I, MRI))
5950 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5952 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5955 MachineInstr *ScalarToVec =
5957 I.getOperand(1).getReg(), MIB);
5966 MachineInstr *PrevMI = ScalarToVec;
5967 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5970 Register OpReg =
I.getOperand(i).getReg();
5973 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5980 if (DstSize < 128) {
5983 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5986 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5991 unsigned SubReg = 0;
5994 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5995 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
6001 Register DstReg =
I.getOperand(0).getReg();
6003 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
6004 MachineOperand &RegOp =
I.getOperand(1);
6024 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6026 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6035bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6038 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6040 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6041 auto &MRI = *MIB.
getMRI();
6042 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6045 "Destination must be 64 bits or 128 bits?");
6046 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6047 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6052 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6053 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6054 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6055 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6064bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6065 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6066 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6068 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6069 auto &MRI = *MIB.
getMRI();
6070 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6073 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6075 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6076 [](
auto MO) { return MO.getReg(); });
6080 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6095 .
addImm(LaneNo->getZExtValue())
6099 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6100 unsigned SubReg = AArch64::qsub0;
6101 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6102 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6103 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6104 : DstOp(
I.getOperand(Idx).
getReg())},
6106 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6111 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6117void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6120 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6121 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6122 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6125 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6126 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6135bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6136 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6137 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6138 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6142 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6143 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6147 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6157 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6160 .
addImm(LaneNo->getZExtValue())
6167bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6168 MachineInstr &
I, MachineRegisterInfo &MRI) {
6181 case Intrinsic::aarch64_ldxp:
6182 case Intrinsic::aarch64_ldaxp: {
6184 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6185 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6191 case Intrinsic::aarch64_neon_ld1x2: {
6192 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6195 Opc = AArch64::LD1Twov8b;
6197 Opc = AArch64::LD1Twov16b;
6199 Opc = AArch64::LD1Twov4h;
6201 Opc = AArch64::LD1Twov8h;
6203 Opc = AArch64::LD1Twov2s;
6205 Opc = AArch64::LD1Twov4s;
6207 Opc = AArch64::LD1Twov2d;
6208 else if (Ty ==
S64 || Ty == P0)
6209 Opc = AArch64::LD1Twov1d;
6212 selectVectorLoadIntrinsic(
Opc, 2,
I);
6215 case Intrinsic::aarch64_neon_ld1x3: {
6216 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6219 Opc = AArch64::LD1Threev8b;
6221 Opc = AArch64::LD1Threev16b;
6223 Opc = AArch64::LD1Threev4h;
6225 Opc = AArch64::LD1Threev8h;
6227 Opc = AArch64::LD1Threev2s;
6229 Opc = AArch64::LD1Threev4s;
6231 Opc = AArch64::LD1Threev2d;
6232 else if (Ty ==
S64 || Ty == P0)
6233 Opc = AArch64::LD1Threev1d;
6236 selectVectorLoadIntrinsic(
Opc, 3,
I);
6239 case Intrinsic::aarch64_neon_ld1x4: {
6240 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6243 Opc = AArch64::LD1Fourv8b;
6245 Opc = AArch64::LD1Fourv16b;
6247 Opc = AArch64::LD1Fourv4h;
6249 Opc = AArch64::LD1Fourv8h;
6251 Opc = AArch64::LD1Fourv2s;
6253 Opc = AArch64::LD1Fourv4s;
6255 Opc = AArch64::LD1Fourv2d;
6256 else if (Ty ==
S64 || Ty == P0)
6257 Opc = AArch64::LD1Fourv1d;
6260 selectVectorLoadIntrinsic(
Opc, 4,
I);
6263 case Intrinsic::aarch64_neon_ld2: {
6264 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6267 Opc = AArch64::LD2Twov8b;
6269 Opc = AArch64::LD2Twov16b;
6271 Opc = AArch64::LD2Twov4h;
6273 Opc = AArch64::LD2Twov8h;
6275 Opc = AArch64::LD2Twov2s;
6277 Opc = AArch64::LD2Twov4s;
6279 Opc = AArch64::LD2Twov2d;
6280 else if (Ty ==
S64 || Ty == P0)
6281 Opc = AArch64::LD1Twov1d;
6284 selectVectorLoadIntrinsic(
Opc, 2,
I);
6287 case Intrinsic::aarch64_neon_ld2lane: {
6288 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6291 Opc = AArch64::LD2i8;
6293 Opc = AArch64::LD2i16;
6295 Opc = AArch64::LD2i32;
6298 Opc = AArch64::LD2i64;
6301 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6305 case Intrinsic::aarch64_neon_ld2r: {
6306 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6309 Opc = AArch64::LD2Rv8b;
6311 Opc = AArch64::LD2Rv16b;
6313 Opc = AArch64::LD2Rv4h;
6315 Opc = AArch64::LD2Rv8h;
6317 Opc = AArch64::LD2Rv2s;
6319 Opc = AArch64::LD2Rv4s;
6321 Opc = AArch64::LD2Rv2d;
6322 else if (Ty ==
S64 || Ty == P0)
6323 Opc = AArch64::LD2Rv1d;
6326 selectVectorLoadIntrinsic(
Opc, 2,
I);
6329 case Intrinsic::aarch64_neon_ld3: {
6330 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6333 Opc = AArch64::LD3Threev8b;
6335 Opc = AArch64::LD3Threev16b;
6337 Opc = AArch64::LD3Threev4h;
6339 Opc = AArch64::LD3Threev8h;
6341 Opc = AArch64::LD3Threev2s;
6343 Opc = AArch64::LD3Threev4s;
6345 Opc = AArch64::LD3Threev2d;
6346 else if (Ty ==
S64 || Ty == P0)
6347 Opc = AArch64::LD1Threev1d;
6350 selectVectorLoadIntrinsic(
Opc, 3,
I);
6353 case Intrinsic::aarch64_neon_ld3lane: {
6354 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6357 Opc = AArch64::LD3i8;
6359 Opc = AArch64::LD3i16;
6361 Opc = AArch64::LD3i32;
6364 Opc = AArch64::LD3i64;
6367 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6371 case Intrinsic::aarch64_neon_ld3r: {
6372 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6375 Opc = AArch64::LD3Rv8b;
6377 Opc = AArch64::LD3Rv16b;
6379 Opc = AArch64::LD3Rv4h;
6381 Opc = AArch64::LD3Rv8h;
6383 Opc = AArch64::LD3Rv2s;
6385 Opc = AArch64::LD3Rv4s;
6387 Opc = AArch64::LD3Rv2d;
6388 else if (Ty ==
S64 || Ty == P0)
6389 Opc = AArch64::LD3Rv1d;
6392 selectVectorLoadIntrinsic(
Opc, 3,
I);
6395 case Intrinsic::aarch64_neon_ld4: {
6396 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6399 Opc = AArch64::LD4Fourv8b;
6401 Opc = AArch64::LD4Fourv16b;
6403 Opc = AArch64::LD4Fourv4h;
6405 Opc = AArch64::LD4Fourv8h;
6407 Opc = AArch64::LD4Fourv2s;
6409 Opc = AArch64::LD4Fourv4s;
6411 Opc = AArch64::LD4Fourv2d;
6412 else if (Ty ==
S64 || Ty == P0)
6413 Opc = AArch64::LD1Fourv1d;
6416 selectVectorLoadIntrinsic(
Opc, 4,
I);
6419 case Intrinsic::aarch64_neon_ld4lane: {
6420 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6423 Opc = AArch64::LD4i8;
6425 Opc = AArch64::LD4i16;
6427 Opc = AArch64::LD4i32;
6430 Opc = AArch64::LD4i64;
6433 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6437 case Intrinsic::aarch64_neon_ld4r: {
6438 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6441 Opc = AArch64::LD4Rv8b;
6443 Opc = AArch64::LD4Rv16b;
6445 Opc = AArch64::LD4Rv4h;
6447 Opc = AArch64::LD4Rv8h;
6449 Opc = AArch64::LD4Rv2s;
6451 Opc = AArch64::LD4Rv4s;
6453 Opc = AArch64::LD4Rv2d;
6454 else if (Ty ==
S64 || Ty == P0)
6455 Opc = AArch64::LD4Rv1d;
6458 selectVectorLoadIntrinsic(
Opc, 4,
I);
6461 case Intrinsic::aarch64_neon_st1x2: {
6462 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6465 Opc = AArch64::ST1Twov8b;
6467 Opc = AArch64::ST1Twov16b;
6469 Opc = AArch64::ST1Twov4h;
6471 Opc = AArch64::ST1Twov8h;
6473 Opc = AArch64::ST1Twov2s;
6475 Opc = AArch64::ST1Twov4s;
6477 Opc = AArch64::ST1Twov2d;
6478 else if (Ty ==
S64 || Ty == P0)
6479 Opc = AArch64::ST1Twov1d;
6482 selectVectorStoreIntrinsic(
I, 2,
Opc);
6485 case Intrinsic::aarch64_neon_st1x3: {
6486 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6489 Opc = AArch64::ST1Threev8b;
6491 Opc = AArch64::ST1Threev16b;
6493 Opc = AArch64::ST1Threev4h;
6495 Opc = AArch64::ST1Threev8h;
6497 Opc = AArch64::ST1Threev2s;
6499 Opc = AArch64::ST1Threev4s;
6501 Opc = AArch64::ST1Threev2d;
6502 else if (Ty ==
S64 || Ty == P0)
6503 Opc = AArch64::ST1Threev1d;
6506 selectVectorStoreIntrinsic(
I, 3,
Opc);
6509 case Intrinsic::aarch64_neon_st1x4: {
6510 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6513 Opc = AArch64::ST1Fourv8b;
6515 Opc = AArch64::ST1Fourv16b;
6517 Opc = AArch64::ST1Fourv4h;
6519 Opc = AArch64::ST1Fourv8h;
6521 Opc = AArch64::ST1Fourv2s;
6523 Opc = AArch64::ST1Fourv4s;
6525 Opc = AArch64::ST1Fourv2d;
6526 else if (Ty ==
S64 || Ty == P0)
6527 Opc = AArch64::ST1Fourv1d;
6530 selectVectorStoreIntrinsic(
I, 4,
Opc);
6533 case Intrinsic::aarch64_neon_st2: {
6534 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6537 Opc = AArch64::ST2Twov8b;
6539 Opc = AArch64::ST2Twov16b;
6541 Opc = AArch64::ST2Twov4h;
6543 Opc = AArch64::ST2Twov8h;
6545 Opc = AArch64::ST2Twov2s;
6547 Opc = AArch64::ST2Twov4s;
6549 Opc = AArch64::ST2Twov2d;
6550 else if (Ty ==
S64 || Ty == P0)
6551 Opc = AArch64::ST1Twov1d;
6554 selectVectorStoreIntrinsic(
I, 2,
Opc);
6557 case Intrinsic::aarch64_neon_st3: {
6558 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6561 Opc = AArch64::ST3Threev8b;
6563 Opc = AArch64::ST3Threev16b;
6565 Opc = AArch64::ST3Threev4h;
6567 Opc = AArch64::ST3Threev8h;
6569 Opc = AArch64::ST3Threev2s;
6571 Opc = AArch64::ST3Threev4s;
6573 Opc = AArch64::ST3Threev2d;
6574 else if (Ty ==
S64 || Ty == P0)
6575 Opc = AArch64::ST1Threev1d;
6578 selectVectorStoreIntrinsic(
I, 3,
Opc);
6581 case Intrinsic::aarch64_neon_st4: {
6582 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6585 Opc = AArch64::ST4Fourv8b;
6587 Opc = AArch64::ST4Fourv16b;
6589 Opc = AArch64::ST4Fourv4h;
6591 Opc = AArch64::ST4Fourv8h;
6593 Opc = AArch64::ST4Fourv2s;
6595 Opc = AArch64::ST4Fourv4s;
6597 Opc = AArch64::ST4Fourv2d;
6598 else if (Ty ==
S64 || Ty == P0)
6599 Opc = AArch64::ST1Fourv1d;
6602 selectVectorStoreIntrinsic(
I, 4,
Opc);
6605 case Intrinsic::aarch64_neon_st2lane: {
6606 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6609 Opc = AArch64::ST2i8;
6611 Opc = AArch64::ST2i16;
6613 Opc = AArch64::ST2i32;
6616 Opc = AArch64::ST2i64;
6619 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6623 case Intrinsic::aarch64_neon_st3lane: {
6624 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6627 Opc = AArch64::ST3i8;
6629 Opc = AArch64::ST3i16;
6631 Opc = AArch64::ST3i32;
6634 Opc = AArch64::ST3i64;
6637 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6641 case Intrinsic::aarch64_neon_st4lane: {
6642 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6645 Opc = AArch64::ST4i8;
6647 Opc = AArch64::ST4i16;
6649 Opc = AArch64::ST4i32;
6652 Opc = AArch64::ST4i64;
6655 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6659 case Intrinsic::aarch64_mops_memset_tag: {
6672 Register DstDef =
I.getOperand(0).getReg();
6674 Register DstUse =
I.getOperand(2).getReg();
6675 Register ValUse =
I.getOperand(3).getReg();
6676 Register SizeUse =
I.getOperand(4).getReg();
6683 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6684 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6689 case Intrinsic::ptrauth_resign_load_relative: {
6690 Register DstReg =
I.getOperand(0).getReg();
6691 Register ValReg =
I.getOperand(2).getReg();
6692 uint64_t AUTKey =
I.getOperand(3).getImm();
6693 Register AUTDisc =
I.getOperand(4).getReg();
6694 uint64_t PACKey =
I.getOperand(5).getImm();
6695 Register PACDisc =
I.getOperand(6).getReg();
6696 int64_t Addend =
I.getOperand(7).getImm();
6699 uint16_t AUTConstDiscC = 0;
6700 std::tie(AUTConstDiscC, AUTAddrDisc) =
6704 uint16_t PACConstDiscC = 0;
6705 std::tie(PACConstDiscC, PACAddrDisc) =
6708 MIB.
buildCopy({AArch64::X16}, {ValReg});
6722 I.eraseFromParent();
6727 I.eraseFromParent();
6731bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6732 MachineRegisterInfo &MRI) {
6738 case Intrinsic::ptrauth_resign: {
6739 Register DstReg =
I.getOperand(0).getReg();
6740 Register ValReg =
I.getOperand(2).getReg();
6741 uint64_t AUTKey =
I.getOperand(3).getImm();
6742 Register AUTDisc =
I.getOperand(4).getReg();
6743 uint64_t PACKey =
I.getOperand(5).getImm();
6744 Register PACDisc =
I.getOperand(6).getReg();
6747 uint16_t AUTConstDiscC = 0;
6748 std::tie(AUTConstDiscC, AUTAddrDisc) =
6752 uint16_t PACConstDiscC = 0;
6753 std::tie(PACConstDiscC, PACAddrDisc) =
6756 MIB.
buildCopy({AArch64::X16}, {ValReg});
6757 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6769 I.eraseFromParent();
6772 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6773 Register DstReg =
I.getOperand(0).getReg();
6774 Register ValReg =
I.getOperand(2).getReg();
6775 uint64_t AUTKey =
I.getOperand(3).getImm();
6776 Register AUTDisc =
I.getOperand(4).getReg();
6777 Register AUTPC =
I.getOperand(5).getReg();
6778 uint64_t PACKey =
I.getOperand(6).getImm();
6779 Register PACDisc =
I.getOperand(7).getReg();
6782 "auth_with_pc_and_resign only supports IA and IB keys");
6784 uint16_t PACConstDiscC = 0;
6786 std::tie(PACConstDiscC, PACAddrDisc) =
6789 if (PACAddrDisc == AArch64::NoRegister)
6790 PACAddrDisc = AArch64::XZR;
6792 MIB.
buildCopy({AArch64::X17}, {ValReg});
6793 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6805 I.eraseFromParent();
6808 case Intrinsic::ptrauth_auth: {
6809 Register DstReg =
I.getOperand(0).getReg();
6810 Register ValReg =
I.getOperand(2).getReg();
6811 uint64_t AUTKey =
I.getOperand(3).getImm();
6812 Register AUTDisc =
I.getOperand(4).getReg();
6815 uint16_t AUTConstDiscC = 0;
6816 std::tie(AUTConstDiscC, AUTAddrDisc) =
6820 MIB.
buildCopy({AArch64::X16}, {ValReg});
6821 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6842 I.eraseFromParent();
6845 case Intrinsic::frameaddress:
6846 case Intrinsic::returnaddress: {
6847 MachineFunction &MF = *
I.getParent()->getParent();
6850 unsigned Depth =
I.getOperand(2).getImm();
6851 Register DstReg =
I.getOperand(0).getReg();
6854 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6855 if (!MFReturnAddr) {
6860 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6863 if (STI.hasPAuth()) {
6864 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6871 I.eraseFromParent();
6880 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6882 FrameAddr = NextFrame;
6885 if (IntrinID == Intrinsic::frameaddress)
6890 if (STI.hasPAuth()) {
6892 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6893 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6902 I.eraseFromParent();
6905 case Intrinsic::aarch64_neon_tbl2:
6906 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6908 case Intrinsic::aarch64_neon_tbl3:
6909 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6912 case Intrinsic::aarch64_neon_tbl4:
6913 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6915 case Intrinsic::aarch64_neon_tbx2:
6916 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6918 case Intrinsic::aarch64_neon_tbx3:
6919 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6921 case Intrinsic::aarch64_neon_tbx4:
6922 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6924 case Intrinsic::swift_async_context_addr:
6925 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6932 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6933 I.eraseFromParent();
6968bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6969 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6970 Register DefReg =
I.getOperand(0).getReg();
6971 Register Addr =
I.getOperand(1).getReg();
6972 uint64_t
Key =
I.getOperand(2).getImm();
6973 Register AddrDisc =
I.getOperand(3).getReg();
6974 uint64_t Disc =
I.getOperand(4).getImm();
6984 "constant discriminator in ptrauth global out of range [0, 0xffff]");
7000 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
7012 const GlobalValue *GV;
7023 MachineIRBuilder MIB(
I);
7029 "unsupported non-GOT op flags on ptrauth global reference");
7031 "unsupported non-GOT reference to weak ptrauth global");
7034 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7041 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7042 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7043 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7046 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7051 I.eraseFromParent();
7063 "unsupported non-zero offset in weak ptrauth global reference");
7068 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7069 .addGlobalAddress(GV,
Offset)
7074 I.eraseFromParent();
7078void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7079 MachineRegisterInfo &MRI,
7080 unsigned NumVec,
unsigned Opc1,
7081 unsigned Opc2,
bool isExt) {
7082 Register DstReg =
I.getOperand(0).getReg();
7087 for (
unsigned i = 0; i < NumVec; i++)
7088 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7091 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7092 MachineInstrBuilder
Instr;
7099 I.eraseFromParent();
7102InstructionSelector::ComplexRendererFns
7103AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7105 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7106 return std::nullopt;
7107 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7108 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7111InstructionSelector::ComplexRendererFns
7112AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7114 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7115 return std::nullopt;
7116 uint64_t Enc = 31 - *MaybeImmed;
7117 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7120InstructionSelector::ComplexRendererFns
7121AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7123 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7124 return std::nullopt;
7125 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7126 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7129InstructionSelector::ComplexRendererFns
7130AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7132 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7133 return std::nullopt;
7134 uint64_t Enc = 63 - *MaybeImmed;
7135 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7143InstructionSelector::ComplexRendererFns
7144AArch64InstructionSelector::select12BitValueWithLeftShift(
7145 uint64_t Immed)
const {
7147 if (Immed >> 12 == 0) {
7149 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7151 Immed = Immed >> 12;
7153 return std::nullopt;
7157 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7158 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7165InstructionSelector::ComplexRendererFns
7166AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7173 if (MaybeImmed == std::nullopt)
7174 return std::nullopt;
7175 return select12BitValueWithLeftShift(*MaybeImmed);
7180InstructionSelector::ComplexRendererFns
7181AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7185 return std::nullopt;
7187 if (MaybeImmed == std::nullopt)
7188 return std::nullopt;
7189 uint64_t Immed = *MaybeImmed;
7195 return std::nullopt;
7201 Immed = ~((uint32_t)Immed) + 1;
7203 Immed = ~Immed + 1ULL;
7205 if (Immed & 0xFFFFFFFFFF000000ULL)
7206 return std::nullopt;
7208 Immed &= 0xFFFFFFULL;
7209 return select12BitValueWithLeftShift(Immed);
7226std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7227 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7228 if (
MI.getOpcode() == AArch64::G_SHL) {
7232 MI.getOperand(2).getReg(), MRI)) {
7233 const APInt ShiftVal = ValAndVeg->Value;
7236 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7239 return std::nullopt;
7247bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7248 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7249 bool IsAddrOperand)
const {
7254 MI.getParent()->getParent()->getFunction().hasOptSize())
7257 if (IsAddrOperand) {
7259 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7263 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7264 MachineInstr *OffsetInst =
7270 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7281 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7284InstructionSelector::ComplexRendererFns
7285AArch64InstructionSelector::selectExtendedSHL(
7286 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7287 unsigned SizeInBytes,
bool WantsExt)
const {
7288 assert(
Base.isReg() &&
"Expected base to be a register operand");
7289 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7294 unsigned OffsetOpc = OffsetInst->
getOpcode();
7295 bool LookedThroughZExt =
false;
7296 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7298 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7299 return std::nullopt;
7303 LookedThroughZExt =
true;
7305 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7306 return std::nullopt;
7309 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7310 if (LegalShiftVal == 0)
7311 return std::nullopt;
7312 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7313 return std::nullopt;
7324 if (OffsetOpc == TargetOpcode::G_SHL)
7325 return std::nullopt;
7331 return std::nullopt;
7336 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7340 if (OffsetOpc == TargetOpcode::G_MUL) {
7342 return std::nullopt;
7348 if ((ImmVal & 0x7) != ImmVal)
7349 return std::nullopt;
7353 if (ImmVal != LegalShiftVal)
7354 return std::nullopt;
7356 unsigned SignExtend = 0;
7360 if (!LookedThroughZExt) {
7362 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7364 return std::nullopt;
7369 return std::nullopt;
7375 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7380 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7381 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7382 [=](MachineInstrBuilder &MIB) {
7385 MIB.addImm(SignExtend);
7398InstructionSelector::ComplexRendererFns
7399AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7400 MachineOperand &Root,
unsigned SizeInBytes)
const {
7402 return std::nullopt;
7417 MachineInstr *PtrAdd =
7419 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7420 return std::nullopt;
7424 MachineInstr *OffsetInst =
7426 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7439InstructionSelector::ComplexRendererFns
7440AArch64InstructionSelector::selectAddrModeRegisterOffset(
7441 MachineOperand &Root)
const {
7446 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7447 return std::nullopt;
7453 return std::nullopt;
7456 return {{[=](MachineInstrBuilder &MIB) {
7459 [=](MachineInstrBuilder &MIB) {
7462 [=](MachineInstrBuilder &MIB) {
7472InstructionSelector::ComplexRendererFns
7473AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7474 unsigned SizeInBytes)
const {
7477 return std::nullopt;
7478 MachineInstr *PtrAdd =
7481 return std::nullopt;
7499 unsigned Scale =
Log2_32(SizeInBytes);
7500 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7504 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7505 ImmOff < (0x1000 << Scale))
7506 return std::nullopt;
7511 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7515 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7521 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7522 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7527 return std::nullopt;
7531 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7537 return selectAddrModeRegisterOffset(Root);
7546InstructionSelector::ComplexRendererFns
7547AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7548 unsigned SizeInBytes)
const {
7551 MachineInstr *PtrAdd =
7553 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7554 return std::nullopt;
7575 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7584 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7585 return std::nullopt;
7589 getExtendTypeForInst(*OffsetInst, MRI,
true);
7591 return std::nullopt;
7594 MachineIRBuilder MIB(*PtrAdd);
7596 AArch64::GPR32RegClass, MIB);
7600 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7601 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7602 [=](MachineInstrBuilder &MIB) {
7603 MIB.addImm(SignExtend);
7613InstructionSelector::ComplexRendererFns
7614AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7615 unsigned Size)
const {
7616 MachineRegisterInfo &MRI =
7620 return std::nullopt;
7622 if (!isBaseWithConstantOffset(Root, MRI))
7623 return std::nullopt;
7627 MachineOperand &OffImm = RootDef->
getOperand(2);
7628 if (!OffImm.
isReg())
7629 return std::nullopt;
7631 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7632 return std::nullopt;
7634 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7636 return std::nullopt;
7639 if (RHSC >= -256 && RHSC < 256) {
7642 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7643 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7646 return std::nullopt;
7649InstructionSelector::ComplexRendererFns
7650AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7652 MachineRegisterInfo &MRI)
const {
7653 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7654 return std::nullopt;
7657 return std::nullopt;
7662 return std::nullopt;
7666 return std::nullopt;
7670 return std::nullopt;
7673 MachineIRBuilder MIRBuilder(RootDef);
7675 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7676 [=](MachineInstrBuilder &MIB) {
7677 MIB.addGlobalAddress(GV,
Offset,
7686InstructionSelector::ComplexRendererFns
7687AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7688 unsigned Size)
const {
7693 return std::nullopt;
7696 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7698 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7699 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7707 MachineInstr *RootParent = Root.
getParent();
7709 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7711 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7716 if (isBaseWithConstantOffset(Root, MRI)) {
7724 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7725 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7727 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7728 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7732 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7733 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7740 if (selectAddrModeUnscaled(Root,
Size))
7741 return std::nullopt;
7744 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7745 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7752 switch (
MI.getOpcode()) {
7755 case TargetOpcode::G_SHL:
7757 case TargetOpcode::G_LSHR:
7759 case TargetOpcode::G_ASHR:
7761 case TargetOpcode::G_ROTR:
7768InstructionSelector::ComplexRendererFns
7769AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7770 bool AllowROR)
const {
7772 return std::nullopt;
7773 MachineRegisterInfo &MRI =
7781 return std::nullopt;
7783 return std::nullopt;
7784 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7785 return std::nullopt;
7788 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7791 return std::nullopt;
7795 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7799 unsigned Val = *Immed & (NumBits - 1);
7802 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7803 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7807 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7808 unsigned Opc =
MI.getOpcode();
7811 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7813 if (
Opc == TargetOpcode::G_SEXT)
7816 Size =
MI.getOperand(2).getImm();
7817 assert(
Size != 64 &&
"Extend from 64 bits?");
7830 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7832 assert(
Size != 64 &&
"Extend from 64 bits?");
7847 if (
Opc != TargetOpcode::G_AND)
7853 uint64_t AndMask = *MaybeAndMask;
7866Register AArch64InstructionSelector::moveScalarRegClass(
7868 MachineRegisterInfo &MRI = *MIB.
getMRI();
7878 return Copy.getReg(0);
7883InstructionSelector::ComplexRendererFns
7884AArch64InstructionSelector::selectArithExtendedRegister(
7885 MachineOperand &Root)
const {
7887 return std::nullopt;
7888 MachineRegisterInfo &MRI =
7891 uint64_t ShiftVal = 0;
7896 return std::nullopt;
7898 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7899 return std::nullopt;
7902 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7907 return std::nullopt;
7908 ShiftVal = *MaybeShiftVal;
7910 return std::nullopt;
7915 return std::nullopt;
7916 Ext = getExtendTypeForInst(*ExtDef, MRI);
7918 return std::nullopt;
7922 Ext = getExtendTypeForInst(*RootDef, MRI);
7924 return std::nullopt;
7932 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7933 if (isDef32(*ExtInst))
7934 return std::nullopt;
7940 MachineIRBuilder MIB(*RootDef);
7941 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7943 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7944 [=](MachineInstrBuilder &MIB) {
7945 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7949InstructionSelector::ComplexRendererFns
7950AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7952 return std::nullopt;
7953 MachineRegisterInfo &MRI =
7957 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7962 return std::nullopt;
7965 if (Unmerge->getNumDefs() == 2 &&
7967 Register ExtReg = Unmerge->getSourceReg();
7968 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7972 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7976 LaneIdx->Value.getSExtValue() == 1) {
7977 Register ExtReg = ExtElt->getVectorReg();
7978 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7982 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7983 auto LaneIdx = Subvec->getIndexImm();
7985 Register ExtReg = Subvec->getSrcVec();
7986 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7990 return std::nullopt;
7993InstructionSelector::ComplexRendererFns
7994AArch64InstructionSelector::selectCVTFixedPointVecBase(
7995 const MachineOperand &Root,
bool isReciprocal)
const {
7997 return std::nullopt;
7998 const MachineRegisterInfo &MRI =
8003 return std::nullopt;
8004 std::optional<ValueAndVReg> CstVal =
8007 return std::nullopt;
8013 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
8016 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8019 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8022 return std::nullopt;
8024 if (
unsigned FBits =
8026 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8028 return std::nullopt;
8031InstructionSelector::ComplexRendererFns
8032AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8033 return selectCVTFixedPointVecBase(Root,
false);
8036InstructionSelector::ComplexRendererFns
8037AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8038 MachineOperand &Root)
const {
8039 return selectCVTFixedPointVecBase(Root,
true);
8042void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8043 const MachineInstr &
MI,
8048 InstructionSelector::ComplexRendererFns Renderer =
8049 selectCVTFixedPointVecBase(
MI.getOperand(
OpIdx),
false);
8050 assert((Renderer && Renderer->size() == 1) &&
8051 "Expected selectCVTFixedPointVec to provide a function\n");
8052 (Renderer->front())(MIB);
8055void AArch64InstructionSelector::renderFixedPointRecipXForm(
8056 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8057 InstructionSelector::ComplexRendererFns Renderer =
8058 selectCVTFixedPointVecBase(
MI.getOperand(
OpIdx),
true);
8059 assert((Renderer && Renderer->size() == 1) &&
8060 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
8061 (Renderer->front())(MIB);
8064void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8065 const MachineInstr &
MI,
8067 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8068 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8069 "Expected G_CONSTANT");
8070 std::optional<int64_t> CstVal =
8072 assert(CstVal &&
"Expected constant value");
8076void AArch64InstructionSelector::renderLogicalImm32(
8077 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8078 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8079 "Expected G_CONSTANT");
8080 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8085void AArch64InstructionSelector::renderLogicalImm64(
8086 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8087 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8088 "Expected G_CONSTANT");
8089 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8094void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8095 const MachineInstr &
MI,
8097 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
8098 "Expected G_UBSANTRAP");
8099 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8102void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8103 const MachineInstr &
MI,
8105 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8106 "Expected G_FCONSTANT");
8111void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8112 const MachineInstr &
MI,
8114 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8115 "Expected G_FCONSTANT");
8120void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8121 const MachineInstr &
MI,
8123 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8124 "Expected G_FCONSTANT");
8129void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8130 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8131 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8132 "Expected G_FCONSTANT");
8140bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8141 const MachineInstr &
MI,
unsigned NumBytes)
const {
8142 if (!
MI.mayLoadOrStore())
8145 "Expected load/store to have only one mem op!");
8146 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8149bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8150 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8158 switch (
MI.getOpcode()) {
8161 case TargetOpcode::COPY:
8162 case TargetOpcode::G_BITCAST:
8163 case TargetOpcode::G_TRUNC:
8164 case TargetOpcode::G_PHI:
8174 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8177 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8195 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8200 MO.setReg(Copy.getReg(0));
8205void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8209 for (
auto &BB : MF) {
8210 for (
auto &
MI : BB) {
8211 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8216 for (
auto *
MI : Phis) {
8238 bool HasGPROp =
false, HasFPROp =
false;
8242 const LLT &Ty = MRI.
getType(MO.getReg());
8252 if (RB->
getID() == AArch64::GPRRegBankID)
8258 if (HasGPROp && HasFPROp)
8264InstructionSelector *
8268 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.