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);
4021 "source register size too small!");
4022 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4025 MachineOperand &LaneIdxOp =
I.getOperand(2);
4026 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4037 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4040 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4041 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4046 I.eraseFromParent();
4050bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4051 MachineInstr &
I, MachineRegisterInfo &MRI) {
4052 unsigned NumElts =
I.getNumOperands() - 1;
4053 Register SrcReg =
I.getOperand(NumElts).getReg();
4054 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4055 const LLT SrcTy = MRI.
getType(SrcReg);
4057 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4059 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4065 const RegisterBank &DstRB =
4069 MachineInstr *Extract =
4070 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4074 I.eraseFromParent();
4078bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4079 MachineRegisterInfo &MRI) {
4080 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4081 "unexpected opcode");
4085 AArch64::FPRRegBankID ||
4087 AArch64::FPRRegBankID) {
4088 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4089 "currently unsupported.\n");
4095 unsigned NumElts =
I.getNumOperands() - 1;
4096 Register SrcReg =
I.getOperand(NumElts).getReg();
4097 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4098 const LLT WideTy = MRI.
getType(SrcReg);
4101 "source register size too small!");
4104 return selectSplitVectorUnmerge(
I, MRI);
4108 unsigned CopyOpc = 0;
4109 unsigned ExtractSubReg = 0;
4120 unsigned NumInsertRegs = NumElts - 1;
4126 InsertRegs.
assign(NumInsertRegs, SrcReg);
4135 unsigned SubReg = 0;
4138 assert(Found &&
"expected to find last operand's subeg idx");
4139 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4141 MachineInstr &ImpDefMI =
4142 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4147 MachineInstr &InsMI =
4149 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4166 Register CopyTo =
I.getOperand(0).getReg();
4167 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4168 .addReg(InsertRegs[0], {}, ExtractSubReg);
4172 unsigned LaneIdx = 1;
4173 for (
Register InsReg : InsertRegs) {
4174 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4175 MachineInstr &CopyInst =
4194 I.eraseFromParent();
4198bool AArch64InstructionSelector::selectConcatVectors(
4199 MachineInstr &
I, MachineRegisterInfo &MRI) {
4200 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4201 "Unexpected opcode");
4202 Register Dst =
I.getOperand(0).getReg();
4203 Register Op1 =
I.getOperand(1).getReg();
4204 Register Op2 =
I.getOperand(2).getReg();
4205 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4208 I.eraseFromParent();
4213AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4214 MachineFunction &MF)
const {
4222MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4223 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4230 RC = &AArch64::FPR128RegClass;
4231 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4234 RC = &AArch64::FPR64RegClass;
4235 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4238 RC = &AArch64::FPR32RegClass;
4239 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4242 RC = &AArch64::FPR16RegClass;
4243 Opc = AArch64::LDRHui;
4246 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4251 MachineInstr *LoadMI =
nullptr;
4252 auto &MF = MIRBuilder.
getMF();
4253 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4254 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4256 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4259 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4263 .addConstantPoolIndex(
4279static std::pair<unsigned, unsigned>
4281 unsigned Opc, SubregIdx;
4282 if (RB.
getID() == AArch64::GPRRegBankID) {
4284 Opc = AArch64::INSvi8gpr;
4285 SubregIdx = AArch64::bsub;
4286 }
else if (EltSize == 16) {
4287 Opc = AArch64::INSvi16gpr;
4288 SubregIdx = AArch64::ssub;
4289 }
else if (EltSize == 32) {
4290 Opc = AArch64::INSvi32gpr;
4291 SubregIdx = AArch64::ssub;
4292 }
else if (EltSize == 64) {
4293 Opc = AArch64::INSvi64gpr;
4294 SubregIdx = AArch64::dsub;
4300 Opc = AArch64::INSvi8lane;
4301 SubregIdx = AArch64::bsub;
4302 }
else if (EltSize == 16) {
4303 Opc = AArch64::INSvi16lane;
4304 SubregIdx = AArch64::hsub;
4305 }
else if (EltSize == 32) {
4306 Opc = AArch64::INSvi32lane;
4307 SubregIdx = AArch64::ssub;
4308 }
else if (EltSize == 64) {
4309 Opc = AArch64::INSvi64lane;
4310 SubregIdx = AArch64::dsub;
4315 return std::make_pair(
Opc, SubregIdx);
4318MachineInstr *AArch64InstructionSelector::emitInstr(
4319 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4320 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4321 const ComplexRendererFns &RenderFns)
const {
4322 assert(Opcode &&
"Expected an opcode?");
4324 "Function should only be used to produce selected instructions!");
4325 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4327 for (
auto &Fn : *RenderFns)
4333MachineInstr *AArch64InstructionSelector::emitAddSub(
4334 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4336 MachineIRBuilder &MIRBuilder)
const {
4338 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4342 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4343 bool Is32Bit =
Size == 32;
4346 if (
auto Fns = selectArithImmed(
RHS))
4347 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4351 if (
auto Fns = selectNegArithImmed(
RHS))
4352 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4356 if (
auto Fns = selectArithExtendedRegister(
RHS))
4357 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4361 if (
auto Fns = selectShiftedRegister(
RHS))
4362 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4364 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4369AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4370 MachineOperand &
RHS,
4371 MachineIRBuilder &MIRBuilder)
const {
4372 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4373 {{AArch64::ADDXri, AArch64::ADDWri},
4374 {AArch64::ADDXrs, AArch64::ADDWrs},
4375 {AArch64::ADDXrr, AArch64::ADDWrr},
4376 {AArch64::SUBXri, AArch64::SUBWri},
4377 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4378 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4382AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4383 MachineOperand &
RHS,
4384 MachineIRBuilder &MIRBuilder)
const {
4385 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4386 {{AArch64::ADDSXri, AArch64::ADDSWri},
4387 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4388 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4389 {AArch64::SUBSXri, AArch64::SUBSWri},
4390 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4391 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4395AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4396 MachineOperand &
RHS,
4397 MachineIRBuilder &MIRBuilder)
const {
4398 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4399 {{AArch64::SUBSXri, AArch64::SUBSWri},
4400 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4401 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4402 {AArch64::ADDSXri, AArch64::ADDSWri},
4403 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4404 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4408AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4409 MachineOperand &
RHS,
4410 MachineIRBuilder &MIRBuilder)
const {
4411 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4412 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4414 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4415 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4419AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4420 MachineOperand &
RHS,
4421 MachineIRBuilder &MIRBuilder)
const {
4422 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4423 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4425 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4426 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4430AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4431 MachineIRBuilder &MIRBuilder)
const {
4434 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4439AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4440 MachineIRBuilder &MIRBuilder)
const {
4443 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4448AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4449 MachineIRBuilder &MIRBuilder)
const {
4450 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4454 bool Is32Bit = (
RegSize == 32);
4455 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4456 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4457 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4461 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4464 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4471 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4472 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4473 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4476MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4477 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4478 MachineIRBuilder &MIRBuilder)
const {
4479 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4486 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4488 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4490 return emitCMP(
LHS,
RHS, MIRBuilder);
4493MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4495 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4499 "Expected a 32-bit scalar register?");
4501 const Register ZReg = AArch64::WZR;
4506 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4512 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4513 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4514 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4519MachineInstr *AArch64InstructionSelector::emitFPCompare(
4521 std::optional<CmpInst::Predicate> Pred)
const {
4522 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4527 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4538 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4542 ShouldUseImm =
true;
4546 unsigned CmpOpcTbl[2][3] = {
4547 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4548 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4550 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4562MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4564 MachineIRBuilder &MIRBuilder)
const {
4571 const LLT Op1Ty = MRI.
getType(Op1);
4572 const LLT Op2Ty = MRI.
getType(Op2);
4574 if (Op1Ty != Op2Ty) {
4575 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4578 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4581 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4592 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4596 MachineInstr *WidenedOp1 =
4597 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4598 MachineInstr *WidenedOp2 =
4599 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4600 if (!WidenedOp1 || !WidenedOp2) {
4601 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4606 unsigned InsertOpc, InsSubRegIdx;
4607 std::tie(InsertOpc, InsSubRegIdx) =
4625 MachineIRBuilder &MIRBuilder)
const {
4626 auto &MRI = *MIRBuilder.
getMRI();
4632 Size =
TRI.getRegSizeInBits(*RC);
4636 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4637 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4638 unsigned Opc = OpcTable[
Size == 64];
4639 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4644MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4646 MachineRegisterInfo *MRI = MIB.
getMRI();
4647 unsigned Opcode =
I.getOpcode();
4651 bool NeedsNegatedCarry =
4652 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4661 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4662 if (SrcMI ==
I.getPrevNode()) {
4664 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4665 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4666 CarrySrcMI->isUnsigned() &&
4667 CarrySrcMI->getCarryOutReg() == CarryReg &&
4668 selectAndRestoreState(*SrcMI))
4675 if (NeedsNegatedCarry) {
4678 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4682 auto Fns = select12BitValueWithLeftShift(1);
4683 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4686bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4687 MachineRegisterInfo &MRI) {
4692 emitCarryIn(
I, CarryInMI->getCarryInReg());
4696 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4697 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4699 Register CarryOutReg = CarryMI.getCarryOutReg();
4708 emitCSINC(CarryOutReg, ZReg, ZReg,
4709 getInvertedCondCode(OpAndCC.second), MIB);
4712 I.eraseFromParent();
4716std::pair<MachineInstr *, AArch64CC::CondCode>
4717AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4718 MachineOperand &
LHS,
4719 MachineOperand &
RHS,
4720 MachineIRBuilder &MIRBuilder)
const {
4724 case TargetOpcode::G_SADDO:
4726 case TargetOpcode::G_UADDO:
4728 case TargetOpcode::G_SSUBO:
4730 case TargetOpcode::G_USUBO:
4732 case TargetOpcode::G_SADDE:
4734 case TargetOpcode::G_UADDE:
4736 case TargetOpcode::G_SSUBE:
4738 case TargetOpcode::G_USUBE:
4759 unsigned Depth = 0) {
4766 MustBeFirst =
false;
4772 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4773 bool IsOR = Opcode == TargetOpcode::G_OR;
4785 if (MustBeFirstL && MustBeFirstR)
4791 if (!CanNegateL && !CanNegateR)
4795 CanNegate = WillNegate && CanNegateL && CanNegateR;
4798 MustBeFirst = !CanNegate;
4800 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4803 MustBeFirst = MustBeFirstL || MustBeFirstR;
4810MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4813 MachineIRBuilder &MIB)
const {
4814 auto &MRI = *MIB.
getMRI();
4817 std::optional<ValueAndVReg>
C;
4821 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4822 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4823 else if (
C->Value.ule(31))
4824 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4826 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4832 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4833 CCmpOpc = AArch64::FCCMPHrr;
4836 CCmpOpc = AArch64::FCCMPSrr;
4839 CCmpOpc = AArch64::FCCMPDrr;
4849 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4850 CCmp.
addImm(
C->Value.getZExtValue());
4851 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4852 CCmp.
addImm(
C->Value.abs().getZExtValue());
4860MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4864 auto &MRI = *MIB.
getMRI();
4882 MachineInstr *ExtraCmp;
4884 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4896 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4897 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4898 Cmp->getOperand(3).getReg(), MIB);
4905 bool IsOR = Opcode == TargetOpcode::G_OR;
4911 assert(ValidL &&
"Valid conjunction/disjunction tree");
4918 assert(ValidR &&
"Valid conjunction/disjunction tree");
4923 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4932 bool NegateAfterAll;
4933 if (Opcode == TargetOpcode::G_OR) {
4936 assert(CanNegateR &&
"at least one side must be negatable");
4937 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4941 NegateAfterR =
true;
4944 NegateR = CanNegateR;
4945 NegateAfterR = !CanNegateR;
4948 NegateAfterAll = !Negate;
4950 assert(Opcode == TargetOpcode::G_AND &&
4951 "Valid conjunction/disjunction tree");
4952 assert(!Negate &&
"Valid conjunction/disjunction tree");
4956 NegateAfterR =
false;
4957 NegateAfterAll =
false;
4962 MachineInstr *CmpR =
4973MachineInstr *AArch64InstructionSelector::emitConjunction(
4975 bool DummyCanNegate;
4976 bool DummyMustBeFirst;
4983bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4984 MachineInstr &CondMI) {
4995bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4996 MachineRegisterInfo &MRI = *MIB.
getMRI();
5015 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5024 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5030 unsigned CondOpc = CondDef->
getOpcode();
5031 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5032 if (tryOptSelectConjunction(
I, *CondDef))
5038 if (CondOpc == TargetOpcode::G_ICMP) {
5067 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5068 I.getOperand(3).getReg(), CondCode, MIB);
5069 I.eraseFromParent();
5073MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5074 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5075 MachineIRBuilder &MIRBuilder)
const {
5077 "Unexpected MachineOperand");
5078 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5101 if (
isCMN(RHSDef,
P, MRI))
5116 if (
isCMN(LHSDef,
P, MRI)) {
5133 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5136 if (!ValAndVReg || ValAndVReg->Value != 0)
5146bool AArch64InstructionSelector::selectShuffleVector(
5147 MachineInstr &
I, MachineRegisterInfo &MRI) {
5148 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5149 Register Src1Reg =
I.getOperand(1).getReg();
5150 Register Src2Reg =
I.getOperand(2).getReg();
5151 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5153 "Expected equal shuffle types during selection");
5162 SmallVector<int> NewMask;
5163 bool FirstUsed =
false;
5164 bool SecondUsed =
false;
5165 for (
int M : Mask) {
5167 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5170 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5175 FirstUsed |=
M < NumElts;
5176 SecondUsed |=
M >= NumElts;
5177 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5186 for (
int &M : NewMask) {
5188 assert(M >= ByteLanes && M < 2 * ByteLanes);
5198 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5199 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5212 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5219 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5223 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5228 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5229 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5231 I.eraseFromParent();
5236 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5239 I.eraseFromParent();
5247 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5250 I.eraseFromParent();
5254MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5256 unsigned LaneIdx,
const RegisterBank &RB,
5257 MachineIRBuilder &MIRBuilder)
const {
5258 MachineInstr *InsElt =
nullptr;
5260 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5269 if (RB.
getID() == AArch64::FPRRegBankID) {
5270 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5273 .
addUse(InsSub->getOperand(0).getReg())
5285bool AArch64InstructionSelector::selectUSMovFromExtend(
5286 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5287 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5288 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5289 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5291 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5292 const Register DefReg =
MI.getOperand(0).getReg();
5293 const LLT DstTy = MRI.
getType(DefReg);
5296 if (DstSize != 32 && DstSize != 64)
5299 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5300 MI.getOperand(1).getReg(), MRI);
5306 const LLT VecTy = MRI.
getType(Src0);
5311 const MachineInstr *ScalarToVector = emitScalarToVector(
5312 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5313 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5319 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5321 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5323 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5325 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5327 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5335 MachineInstr *ExtI =
nullptr;
5336 if (DstSize == 64 && !IsSigned) {
5338 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5339 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5341 .
addImm(AArch64::sub_32);
5344 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5347 MI.eraseFromParent();
5351MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5352 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5354 if (DstSize == 128) {
5355 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5357 Op = AArch64::MOVIv16b_ns;
5359 Op = AArch64::MOVIv8b_ns;
5362 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5366 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5373MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5374 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5378 if (DstSize == 128) {
5379 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5381 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5383 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5386 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5403MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5404 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5408 if (DstSize == 128) {
5409 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5411 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5413 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5416 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5439MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5440 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5443 if (DstSize == 128) {
5444 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5446 Op = AArch64::MOVIv2d_ns;
5448 Op = AArch64::MOVID;
5451 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5454 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5461MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5462 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5466 if (DstSize == 128) {
5467 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5469 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5471 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5474 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5491MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5492 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5495 bool IsWide =
false;
5496 if (DstSize == 128) {
5497 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5499 Op = AArch64::FMOVv4f32_ns;
5502 Op = AArch64::FMOVv2f32_ns;
5505 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5511 Op = AArch64::FMOVv2f64_ns;
5515 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5520bool AArch64InstructionSelector::selectIndexedExtLoad(
5521 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5524 Register WriteBack = ExtLd.getWritebackReg();
5529 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5530 bool IsPre = ExtLd.isPre();
5532 unsigned InsertIntoSubReg = 0;
5538 if ((IsSExt && IsFPR) || Ty.
isVector())
5546 if (MemSizeBits == 8) {
5549 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5551 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5552 NewLdDstTy = IsDst64 ? s64 : s32;
5554 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5555 InsertIntoSubReg = AArch64::bsub;
5558 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5559 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5562 }
else if (MemSizeBits == 16) {
5565 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5567 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5568 NewLdDstTy = IsDst64 ? s64 : s32;
5570 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5571 InsertIntoSubReg = AArch64::hsub;
5574 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5575 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5578 }
else if (MemSizeBits == 32) {
5580 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5583 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5584 InsertIntoSubReg = AArch64::ssub;
5587 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5588 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5600 .addImm(Cst->getSExtValue());
5605 if (InsertIntoSubReg) {
5607 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5608 .addUse(LdMI.getReg(1))
5609 .
addImm(InsertIntoSubReg);
5612 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5619 MI.eraseFromParent();
5624bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5625 MachineRegisterInfo &MRI) {
5628 Register WriteBack = Ld.getWritebackReg();
5632 "Unexpected type for indexed load");
5633 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5636 return selectIndexedExtLoad(
MI, MRI);
5640 static constexpr unsigned GPROpcodes[] = {
5641 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5643 static constexpr unsigned FPROpcodes[] = {
5644 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5647 ? FPROpcodes[
Log2_32(MemSize)]
5648 : GPROpcodes[
Log2_32(MemSize)];
5651 static constexpr unsigned GPROpcodes[] = {
5652 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5654 static constexpr unsigned FPROpcodes[] = {
5655 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5656 AArch64::LDRDpost, AArch64::LDRQpost};
5658 ? FPROpcodes[
Log2_32(MemSize)]
5659 : GPROpcodes[
Log2_32(MemSize)];
5669 MI.eraseFromParent();
5673bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5674 MachineRegisterInfo &MRI) {
5680 "Unexpected type for indexed store");
5682 LocationSize MemSize =
I.getMMO().getSize();
5683 unsigned MemSizeInBytes = MemSize.
getValue();
5685 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5686 "Unexpected indexed store size");
5687 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5691 static constexpr unsigned GPROpcodes[] = {
5692 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5694 static constexpr unsigned FPROpcodes[] = {
5695 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5699 Opc = FPROpcodes[MemSizeLog2];
5701 Opc = GPROpcodes[MemSizeLog2];
5703 static constexpr unsigned GPROpcodes[] = {
5704 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5706 static constexpr unsigned FPROpcodes[] = {
5707 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5708 AArch64::STRDpost, AArch64::STRQpost};
5711 Opc = FPROpcodes[MemSizeLog2];
5713 Opc = GPROpcodes[MemSizeLog2];
5721 Str.cloneMemRefs(
I);
5723 I.eraseFromParent();
5728AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5729 MachineIRBuilder &MIRBuilder,
5730 MachineRegisterInfo &MRI) {
5733 assert((DstSize == 64 || DstSize == 128) &&
5734 "Unexpected vector constant size");
5737 if (DstSize == 128) {
5739 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5744 if (DstSize == 64) {
5747 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5750 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5757 APInt SplatValueAsInt =
5760 : SplatValue->getUniqueInteger();
5763 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5764 MachineInstr *NewOp;
5788 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5792 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5793 unsigned NegOpc) -> MachineInstr * {
5796 APInt NegBits(DstSize, 0);
5797 unsigned NumElts = DstSize / NumBits;
5798 for (
unsigned i = 0; i < NumElts; i++)
5799 NegBits |= Neg << (NumBits * i);
5800 NegBits = DefBits ^ NegBits;
5804 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5806 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5808 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5813 if ((R = TryWithFNeg(DefBits, 32,
5814 DstSize == 64 ? AArch64::FNEGv2f32
5815 : AArch64::FNEGv4f32)) ||
5816 (R = TryWithFNeg(DefBits, 64,
5817 DstSize == 64 ? AArch64::FNEGDr
5818 : AArch64::FNEGv2f64)) ||
5819 (STI.hasFullFP16() &&
5820 (R = TryWithFNeg(DefBits, 16,
5821 DstSize == 64 ? AArch64::FNEGv4f16
5822 : AArch64::FNEGv8f16))))
5828 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5832 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5834 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5838bool AArch64InstructionSelector::tryOptConstantBuildVec(
5839 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5840 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5842 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5848 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5849 Register OpReg =
I.getOperand(Idx).getReg();
5858 std::move(AnyConst->Value)));
5871 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5873 I.eraseFromParent();
5877bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5878 MachineInstr &
I, MachineRegisterInfo &MRI) {
5883 Register Dst =
I.getOperand(0).getReg();
5884 Register EltReg =
I.getOperand(1).getReg();
5885 LLT EltTy = MRI.
getType(EltReg);
5888 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5893 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5901 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5906 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5909 I.eraseFromParent();
5914bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5915 MachineRegisterInfo &MRI) {
5916 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5919 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5920 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5923 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5925 if (tryOptBuildVecToSubregToReg(
I, MRI))
5928 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5930 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5933 MachineInstr *ScalarToVec =
5935 I.getOperand(1).getReg(), MIB);
5944 MachineInstr *PrevMI = ScalarToVec;
5945 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5948 Register OpReg =
I.getOperand(i).getReg();
5951 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5958 if (DstSize < 128) {
5961 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5964 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5969 unsigned SubReg = 0;
5972 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5973 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5979 Register DstReg =
I.getOperand(0).getReg();
5981 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5982 MachineOperand &RegOp =
I.getOperand(1);
6002 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6004 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6013bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6016 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6018 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6019 auto &MRI = *MIB.
getMRI();
6020 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6023 "Destination must be 64 bits or 128 bits?");
6024 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6025 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6028 Load.cloneMemRefs(
I);
6030 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6031 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6032 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6033 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6042bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6043 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6044 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6046 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6047 auto &MRI = *MIB.
getMRI();
6048 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6051 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6053 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6054 [](
auto MO) { return MO.getReg(); });
6058 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6073 .
addImm(LaneNo->getZExtValue())
6075 Load.cloneMemRefs(
I);
6077 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6078 unsigned SubReg = AArch64::qsub0;
6079 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6080 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6081 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6082 : DstOp(
I.getOperand(Idx).
getReg())},
6084 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6089 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6095void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6098 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6099 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6100 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6103 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6104 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6113bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6114 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6115 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6116 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6120 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6121 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6125 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6135 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6138 .
addImm(LaneNo->getZExtValue())
6145bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6146 MachineInstr &
I, MachineRegisterInfo &MRI) {
6159 case Intrinsic::aarch64_ldxp:
6160 case Intrinsic::aarch64_ldaxp: {
6162 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6163 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6169 case Intrinsic::aarch64_neon_ld1x2: {
6170 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6173 Opc = AArch64::LD1Twov8b;
6175 Opc = AArch64::LD1Twov16b;
6177 Opc = AArch64::LD1Twov4h;
6179 Opc = AArch64::LD1Twov8h;
6181 Opc = AArch64::LD1Twov2s;
6183 Opc = AArch64::LD1Twov4s;
6185 Opc = AArch64::LD1Twov2d;
6186 else if (Ty ==
S64 || Ty == P0)
6187 Opc = AArch64::LD1Twov1d;
6190 selectVectorLoadIntrinsic(
Opc, 2,
I);
6193 case Intrinsic::aarch64_neon_ld1x3: {
6194 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6197 Opc = AArch64::LD1Threev8b;
6199 Opc = AArch64::LD1Threev16b;
6201 Opc = AArch64::LD1Threev4h;
6203 Opc = AArch64::LD1Threev8h;
6205 Opc = AArch64::LD1Threev2s;
6207 Opc = AArch64::LD1Threev4s;
6209 Opc = AArch64::LD1Threev2d;
6210 else if (Ty ==
S64 || Ty == P0)
6211 Opc = AArch64::LD1Threev1d;
6214 selectVectorLoadIntrinsic(
Opc, 3,
I);
6217 case Intrinsic::aarch64_neon_ld1x4: {
6218 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6221 Opc = AArch64::LD1Fourv8b;
6223 Opc = AArch64::LD1Fourv16b;
6225 Opc = AArch64::LD1Fourv4h;
6227 Opc = AArch64::LD1Fourv8h;
6229 Opc = AArch64::LD1Fourv2s;
6231 Opc = AArch64::LD1Fourv4s;
6233 Opc = AArch64::LD1Fourv2d;
6234 else if (Ty ==
S64 || Ty == P0)
6235 Opc = AArch64::LD1Fourv1d;
6238 selectVectorLoadIntrinsic(
Opc, 4,
I);
6241 case Intrinsic::aarch64_neon_ld2: {
6242 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6245 Opc = AArch64::LD2Twov8b;
6247 Opc = AArch64::LD2Twov16b;
6249 Opc = AArch64::LD2Twov4h;
6251 Opc = AArch64::LD2Twov8h;
6253 Opc = AArch64::LD2Twov2s;
6255 Opc = AArch64::LD2Twov4s;
6257 Opc = AArch64::LD2Twov2d;
6258 else if (Ty ==
S64 || Ty == P0)
6259 Opc = AArch64::LD1Twov1d;
6262 selectVectorLoadIntrinsic(
Opc, 2,
I);
6265 case Intrinsic::aarch64_neon_ld2lane: {
6266 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6269 Opc = AArch64::LD2i8;
6271 Opc = AArch64::LD2i16;
6273 Opc = AArch64::LD2i32;
6276 Opc = AArch64::LD2i64;
6279 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6283 case Intrinsic::aarch64_neon_ld2r: {
6284 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6287 Opc = AArch64::LD2Rv8b;
6289 Opc = AArch64::LD2Rv16b;
6291 Opc = AArch64::LD2Rv4h;
6293 Opc = AArch64::LD2Rv8h;
6295 Opc = AArch64::LD2Rv2s;
6297 Opc = AArch64::LD2Rv4s;
6299 Opc = AArch64::LD2Rv2d;
6300 else if (Ty ==
S64 || Ty == P0)
6301 Opc = AArch64::LD2Rv1d;
6304 selectVectorLoadIntrinsic(
Opc, 2,
I);
6307 case Intrinsic::aarch64_neon_ld3: {
6308 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6311 Opc = AArch64::LD3Threev8b;
6313 Opc = AArch64::LD3Threev16b;
6315 Opc = AArch64::LD3Threev4h;
6317 Opc = AArch64::LD3Threev8h;
6319 Opc = AArch64::LD3Threev2s;
6321 Opc = AArch64::LD3Threev4s;
6323 Opc = AArch64::LD3Threev2d;
6324 else if (Ty ==
S64 || Ty == P0)
6325 Opc = AArch64::LD1Threev1d;
6328 selectVectorLoadIntrinsic(
Opc, 3,
I);
6331 case Intrinsic::aarch64_neon_ld3lane: {
6332 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6335 Opc = AArch64::LD3i8;
6337 Opc = AArch64::LD3i16;
6339 Opc = AArch64::LD3i32;
6342 Opc = AArch64::LD3i64;
6345 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6349 case Intrinsic::aarch64_neon_ld3r: {
6350 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6353 Opc = AArch64::LD3Rv8b;
6355 Opc = AArch64::LD3Rv16b;
6357 Opc = AArch64::LD3Rv4h;
6359 Opc = AArch64::LD3Rv8h;
6361 Opc = AArch64::LD3Rv2s;
6363 Opc = AArch64::LD3Rv4s;
6365 Opc = AArch64::LD3Rv2d;
6366 else if (Ty ==
S64 || Ty == P0)
6367 Opc = AArch64::LD3Rv1d;
6370 selectVectorLoadIntrinsic(
Opc, 3,
I);
6373 case Intrinsic::aarch64_neon_ld4: {
6374 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6377 Opc = AArch64::LD4Fourv8b;
6379 Opc = AArch64::LD4Fourv16b;
6381 Opc = AArch64::LD4Fourv4h;
6383 Opc = AArch64::LD4Fourv8h;
6385 Opc = AArch64::LD4Fourv2s;
6387 Opc = AArch64::LD4Fourv4s;
6389 Opc = AArch64::LD4Fourv2d;
6390 else if (Ty ==
S64 || Ty == P0)
6391 Opc = AArch64::LD1Fourv1d;
6394 selectVectorLoadIntrinsic(
Opc, 4,
I);
6397 case Intrinsic::aarch64_neon_ld4lane: {
6398 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6401 Opc = AArch64::LD4i8;
6403 Opc = AArch64::LD4i16;
6405 Opc = AArch64::LD4i32;
6408 Opc = AArch64::LD4i64;
6411 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6415 case Intrinsic::aarch64_neon_ld4r: {
6416 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6419 Opc = AArch64::LD4Rv8b;
6421 Opc = AArch64::LD4Rv16b;
6423 Opc = AArch64::LD4Rv4h;
6425 Opc = AArch64::LD4Rv8h;
6427 Opc = AArch64::LD4Rv2s;
6429 Opc = AArch64::LD4Rv4s;
6431 Opc = AArch64::LD4Rv2d;
6432 else if (Ty ==
S64 || Ty == P0)
6433 Opc = AArch64::LD4Rv1d;
6436 selectVectorLoadIntrinsic(
Opc, 4,
I);
6439 case Intrinsic::aarch64_neon_st1x2: {
6440 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6443 Opc = AArch64::ST1Twov8b;
6445 Opc = AArch64::ST1Twov16b;
6447 Opc = AArch64::ST1Twov4h;
6449 Opc = AArch64::ST1Twov8h;
6451 Opc = AArch64::ST1Twov2s;
6453 Opc = AArch64::ST1Twov4s;
6455 Opc = AArch64::ST1Twov2d;
6456 else if (Ty ==
S64 || Ty == P0)
6457 Opc = AArch64::ST1Twov1d;
6460 selectVectorStoreIntrinsic(
I, 2,
Opc);
6463 case Intrinsic::aarch64_neon_st1x3: {
6464 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6467 Opc = AArch64::ST1Threev8b;
6469 Opc = AArch64::ST1Threev16b;
6471 Opc = AArch64::ST1Threev4h;
6473 Opc = AArch64::ST1Threev8h;
6475 Opc = AArch64::ST1Threev2s;
6477 Opc = AArch64::ST1Threev4s;
6479 Opc = AArch64::ST1Threev2d;
6480 else if (Ty ==
S64 || Ty == P0)
6481 Opc = AArch64::ST1Threev1d;
6484 selectVectorStoreIntrinsic(
I, 3,
Opc);
6487 case Intrinsic::aarch64_neon_st1x4: {
6488 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6491 Opc = AArch64::ST1Fourv8b;
6493 Opc = AArch64::ST1Fourv16b;
6495 Opc = AArch64::ST1Fourv4h;
6497 Opc = AArch64::ST1Fourv8h;
6499 Opc = AArch64::ST1Fourv2s;
6501 Opc = AArch64::ST1Fourv4s;
6503 Opc = AArch64::ST1Fourv2d;
6504 else if (Ty ==
S64 || Ty == P0)
6505 Opc = AArch64::ST1Fourv1d;
6508 selectVectorStoreIntrinsic(
I, 4,
Opc);
6511 case Intrinsic::aarch64_neon_st2: {
6512 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6515 Opc = AArch64::ST2Twov8b;
6517 Opc = AArch64::ST2Twov16b;
6519 Opc = AArch64::ST2Twov4h;
6521 Opc = AArch64::ST2Twov8h;
6523 Opc = AArch64::ST2Twov2s;
6525 Opc = AArch64::ST2Twov4s;
6527 Opc = AArch64::ST2Twov2d;
6528 else if (Ty ==
S64 || Ty == P0)
6529 Opc = AArch64::ST1Twov1d;
6532 selectVectorStoreIntrinsic(
I, 2,
Opc);
6535 case Intrinsic::aarch64_neon_st3: {
6536 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6539 Opc = AArch64::ST3Threev8b;
6541 Opc = AArch64::ST3Threev16b;
6543 Opc = AArch64::ST3Threev4h;
6545 Opc = AArch64::ST3Threev8h;
6547 Opc = AArch64::ST3Threev2s;
6549 Opc = AArch64::ST3Threev4s;
6551 Opc = AArch64::ST3Threev2d;
6552 else if (Ty ==
S64 || Ty == P0)
6553 Opc = AArch64::ST1Threev1d;
6556 selectVectorStoreIntrinsic(
I, 3,
Opc);
6559 case Intrinsic::aarch64_neon_st4: {
6560 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6563 Opc = AArch64::ST4Fourv8b;
6565 Opc = AArch64::ST4Fourv16b;
6567 Opc = AArch64::ST4Fourv4h;
6569 Opc = AArch64::ST4Fourv8h;
6571 Opc = AArch64::ST4Fourv2s;
6573 Opc = AArch64::ST4Fourv4s;
6575 Opc = AArch64::ST4Fourv2d;
6576 else if (Ty ==
S64 || Ty == P0)
6577 Opc = AArch64::ST1Fourv1d;
6580 selectVectorStoreIntrinsic(
I, 4,
Opc);
6583 case Intrinsic::aarch64_neon_st2lane: {
6584 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6587 Opc = AArch64::ST2i8;
6589 Opc = AArch64::ST2i16;
6591 Opc = AArch64::ST2i32;
6594 Opc = AArch64::ST2i64;
6597 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6601 case Intrinsic::aarch64_neon_st3lane: {
6602 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6605 Opc = AArch64::ST3i8;
6607 Opc = AArch64::ST3i16;
6609 Opc = AArch64::ST3i32;
6612 Opc = AArch64::ST3i64;
6615 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6619 case Intrinsic::aarch64_neon_st4lane: {
6620 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6623 Opc = AArch64::ST4i8;
6625 Opc = AArch64::ST4i16;
6627 Opc = AArch64::ST4i32;
6630 Opc = AArch64::ST4i64;
6633 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6637 case Intrinsic::aarch64_mops_memset_tag: {
6650 Register DstDef =
I.getOperand(0).getReg();
6652 Register DstUse =
I.getOperand(2).getReg();
6653 Register ValUse =
I.getOperand(3).getReg();
6654 Register SizeUse =
I.getOperand(4).getReg();
6661 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6662 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6667 case Intrinsic::ptrauth_resign_load_relative: {
6668 Register DstReg =
I.getOperand(0).getReg();
6669 Register ValReg =
I.getOperand(2).getReg();
6670 uint64_t AUTKey =
I.getOperand(3).getImm();
6671 Register AUTDisc =
I.getOperand(4).getReg();
6672 uint64_t PACKey =
I.getOperand(5).getImm();
6673 Register PACDisc =
I.getOperand(6).getReg();
6674 int64_t Addend =
I.getOperand(7).getImm();
6677 uint16_t AUTConstDiscC = 0;
6678 std::tie(AUTConstDiscC, AUTAddrDisc) =
6682 uint16_t PACConstDiscC = 0;
6683 std::tie(PACConstDiscC, PACAddrDisc) =
6686 MIB.
buildCopy({AArch64::X16}, {ValReg});
6700 I.eraseFromParent();
6705 I.eraseFromParent();
6709bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6710 MachineRegisterInfo &MRI) {
6716 case Intrinsic::ptrauth_resign: {
6717 Register DstReg =
I.getOperand(0).getReg();
6718 Register ValReg =
I.getOperand(2).getReg();
6719 uint64_t AUTKey =
I.getOperand(3).getImm();
6720 Register AUTDisc =
I.getOperand(4).getReg();
6721 uint64_t PACKey =
I.getOperand(5).getImm();
6722 Register PACDisc =
I.getOperand(6).getReg();
6725 uint16_t AUTConstDiscC = 0;
6726 std::tie(AUTConstDiscC, AUTAddrDisc) =
6730 uint16_t PACConstDiscC = 0;
6731 std::tie(PACConstDiscC, PACAddrDisc) =
6734 MIB.
buildCopy({AArch64::X16}, {ValReg});
6735 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6747 I.eraseFromParent();
6750 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6751 Register DstReg =
I.getOperand(0).getReg();
6752 Register ValReg =
I.getOperand(2).getReg();
6753 uint64_t AUTKey =
I.getOperand(3).getImm();
6754 Register AUTDisc =
I.getOperand(4).getReg();
6755 Register AUTPC =
I.getOperand(5).getReg();
6756 uint64_t PACKey =
I.getOperand(6).getImm();
6757 Register PACDisc =
I.getOperand(7).getReg();
6760 "auth_with_pc_and_resign only supports IA and IB keys");
6762 uint16_t PACConstDiscC = 0;
6764 std::tie(PACConstDiscC, PACAddrDisc) =
6767 if (PACAddrDisc == AArch64::NoRegister)
6768 PACAddrDisc = AArch64::XZR;
6770 MIB.
buildCopy({AArch64::X17}, {ValReg});
6771 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6783 I.eraseFromParent();
6786 case Intrinsic::ptrauth_auth: {
6787 Register DstReg =
I.getOperand(0).getReg();
6788 Register ValReg =
I.getOperand(2).getReg();
6789 uint64_t AUTKey =
I.getOperand(3).getImm();
6790 Register AUTDisc =
I.getOperand(4).getReg();
6793 uint16_t AUTConstDiscC = 0;
6794 std::tie(AUTConstDiscC, AUTAddrDisc) =
6798 MIB.
buildCopy({AArch64::X16}, {ValReg});
6799 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6820 I.eraseFromParent();
6823 case Intrinsic::frameaddress:
6824 case Intrinsic::returnaddress: {
6825 MachineFunction &MF = *
I.getParent()->getParent();
6828 unsigned Depth =
I.getOperand(2).getImm();
6829 Register DstReg =
I.getOperand(0).getReg();
6832 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6833 if (!MFReturnAddr) {
6838 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6841 if (STI.hasPAuth()) {
6842 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6849 I.eraseFromParent();
6858 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6860 FrameAddr = NextFrame;
6863 if (IntrinID == Intrinsic::frameaddress)
6868 if (STI.hasPAuth()) {
6870 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6871 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6880 I.eraseFromParent();
6883 case Intrinsic::aarch64_neon_tbl2:
6884 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6886 case Intrinsic::aarch64_neon_tbl3:
6887 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6890 case Intrinsic::aarch64_neon_tbl4:
6891 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6893 case Intrinsic::aarch64_neon_tbx2:
6894 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6896 case Intrinsic::aarch64_neon_tbx3:
6897 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6899 case Intrinsic::aarch64_neon_tbx4:
6900 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6902 case Intrinsic::swift_async_context_addr:
6903 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6910 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6911 I.eraseFromParent();
6946bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6947 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6948 Register DefReg =
I.getOperand(0).getReg();
6949 Register Addr =
I.getOperand(1).getReg();
6950 uint64_t
Key =
I.getOperand(2).getImm();
6951 Register AddrDisc =
I.getOperand(3).getReg();
6952 uint64_t Disc =
I.getOperand(4).getImm();
6962 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6978 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6990 const GlobalValue *GV;
7001 MachineIRBuilder MIB(
I);
7007 "unsupported non-GOT op flags on ptrauth global reference");
7009 "unsupported non-GOT reference to weak ptrauth global");
7012 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7019 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7020 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7021 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7024 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7029 I.eraseFromParent();
7041 "unsupported non-zero offset in weak ptrauth global reference");
7046 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7047 .addGlobalAddress(GV,
Offset)
7052 I.eraseFromParent();
7056void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7057 MachineRegisterInfo &MRI,
7058 unsigned NumVec,
unsigned Opc1,
7059 unsigned Opc2,
bool isExt) {
7060 Register DstReg =
I.getOperand(0).getReg();
7065 for (
unsigned i = 0; i < NumVec; i++)
7066 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7069 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7070 MachineInstrBuilder
Instr;
7077 I.eraseFromParent();
7080InstructionSelector::ComplexRendererFns
7081AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7083 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7084 return std::nullopt;
7085 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7086 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7089InstructionSelector::ComplexRendererFns
7090AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7092 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7093 return std::nullopt;
7094 uint64_t Enc = 31 - *MaybeImmed;
7095 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7098InstructionSelector::ComplexRendererFns
7099AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7101 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7102 return std::nullopt;
7103 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7104 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7107InstructionSelector::ComplexRendererFns
7108AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7110 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7111 return std::nullopt;
7112 uint64_t Enc = 63 - *MaybeImmed;
7113 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7121InstructionSelector::ComplexRendererFns
7122AArch64InstructionSelector::select12BitValueWithLeftShift(
7123 uint64_t Immed)
const {
7125 if (Immed >> 12 == 0) {
7127 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7129 Immed = Immed >> 12;
7131 return std::nullopt;
7135 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7136 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7143InstructionSelector::ComplexRendererFns
7144AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7151 if (MaybeImmed == std::nullopt)
7152 return std::nullopt;
7153 return select12BitValueWithLeftShift(*MaybeImmed);
7158InstructionSelector::ComplexRendererFns
7159AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7163 return std::nullopt;
7165 if (MaybeImmed == std::nullopt)
7166 return std::nullopt;
7167 uint64_t Immed = *MaybeImmed;
7173 return std::nullopt;
7179 Immed = ~((uint32_t)Immed) + 1;
7181 Immed = ~Immed + 1ULL;
7183 if (Immed & 0xFFFFFFFFFF000000ULL)
7184 return std::nullopt;
7186 Immed &= 0xFFFFFFULL;
7187 return select12BitValueWithLeftShift(Immed);
7204std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7205 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7206 if (
MI.getOpcode() == AArch64::G_SHL) {
7210 MI.getOperand(2).getReg(), MRI)) {
7211 const APInt ShiftVal = ValAndVeg->Value;
7214 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7217 return std::nullopt;
7225bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7226 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7227 bool IsAddrOperand)
const {
7232 MI.getParent()->getParent()->getFunction().hasOptSize())
7235 if (IsAddrOperand) {
7237 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7241 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7242 MachineInstr *OffsetInst =
7248 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7259 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7262InstructionSelector::ComplexRendererFns
7263AArch64InstructionSelector::selectExtendedSHL(
7264 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7265 unsigned SizeInBytes,
bool WantsExt)
const {
7266 assert(
Base.isReg() &&
"Expected base to be a register operand");
7267 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7272 unsigned OffsetOpc = OffsetInst->
getOpcode();
7273 bool LookedThroughZExt =
false;
7274 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7276 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7277 return std::nullopt;
7281 LookedThroughZExt =
true;
7283 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7284 return std::nullopt;
7287 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7288 if (LegalShiftVal == 0)
7289 return std::nullopt;
7290 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7291 return std::nullopt;
7302 if (OffsetOpc == TargetOpcode::G_SHL)
7303 return std::nullopt;
7309 return std::nullopt;
7314 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7318 if (OffsetOpc == TargetOpcode::G_MUL) {
7320 return std::nullopt;
7326 if ((ImmVal & 0x7) != ImmVal)
7327 return std::nullopt;
7331 if (ImmVal != LegalShiftVal)
7332 return std::nullopt;
7334 unsigned SignExtend = 0;
7338 if (!LookedThroughZExt) {
7340 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7342 return std::nullopt;
7347 return std::nullopt;
7353 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7358 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7359 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7360 [=](MachineInstrBuilder &MIB) {
7363 MIB.addImm(SignExtend);
7376InstructionSelector::ComplexRendererFns
7377AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7378 MachineOperand &Root,
unsigned SizeInBytes)
const {
7380 return std::nullopt;
7395 MachineInstr *PtrAdd =
7397 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7398 return std::nullopt;
7402 MachineInstr *OffsetInst =
7404 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7417InstructionSelector::ComplexRendererFns
7418AArch64InstructionSelector::selectAddrModeRegisterOffset(
7419 MachineOperand &Root)
const {
7424 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7425 return std::nullopt;
7431 return std::nullopt;
7434 return {{[=](MachineInstrBuilder &MIB) {
7437 [=](MachineInstrBuilder &MIB) {
7440 [=](MachineInstrBuilder &MIB) {
7450InstructionSelector::ComplexRendererFns
7451AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7452 unsigned SizeInBytes)
const {
7455 return std::nullopt;
7456 MachineInstr *PtrAdd =
7459 return std::nullopt;
7477 unsigned Scale =
Log2_32(SizeInBytes);
7478 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7482 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7483 ImmOff < (0x1000 << Scale))
7484 return std::nullopt;
7489 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7493 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7499 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7500 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7505 return std::nullopt;
7509 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7515 return selectAddrModeRegisterOffset(Root);
7524InstructionSelector::ComplexRendererFns
7525AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7526 unsigned SizeInBytes)
const {
7529 MachineInstr *PtrAdd =
7531 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7532 return std::nullopt;
7553 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7562 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7563 return std::nullopt;
7567 getExtendTypeForInst(*OffsetInst, MRI,
true);
7569 return std::nullopt;
7572 MachineIRBuilder MIB(*PtrAdd);
7574 AArch64::GPR32RegClass, MIB);
7578 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7579 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7580 [=](MachineInstrBuilder &MIB) {
7581 MIB.addImm(SignExtend);
7591InstructionSelector::ComplexRendererFns
7592AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7593 unsigned Size)
const {
7594 MachineRegisterInfo &MRI =
7598 return std::nullopt;
7600 if (!isBaseWithConstantOffset(Root, MRI))
7601 return std::nullopt;
7605 MachineOperand &OffImm = RootDef->
getOperand(2);
7606 if (!OffImm.
isReg())
7607 return std::nullopt;
7609 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7610 return std::nullopt;
7612 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7614 return std::nullopt;
7617 if (RHSC >= -256 && RHSC < 256) {
7620 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7621 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7624 return std::nullopt;
7627InstructionSelector::ComplexRendererFns
7628AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7630 MachineRegisterInfo &MRI)
const {
7631 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7632 return std::nullopt;
7635 return std::nullopt;
7640 return std::nullopt;
7644 return std::nullopt;
7648 return std::nullopt;
7651 MachineIRBuilder MIRBuilder(RootDef);
7653 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7654 [=](MachineInstrBuilder &MIB) {
7655 MIB.addGlobalAddress(GV,
Offset,
7664InstructionSelector::ComplexRendererFns
7665AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7666 unsigned Size)
const {
7671 return std::nullopt;
7674 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7676 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7677 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7685 MachineInstr *RootParent = Root.
getParent();
7687 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7689 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7694 if (isBaseWithConstantOffset(Root, MRI)) {
7702 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7703 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7705 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7706 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7710 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7711 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7718 if (selectAddrModeUnscaled(Root,
Size))
7719 return std::nullopt;
7722 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7723 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7730 switch (
MI.getOpcode()) {
7733 case TargetOpcode::G_SHL:
7735 case TargetOpcode::G_LSHR:
7737 case TargetOpcode::G_ASHR:
7739 case TargetOpcode::G_ROTR:
7746InstructionSelector::ComplexRendererFns
7747AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7748 bool AllowROR)
const {
7750 return std::nullopt;
7751 MachineRegisterInfo &MRI =
7759 return std::nullopt;
7761 return std::nullopt;
7762 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7763 return std::nullopt;
7766 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7769 return std::nullopt;
7773 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7777 unsigned Val = *Immed & (NumBits - 1);
7780 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7781 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7785 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7786 unsigned Opc =
MI.getOpcode();
7789 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7791 if (
Opc == TargetOpcode::G_SEXT)
7794 Size =
MI.getOperand(2).getImm();
7795 assert(
Size != 64 &&
"Extend from 64 bits?");
7808 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7810 assert(
Size != 64 &&
"Extend from 64 bits?");
7825 if (
Opc != TargetOpcode::G_AND)
7831 uint64_t AndMask = *MaybeAndMask;
7844Register AArch64InstructionSelector::moveScalarRegClass(
7846 MachineRegisterInfo &MRI = *MIB.
getMRI();
7856 return Copy.getReg(0);
7861InstructionSelector::ComplexRendererFns
7862AArch64InstructionSelector::selectArithExtendedRegister(
7863 MachineOperand &Root)
const {
7865 return std::nullopt;
7866 MachineRegisterInfo &MRI =
7869 uint64_t ShiftVal = 0;
7874 return std::nullopt;
7876 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7877 return std::nullopt;
7880 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7885 return std::nullopt;
7886 ShiftVal = *MaybeShiftVal;
7888 return std::nullopt;
7893 return std::nullopt;
7894 Ext = getExtendTypeForInst(*ExtDef, MRI);
7896 return std::nullopt;
7900 Ext = getExtendTypeForInst(*RootDef, MRI);
7902 return std::nullopt;
7910 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7911 if (isDef32(*ExtInst))
7912 return std::nullopt;
7918 MachineIRBuilder MIB(*RootDef);
7919 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7921 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7922 [=](MachineInstrBuilder &MIB) {
7923 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7927InstructionSelector::ComplexRendererFns
7928AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7930 return std::nullopt;
7931 MachineRegisterInfo &MRI =
7935 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7940 return std::nullopt;
7943 if (Unmerge->getNumDefs() == 2 &&
7945 Register ExtReg = Unmerge->getSourceReg();
7946 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7950 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7954 LaneIdx->Value.getSExtValue() == 1) {
7955 Register ExtReg = ExtElt->getVectorReg();
7956 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7960 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7961 auto LaneIdx = Subvec->getIndexImm();
7963 Register ExtReg = Subvec->getSrcVec();
7964 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7968 return std::nullopt;
7971InstructionSelector::ComplexRendererFns
7972AArch64InstructionSelector::selectCVTFixedPointVecBase(
7973 const MachineOperand &Root,
bool isReciprocal)
const {
7975 return std::nullopt;
7976 const MachineRegisterInfo &MRI =
7981 return std::nullopt;
7982 std::optional<ValueAndVReg> CstVal =
7985 return std::nullopt;
7991 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7994 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7997 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8000 return std::nullopt;
8002 if (
unsigned FBits =
8004 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8006 return std::nullopt;
8009InstructionSelector::ComplexRendererFns
8010AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8011 return selectCVTFixedPointVecBase(Root,
false);
8014InstructionSelector::ComplexRendererFns
8015AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8016 MachineOperand &Root)
const {
8017 return selectCVTFixedPointVecBase(Root,
true);
8020void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8021 const MachineInstr &
MI,
8026 InstructionSelector::ComplexRendererFns Renderer =
8027 selectCVTFixedPointVecBase(
MI.getOperand(
OpIdx),
false);
8028 assert((Renderer && Renderer->size() == 1) &&
8029 "Expected selectCVTFixedPointVec to provide a function\n");
8030 (Renderer->front())(MIB);
8033void AArch64InstructionSelector::renderFixedPointRecipXForm(
8034 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8035 InstructionSelector::ComplexRendererFns Renderer =
8036 selectCVTFixedPointVecBase(
MI.getOperand(
OpIdx),
true);
8037 assert((Renderer && Renderer->size() == 1) &&
8038 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
8039 (Renderer->front())(MIB);
8042void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8043 const MachineInstr &
MI,
8045 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8046 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8047 "Expected G_CONSTANT");
8048 std::optional<int64_t> CstVal =
8050 assert(CstVal &&
"Expected constant value");
8054void AArch64InstructionSelector::renderLogicalImm32(
8055 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8056 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8057 "Expected G_CONSTANT");
8058 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8063void AArch64InstructionSelector::renderLogicalImm64(
8064 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8065 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
8066 "Expected G_CONSTANT");
8067 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8072void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8073 const MachineInstr &
MI,
8075 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
8076 "Expected G_UBSANTRAP");
8077 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8080void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8081 const MachineInstr &
MI,
8083 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8084 "Expected G_FCONSTANT");
8089void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8090 const MachineInstr &
MI,
8092 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8093 "Expected G_FCONSTANT");
8098void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8099 const MachineInstr &
MI,
8101 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8102 "Expected G_FCONSTANT");
8107void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8108 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8109 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8110 "Expected G_FCONSTANT");
8118bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8119 const MachineInstr &
MI,
unsigned NumBytes)
const {
8120 if (!
MI.mayLoadOrStore())
8123 "Expected load/store to have only one mem op!");
8124 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8127bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8128 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8136 switch (
MI.getOpcode()) {
8139 case TargetOpcode::COPY:
8140 case TargetOpcode::G_BITCAST:
8141 case TargetOpcode::G_TRUNC:
8142 case TargetOpcode::G_PHI:
8152 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8155 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8173 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8178 MO.setReg(Copy.getReg(0));
8183void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8187 for (
auto &BB : MF) {
8188 for (
auto &
MI : BB) {
8189 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8194 for (
auto *
MI : Phis) {
8216 bool HasGPROp =
false, HasFPROp =
false;
8220 const LLT &Ty = MRI.
getType(MO.getReg());
8230 if (RB->
getID() == AArch64::GPRRegBankID)
8236 if (HasGPROp && HasFPROp)
8242InstructionSelector *
8246 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
static std::pair< const TargetRegisterClass *, const TargetRegisterClass * > getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Helper function to get the source and destination register classes for a copy.
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc (such as G_OR or G_SDIV),...
static bool getSubRegForClass(const TargetRegisterClass *RC, const TargetRegisterInfo &TRI, unsigned &SubReg)
Returns the correct subregister to use for a given register class.
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI, Register SrcReg, const TargetRegisterClass *To, unsigned SubReg)
Helper function for selectCopy.
static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P, Register RHS={}, MachineRegisterInfo *MRI=nullptr)
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, const AArch64RegisterBankInfo &RBI)
static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool unsupportedBinOp(const MachineInstr &I, const AArch64RegisterBankInfo &RBI, const MachineRegisterInfo &MRI, const AArch64RegisterInfo &TRI)
Check whether I is a currently unsupported binary operation:
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
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.
@ C
The default llvm calling convention, compatible with C.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
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.