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;
486 int OpIdx = -1)
const;
488 int OpIdx = -1)
const;
490 int OpIdx = -1)
const;
494 int OpIdx = -1)
const;
496 int OpIdx = -1)
const;
498 int OpIdx = -1)
const;
501 int OpIdx = -1)
const;
507 bool tryOptSelect(
GSelect &Sel);
514 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
527 bool ProduceNonFlagSettingCondBr =
false;
536#define GET_GLOBALISEL_PREDICATES_DECL
537#include "AArch64GenGlobalISel.inc"
538#undef GET_GLOBALISEL_PREDICATES_DECL
542#define GET_GLOBALISEL_TEMPORARIES_DECL
543#include "AArch64GenGlobalISel.inc"
544#undef GET_GLOBALISEL_TEMPORARIES_DECL
549#define GET_GLOBALISEL_IMPL
550#include "AArch64GenGlobalISel.inc"
551#undef GET_GLOBALISEL_IMPL
553AArch64InstructionSelector::AArch64InstructionSelector(
556 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
559#include
"AArch64GenGlobalISel.inc"
562#include
"AArch64GenGlobalISel.inc"
574 bool GetAllRegSet =
false) {
575 if (RB.
getID() == AArch64::GPRRegBankID) {
576 if (Ty.getSizeInBits() <= 32)
577 return GetAllRegSet ? &AArch64::GPR32allRegClass
578 : &AArch64::GPR32RegClass;
579 if (Ty.getSizeInBits() == 64)
580 return GetAllRegSet ? &AArch64::GPR64allRegClass
581 : &AArch64::GPR64RegClass;
582 if (Ty.getSizeInBits() == 128)
583 return &AArch64::XSeqPairsClassRegClass;
587 if (RB.
getID() == AArch64::FPRRegBankID) {
588 switch (Ty.getSizeInBits()) {
590 return &AArch64::FPR8RegClass;
592 return &AArch64::FPR16RegClass;
594 return &AArch64::FPR32RegClass;
596 return &AArch64::FPR64RegClass;
598 return &AArch64::FPR128RegClass;
610 bool GetAllRegSet =
false) {
613 "Expected FPR regbank for scalable type size");
614 return &AArch64::ZPRRegClass;
617 unsigned RegBankID = RB.
getID();
619 if (RegBankID == AArch64::GPRRegBankID) {
621 if (SizeInBits <= 32)
622 return GetAllRegSet ? &AArch64::GPR32allRegClass
623 : &AArch64::GPR32RegClass;
624 if (SizeInBits == 64)
625 return GetAllRegSet ? &AArch64::GPR64allRegClass
626 : &AArch64::GPR64RegClass;
627 if (SizeInBits == 128)
628 return &AArch64::XSeqPairsClassRegClass;
631 if (RegBankID == AArch64::FPRRegBankID) {
634 "Unexpected scalable register size");
635 return &AArch64::ZPRRegClass;
638 switch (SizeInBits) {
642 return &AArch64::FPR8RegClass;
644 return &AArch64::FPR16RegClass;
646 return &AArch64::FPR32RegClass;
648 return &AArch64::FPR64RegClass;
650 return &AArch64::FPR128RegClass;
660 switch (
TRI.getRegSizeInBits(*RC)) {
668 if (RC != &AArch64::FPR32RegClass)
678 dbgs() <<
"Couldn't find appropriate subregister for register class.");
687 switch (RB.
getID()) {
688 case AArch64::GPRRegBankID:
690 case AArch64::FPRRegBankID:
713 const unsigned RegClassIDs[],
715 unsigned NumRegs = Regs.
size();
718 assert(NumRegs >= 2 && NumRegs <= 4 &&
719 "Only support between two and 4 registers in a tuple!");
721 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
723 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
724 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
725 RegSequence.addUse(Regs[
I]);
726 RegSequence.addImm(SubRegs[
I]);
728 return RegSequence.getReg(0);
733 static const unsigned RegClassIDs[] = {
734 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
735 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
736 AArch64::dsub2, AArch64::dsub3};
737 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
742 static const unsigned RegClassIDs[] = {
743 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
744 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
745 AArch64::qsub2, AArch64::qsub3};
746 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
751 auto &
MBB = *
MI.getParent();
752 auto &MF = *
MBB.getParent();
753 auto &
MRI = MF.getRegInfo();
759 else if (Root.
isReg()) {
764 Immed = ValAndVReg->Value.getSExtValue();
780 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
787 for (
auto &MO :
I.operands()) {
790 LLVM_DEBUG(
dbgs() <<
"Generic inst non-reg operands are unsupported\n");
798 if (!MO.getReg().isVirtual()) {
799 LLVM_DEBUG(
dbgs() <<
"Generic inst has physical register operand\n");
809 if (PrevOpBank && OpBank != PrevOpBank) {
810 LLVM_DEBUG(
dbgs() <<
"Generic inst operands have different banks\n");
825 case AArch64::GPRRegBankID:
827 switch (GenericOpc) {
828 case TargetOpcode::G_SHL:
829 return AArch64::LSLVWr;
830 case TargetOpcode::G_LSHR:
831 return AArch64::LSRVWr;
832 case TargetOpcode::G_ASHR:
833 return AArch64::ASRVWr;
837 }
else if (OpSize == 64) {
838 switch (GenericOpc) {
839 case TargetOpcode::G_PTR_ADD:
840 return AArch64::ADDXrr;
841 case TargetOpcode::G_SHL:
842 return AArch64::LSLVXr;
843 case TargetOpcode::G_LSHR:
844 return AArch64::LSRVXr;
845 case TargetOpcode::G_ASHR:
846 return AArch64::ASRVXr;
852 case AArch64::FPRRegBankID:
855 switch (GenericOpc) {
856 case TargetOpcode::G_FADD:
857 return AArch64::FADDSrr;
858 case TargetOpcode::G_FSUB:
859 return AArch64::FSUBSrr;
860 case TargetOpcode::G_FMUL:
861 return AArch64::FMULSrr;
862 case TargetOpcode::G_FDIV:
863 return AArch64::FDIVSrr;
868 switch (GenericOpc) {
869 case TargetOpcode::G_FADD:
870 return AArch64::FADDDrr;
871 case TargetOpcode::G_FSUB:
872 return AArch64::FSUBDrr;
873 case TargetOpcode::G_FMUL:
874 return AArch64::FMULDrr;
875 case TargetOpcode::G_FDIV:
876 return AArch64::FDIVDrr;
877 case TargetOpcode::G_OR:
878 return AArch64::ORRv8i8;
895 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
897 case AArch64::GPRRegBankID:
900 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
902 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
904 return isStore ? AArch64::STRWui : AArch64::LDRWui;
906 return isStore ? AArch64::STRXui : AArch64::LDRXui;
909 case AArch64::FPRRegBankID:
912 return isStore ? AArch64::STRBui : AArch64::LDRBui;
914 return isStore ? AArch64::STRHui : AArch64::LDRHui;
916 return isStore ? AArch64::STRSui : AArch64::LDRSui;
918 return isStore ? AArch64::STRDui : AArch64::LDRDui;
920 return isStore ? AArch64::STRQui : AArch64::LDRQui;
934 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
935 assert(To &&
"Destination register class cannot be null");
942 RegOp.
setReg(SubRegCopy.getReg(0));
946 if (!
I.getOperand(0).getReg().isPhysical())
956static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
960 Register DstReg =
I.getOperand(0).getReg();
961 Register SrcReg =
I.getOperand(1).getReg();
976 if (SrcRegBank != DstRegBank &&
995 if (
Reg.isPhysical())
1003 RC = getRegClassForTypeOnBank(Ty, RB);
1006 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
1019 Register DstReg =
I.getOperand(0).getReg();
1020 Register SrcReg =
I.getOperand(1).getReg();
1039 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1043 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1044 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1055 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1057 }
else if (SrcSize > DstSize) {
1064 }
else if (DstSize > SrcSize) {
1071 Register PromoteReg =
MRI.createVirtualRegister(PromotionRC);
1073 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1078 RegOp.
setReg(PromoteReg);
1097 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1098 I.setDesc(
TII.get(AArch64::COPY));
1099 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1103 I.setDesc(
TII.get(AArch64::COPY));
1111 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1114 "Expected both select operands to have the same regbank?");
1115 LLT Ty =
MRI.getType(True);
1120 "Expected 32 bit or 64 bit select only?");
1121 const bool Is32Bit =
Size == 32;
1123 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1124 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1130 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1132 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &
MRI,
1147 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1164 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1183 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1199 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &
MRI,
1205 if (!TrueCst && !FalseCst)
1208 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1209 if (TrueCst && FalseCst) {
1210 int64_t
T = TrueCst->Value.getSExtValue();
1211 int64_t
F = FalseCst->Value.getSExtValue();
1213 if (
T == 0 &&
F == 1) {
1215 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1221 if (
T == 0 &&
F == -1) {
1223 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1231 int64_t
T = TrueCst->Value.getSExtValue();
1234 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1243 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1252 int64_t
F = FalseCst->Value.getSExtValue();
1255 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1262 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1270 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1271 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1273 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1275 return &*SelectInst;
1280 MachineRegisterInfo *
MRI =
nullptr) {
1293 if (ValAndVReg && ValAndVReg->Value == 0)
1300 if (ValAndVReg && ValAndVReg->Value == 0)
1404 assert(
Reg.isValid() &&
"Expected valid register!");
1405 bool HasZext =
false;
1407 unsigned Opc =
MI->getOpcode();
1409 if (!
MI->getOperand(0).isReg() ||
1410 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1417 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1418 Opc == TargetOpcode::G_TRUNC) {
1419 if (
Opc == TargetOpcode::G_ZEXT)
1422 Register NextReg =
MI->getOperand(1).getReg();
1424 if (!NextReg.
isValid() || !
MRI.hasOneNonDBGUse(NextReg))
1433 std::optional<uint64_t>
C;
1438 case TargetOpcode::G_AND:
1439 case TargetOpcode::G_XOR: {
1440 TestReg =
MI->getOperand(1).getReg();
1441 Register ConstantReg =
MI->getOperand(2).getReg();
1452 C = VRegAndVal->Value.getZExtValue();
1454 C = VRegAndVal->Value.getSExtValue();
1458 case TargetOpcode::G_ASHR:
1459 case TargetOpcode::G_LSHR:
1460 case TargetOpcode::G_SHL: {
1461 TestReg =
MI->getOperand(1).getReg();
1465 C = VRegAndVal->Value.getSExtValue();
1477 unsigned TestRegSize =
MRI.getType(TestReg).getSizeInBits();
1481 case TargetOpcode::G_AND:
1483 if ((*
C >> Bit) & 1)
1486 case TargetOpcode::G_SHL:
1489 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1494 case TargetOpcode::G_ASHR:
1499 if (Bit >= TestRegSize)
1500 Bit = TestRegSize - 1;
1502 case TargetOpcode::G_LSHR:
1504 if ((Bit + *
C) < TestRegSize) {
1509 case TargetOpcode::G_XOR:
1518 if ((*
C >> Bit) & 1)
1533MachineInstr *AArch64InstructionSelector::emitTestBit(
1534 Register TestReg, uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1535 MachineIRBuilder &MIB)
const {
1537 assert(ProduceNonFlagSettingCondBr &&
1538 "Cannot emit TB(N)Z with speculation tracking!");
1539 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1543 LLT Ty =
MRI.getType(TestReg);
1546 assert(Bit < 64 &&
"Bit is too large!");
1550 bool UseWReg =
Bit < 32;
1551 unsigned NecessarySize = UseWReg ? 32 : 64;
1552 if (
Size != NecessarySize)
1553 TestReg = moveScalarRegClass(
1554 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1557 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1558 {AArch64::TBZW, AArch64::TBNZW}};
1559 unsigned Opc = OpcTable[UseWReg][IsNegative];
1566bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1567 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1568 MachineIRBuilder &MIB)
const {
1569 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1596 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1603 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1607MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1609 MachineBasicBlock *DestMBB,
1610 MachineIRBuilder &MIB)
const {
1611 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1612 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1614 AArch64::GPRRegBankID &&
1615 "Expected GPRs only?");
1616 auto Ty =
MRI.getType(CompareReg);
1619 assert(Width <= 64 &&
"Expected width to be at most 64?");
1620 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1621 {AArch64::CBNZW, AArch64::CBNZX}};
1622 unsigned Opc = OpcTable[IsNegative][Width == 64];
1623 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1628bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1629 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1631 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1639 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1643 I.eraseFromParent();
1647bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1648 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1650 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1656 if (!ProduceNonFlagSettingCondBr)
1659 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1660 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1675 if (VRegAndVal && !AndInst) {
1676 int64_t
C = VRegAndVal->Value.getSExtValue();
1681 uint64_t
Bit =
MRI.getType(
LHS).getSizeInBits() - 1;
1682 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1683 I.eraseFromParent();
1690 uint64_t
Bit =
MRI.getType(
LHS).getSizeInBits() - 1;
1691 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1692 I.eraseFromParent();
1699 uint64_t
Bit =
MRI.getType(
LHS).getSizeInBits() - 1;
1700 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1701 I.eraseFromParent();
1715 if (VRegAndVal && VRegAndVal->Value == 0) {
1723 tryOptAndIntoCompareBranch(
1725 I.eraseFromParent();
1730 auto LHSTy =
MRI.getType(
LHS);
1731 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1733 I.eraseFromParent();
1742bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1743 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1745 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1746 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1750 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1757 I.eraseFromParent();
1761bool AArch64InstructionSelector::selectCompareBranch(
1762 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &
MRI) {
1763 Register CondReg =
I.getOperand(0).getReg();
1764 MachineInstr *CCMI =
MRI.getVRegDef(CondReg);
1768 if (CCMIOpc == TargetOpcode::G_FCMP)
1769 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1770 if (CCMIOpc == TargetOpcode::G_ICMP)
1771 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1776 if (ProduceNonFlagSettingCondBr) {
1777 emitTestBit(CondReg, 0,
true,
1778 I.getOperand(1).getMBB(), MIB);
1779 I.eraseFromParent();
1789 .
addMBB(
I.getOperand(1).getMBB());
1790 I.eraseFromParent();
1798 assert(
MRI.getType(
Reg).isVector() &&
"Expected a *vector* shift operand");
1809 return std::nullopt;
1811 int64_t Imm = *ShiftImm;
1813 return std::nullopt;
1814 switch (SrcTy.getElementType().getSizeInBits()) {
1817 return std::nullopt;
1820 return std::nullopt;
1824 return std::nullopt;
1828 return std::nullopt;
1832 return std::nullopt;
1838bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1839 MachineRegisterInfo &
MRI) {
1840 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1841 Register DstReg =
I.getOperand(0).getReg();
1842 const LLT Ty =
MRI.getType(DstReg);
1843 Register Src1Reg =
I.getOperand(1).getReg();
1844 Register Src2Reg =
I.getOperand(2).getReg();
1855 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1857 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1859 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1861 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1863 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1865 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1867 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1879 I.eraseFromParent();
1883bool AArch64InstructionSelector::selectVectorAshrLshr(
1884 MachineInstr &
I, MachineRegisterInfo &
MRI) {
1885 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1886 I.getOpcode() == TargetOpcode::G_LSHR);
1887 Register DstReg =
I.getOperand(0).getReg();
1888 const LLT Ty =
MRI.getType(DstReg);
1889 Register Src1Reg =
I.getOperand(1).getReg();
1890 Register Src2Reg =
I.getOperand(2).getReg();
1895 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1905 unsigned NegOpc = 0;
1906 const TargetRegisterClass *RC =
1907 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1909 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1910 NegOpc = AArch64::NEGv2i64;
1912 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1913 NegOpc = AArch64::NEGv4i32;
1915 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1916 NegOpc = AArch64::NEGv2i32;
1918 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1919 NegOpc = AArch64::NEGv4i16;
1921 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1922 NegOpc = AArch64::NEGv8i16;
1924 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1925 NegOpc = AArch64::NEGv16i8;
1927 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1928 NegOpc = AArch64::NEGv8i8;
1934 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1938 I.eraseFromParent();
1942bool AArch64InstructionSelector::selectVaStartAAPCS(
1943 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &
MRI)
const {
1952 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1954 const auto *PtrRegClass =
1955 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1957 const MCInstrDesc &MCIDAddAddr =
1959 const MCInstrDesc &MCIDStoreAddr =
1971 const auto VAList =
I.getOperand(0).getReg();
1974 unsigned OffsetBytes = 0;
1978 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1979 const Register Top =
MRI.createVirtualRegister(PtrRegClass);
1980 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1987 const auto *MMO = *
I.memoperands_begin();
1988 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1991 .
addImm(OffsetBytes / PtrSize)
1993 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1997 OffsetBytes += PtrSize;
2013 const auto PushIntConstant = [&](
const int32_t
Value) {
2014 constexpr int IntSize = 4;
2015 const Register Temp =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2017 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
2022 const auto *MMO = *
I.memoperands_begin();
2023 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
2026 .
addImm(OffsetBytes / IntSize)
2028 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2031 OffsetBytes += IntSize;
2035 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2038 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2042 I.eraseFromParent();
2046bool AArch64InstructionSelector::selectVaStartDarwin(
2047 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &
MRI)
const {
2048 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2049 Register ListReg =
I.getOperand(0).getReg();
2051 Register ArgsAddrReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2054 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2062 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2070 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2077 I.eraseFromParent();
2081void AArch64InstructionSelector::materializeLargeCMVal(
2082 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2087 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2098 :
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2102 GV, MovZ->getOperand(1).getOffset(), Flags));
2106 MovZ->getOperand(1).getOffset(), Flags));
2112 Register DstReg = BuildMovK(MovZ.getReg(0),
2118bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2123 switch (
I.getOpcode()) {
2124 case TargetOpcode::G_STORE: {
2125 bool Changed = contractCrossBankCopyIntoStore(
I,
MRI);
2126 MachineOperand &SrcOp =
I.getOperand(0);
2127 if (
MRI.getType(SrcOp.
getReg()).isPointer()) {
2139 case TargetOpcode::G_PTR_ADD: {
2143 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2145 return convertPtrAddToAdd(
I,
MRI);
2147 case TargetOpcode::G_LOAD: {
2152 Register DstReg =
I.getOperand(0).getReg();
2153 const LLT DstTy =
MRI.getType(DstReg);
2159 case AArch64::G_DUP: {
2161 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2165 MRI.setType(
I.getOperand(0).getReg(),
2167 MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2168 I.getOperand(1).setReg(NewSrc.getReg(0));
2171 case AArch64::G_INSERT_VECTOR_ELT: {
2173 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2174 LLT SrcVecTy =
MRI.getType(
I.getOperand(1).getReg());
2178 MRI.setType(
I.getOperand(1).getReg(),
2180 MRI.setType(
I.getOperand(0).getReg(),
2182 MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2183 I.getOperand(2).setReg(NewSrc.getReg(0));
2186 case TargetOpcode::G_UITOFP:
2187 case TargetOpcode::G_SITOFP: {
2192 Register SrcReg =
I.getOperand(1).getReg();
2193 LLT SrcTy =
MRI.getType(SrcReg);
2194 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2199 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2200 I.setDesc(
TII.get(AArch64::G_SITOF));
2202 I.setDesc(
TII.get(AArch64::G_UITOF));
2220bool AArch64InstructionSelector::convertPtrAddToAdd(
2221 MachineInstr &
I, MachineRegisterInfo &
MRI) {
2222 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2223 Register DstReg =
I.getOperand(0).getReg();
2224 Register AddOp1Reg =
I.getOperand(1).getReg();
2225 const LLT PtrTy =
MRI.getType(DstReg);
2229 const LLT CastPtrTy =
2234 MRI.setRegBank(PtrToInt.getReg(0), RBI.
getRegBank(AArch64::FPRRegBankID));
2236 MRI.setRegBank(PtrToInt.getReg(0), RBI.
getRegBank(AArch64::GPRRegBankID));
2240 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2241 MRI.setType(DstReg, CastPtrTy);
2242 I.getOperand(1).setReg(PtrToInt.getReg(0));
2243 if (!select(*PtrToInt)) {
2244 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2253 I.getOperand(2).setReg(NegatedReg);
2254 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2258bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2259 MachineRegisterInfo &
MRI) {
2263 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2264 const auto &MO =
I.getOperand(2);
2269 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2273 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2274 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2276 if (!Imm1Fn || !Imm2Fn)
2280 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2281 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2283 for (
auto &RenderFn : *Imm1Fn)
2285 for (
auto &RenderFn : *Imm2Fn)
2288 I.eraseFromParent();
2292bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2293 MachineInstr &
I, MachineRegisterInfo &
MRI) {
2294 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2312 LLT DefDstTy =
MRI.getType(DefDstReg);
2313 Register StoreSrcReg =
I.getOperand(0).getReg();
2314 LLT StoreSrcTy =
MRI.getType(StoreSrcReg);
2330 I.getOperand(0).setReg(DefDstReg);
2334bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2335 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2336 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2342 switch (
I.getOpcode()) {
2343 case AArch64::G_DUP: {
2346 Register Src =
I.getOperand(1).getReg();
2351 Register Dst =
I.getOperand(0).getReg();
2353 MRI.getType(Dst).getNumElements(),
2355 Type::getIntNTy(Ctx,
MRI.getType(Dst).getScalarSizeInBits()),
2356 ValAndVReg->Value.trunc(
MRI.getType(Dst).getScalarSizeInBits())));
2357 if (!emitConstantVector(Dst, CV, MIB,
MRI))
2359 I.eraseFromParent();
2362 case TargetOpcode::G_SEXT:
2365 if (selectUSMovFromExtend(
I,
MRI))
2368 case TargetOpcode::G_BR:
2370 case TargetOpcode::G_SHL:
2371 return earlySelectSHL(
I,
MRI);
2372 case TargetOpcode::G_CONSTANT: {
2373 bool IsZero =
false;
2374 if (
I.getOperand(1).isCImm())
2375 IsZero =
I.getOperand(1).getCImm()->isZero();
2376 else if (
I.getOperand(1).isImm())
2377 IsZero =
I.getOperand(1).getImm() == 0;
2382 Register DefReg =
I.getOperand(0).getReg();
2383 LLT Ty =
MRI.getType(DefReg);
2385 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2388 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2393 I.setDesc(
TII.get(TargetOpcode::COPY));
2397 case TargetOpcode::G_ADD: {
2406 Register AddDst =
I.getOperand(0).getReg();
2407 Register AddLHS =
I.getOperand(1).getReg();
2408 Register AddRHS =
I.getOperand(2).getReg();
2410 LLT Ty =
MRI.getType(AddLHS);
2418 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2419 if (!
MRI.hasOneNonDBGUse(
Reg))
2433 MRI.getType(
Cmp->getOperand(2).getReg()).getSizeInBits() != 64)
2439 MachineInstr *
Cmp = MatchCmp(AddRHS);
2443 Cmp = MatchCmp(AddRHS);
2447 auto &PredOp =
Cmp->getOperand(1);
2449 emitIntegerCompare(
Cmp->getOperand(2),
2450 Cmp->getOperand(3), PredOp, MIB);
2454 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2455 I.eraseFromParent();
2458 case TargetOpcode::G_OR: {
2462 Register Dst =
I.getOperand(0).getReg();
2463 LLT Ty =
MRI.getType(Dst);
2482 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2485 int64_t Immr =
Size - ShiftImm;
2486 int64_t Imms =
Size - ShiftImm - 1;
2487 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2488 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2489 I.eraseFromParent();
2492 case TargetOpcode::G_FENCE: {
2493 if (
I.getOperand(1).getImm() == 0)
2497 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2498 I.eraseFromParent();
2506bool AArch64InstructionSelector::select(MachineInstr &
I) {
2507 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2508 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2514 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2515 if (Subtarget->requiresStrictAlign()) {
2517 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2523 unsigned Opcode =
I.getOpcode();
2525 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2528 if (Opcode == TargetOpcode::LOAD_STACK_GUARD)
2531 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2532 const Register DefReg =
I.getOperand(0).getReg();
2533 const LLT DefTy =
MRI.getType(DefReg);
2536 MRI.getRegClassOrRegBank(DefReg);
2538 const TargetRegisterClass *DefRC =
2546 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2553 I.setDesc(
TII.get(TargetOpcode::PHI));
2561 if (
I.isDebugInstr())
2568 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2570 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2577 if (preISelLower(
I)) {
2578 Opcode =
I.getOpcode();
2589 if (selectImpl(
I, *CoverageInfo))
2593 I.getOperand(0).isReg() ?
MRI.getType(
I.getOperand(0).getReg()) : LLT{};
2596 case TargetOpcode::G_SBFX:
2597 case TargetOpcode::G_UBFX: {
2598 static const unsigned OpcTable[2][2] = {
2599 {AArch64::UBFMWri, AArch64::UBFMXri},
2600 {AArch64::SBFMWri, AArch64::SBFMXri}};
2601 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2603 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2606 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2609 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2610 auto LSB = Cst1->Value.getZExtValue();
2611 auto Width = Cst2->Value.getZExtValue();
2615 .
addImm(LSB + Width - 1);
2616 I.eraseFromParent();
2619 case TargetOpcode::G_BRCOND:
2620 return selectCompareBranch(
I, MF,
MRI);
2622 case TargetOpcode::G_BRINDIRECT: {
2624 if (std::optional<uint16_t> BADisc =
2626 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2629 MI.addReg(AArch64::XZR);
2630 I.eraseFromParent();
2633 I.setDesc(
TII.get(AArch64::BR));
2637 case TargetOpcode::G_BRJT:
2638 return selectBrJT(
I,
MRI);
2640 case AArch64::G_ADD_LOW: {
2645 MachineInstr *BaseMI =
MRI.getVRegDef(
I.getOperand(1).getReg());
2646 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2647 I.setDesc(
TII.get(AArch64::ADDXri));
2652 "Expected small code model");
2654 auto Op2 =
I.getOperand(2);
2655 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2656 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2657 Op1.getTargetFlags())
2659 Op2.getTargetFlags());
2660 I.eraseFromParent();
2664 case TargetOpcode::G_FCONSTANT:
2665 case TargetOpcode::G_CONSTANT: {
2666 const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
2675 const Register DefReg =
I.getOperand(0).getReg();
2676 const LLT DefTy =
MRI.getType(DefReg);
2682 if (Ty != s16 && Ty != s32 && Ty != s64 && Ty != s128) {
2684 <<
" constant, expected: " << s16 <<
" or " << s32
2685 <<
" or " << s64 <<
" or " << s128 <<
'\n');
2689 if (RB.
getID() != AArch64::FPRRegBankID) {
2691 <<
" constant on bank: " << RB
2692 <<
", expected: FPR\n");
2700 if (DefSize != 128 &&
I.getOperand(1).getFPImm()->isExactlyValue(0.0))
2704 if (Ty != p0 && Ty != s8 && Ty != s16) {
2706 <<
" constant, expected: " << s32 <<
", " << s64
2707 <<
", or " << p0 <<
'\n');
2711 if (RB.
getID() != AArch64::GPRRegBankID) {
2713 <<
" constant on bank: " << RB
2714 <<
", expected: GPR\n");
2720 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2727 bool OptForSize = shouldOptForSize(&MF);
2731 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2738 auto *FPImm =
I.getOperand(1).getFPImm();
2741 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2744 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2745 I.eraseFromParent();
2750 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2752 const Register DefGPRReg =
MRI.createVirtualRegister(
2753 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2754 MachineOperand &RegOp =
I.getOperand(0);
2760 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2764 MachineOperand &ImmOp =
I.getOperand(1);
2768 }
else if (
I.getOperand(1).isCImm()) {
2769 uint64_t Val =
I.getOperand(1).getCImm()->getZExtValue();
2770 I.getOperand(1).ChangeToImmediate(Val);
2771 }
else if (
I.getOperand(1).isImm()) {
2772 uint64_t Val =
I.getOperand(1).getImm();
2773 I.getOperand(1).ChangeToImmediate(Val);
2776 const unsigned MovOpc =
2777 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2778 I.setDesc(
TII.get(MovOpc));
2782 case TargetOpcode::G_EXTRACT: {
2783 Register DstReg =
I.getOperand(0).getReg();
2784 Register SrcReg =
I.getOperand(1).getReg();
2785 LLT SrcTy =
MRI.getType(SrcReg);
2786 LLT DstTy =
MRI.getType(DstReg);
2798 unsigned Offset =
I.getOperand(2).getImm();
2807 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2809 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2811 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2813 AArch64::GPR64RegClass, NewI->getOperand(0));
2814 I.eraseFromParent();
2820 unsigned LaneIdx =
Offset / 64;
2821 MachineInstr *Extract = emitExtractVectorElt(
2822 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2825 I.eraseFromParent();
2829 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2830 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2835 "unexpected G_EXTRACT types");
2841 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2842 .addReg(DstReg, 0, AArch64::sub_32);
2844 AArch64::GPR32RegClass,
MRI);
2845 I.getOperand(0).setReg(DstReg);
2850 case TargetOpcode::G_INSERT: {
2851 LLT SrcTy =
MRI.getType(
I.getOperand(2).getReg());
2852 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2859 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2860 unsigned LSB =
I.getOperand(3).getImm();
2861 unsigned Width =
MRI.getType(
I.getOperand(2).getReg()).getSizeInBits();
2862 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2863 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2867 "unexpected G_INSERT types");
2873 TII.get(AArch64::SUBREG_TO_REG))
2876 .
addUse(
I.getOperand(2).getReg())
2877 .
addImm(AArch64::sub_32);
2879 AArch64::GPR32RegClass,
MRI);
2880 I.getOperand(2).setReg(SrcReg);
2884 case TargetOpcode::G_FRAME_INDEX: {
2891 I.setDesc(
TII.get(AArch64::ADDXri));
2900 case TargetOpcode::G_GLOBAL_VALUE: {
2901 const GlobalValue *GV =
nullptr;
2903 if (
I.getOperand(1).isSymbol()) {
2904 OpFlags =
I.getOperand(1).getTargetFlags();
2913 return selectTLSGlobalValue(
I,
MRI);
2919 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2920 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2921 I.getOperand(1).setTargetFlags(OpFlags);
2922 I.addImplicitDefUseOperands(MF);
2926 materializeLargeCMVal(
I, GV, OpFlags);
2927 I.eraseFromParent();
2930 I.setDesc(
TII.get(AArch64::ADR));
2931 I.getOperand(1).setTargetFlags(OpFlags);
2933 I.setDesc(
TII.get(AArch64::MOVaddr));
2935 MachineInstrBuilder MIB(MF,
I);
2936 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2942 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2943 return selectPtrAuthGlobalValue(
I,
MRI);
2945 case TargetOpcode::G_ZEXTLOAD:
2946 case TargetOpcode::G_LOAD:
2947 case TargetOpcode::G_STORE: {
2949 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2964 assert(MemSizeInBytes <= 8 &&
2965 "128-bit atomics should already be custom-legalized");
2968 static constexpr unsigned LDAPROpcodes[] = {
2969 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2970 static constexpr unsigned LDAROpcodes[] = {
2971 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2972 ArrayRef<unsigned> Opcodes =
2973 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2976 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2978 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2979 AArch64::STLRW, AArch64::STLRX};
2981 if (
MRI.getType(ValReg).getSizeInBits() == 64 && MemSizeInBits != 64) {
2983 Register NewVal =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2984 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2985 .addReg(
I.getOperand(0).getReg(), 0, AArch64::sub_32);
2986 I.getOperand(0).setReg(NewVal);
2988 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2999 "Load/Store pointer operand isn't a GPR");
3000 assert(
MRI.getType(PtrReg).isPointer() &&
3001 "Load/Store pointer operand isn't a pointer");
3006 LLT ValTy =
MRI.getType(ValReg);
3013 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3019 .addReg(ValReg, 0,
SubReg)
3026 if (RB.
getID() == AArch64::FPRRegBankID) {
3029 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3036 MRI.setRegBank(NewDst, RB);
3039 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3043 auto SubRegRC = getRegClassForTypeOnBank(
MRI.getType(OldDst), RB);
3052 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3054 const unsigned NewOpc =
3056 if (NewOpc ==
I.getOpcode())
3060 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3063 I.setDesc(
TII.get(NewOpc));
3069 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3070 Register CurValReg =
I.getOperand(0).getReg();
3071 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3072 NewInst.cloneMemRefs(
I);
3073 for (
auto &Fn : *AddrModeFns)
3075 I.eraseFromParent();
3079 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3084 if (Opcode == TargetOpcode::G_STORE) {
3087 if (CVal && CVal->Value == 0) {
3089 case AArch64::STRWui:
3090 case AArch64::STRHHui:
3091 case AArch64::STRBBui:
3092 LoadStore->getOperand(0).setReg(AArch64::WZR);
3094 case AArch64::STRXui:
3095 LoadStore->getOperand(0).setReg(AArch64::XZR);
3101 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3102 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3105 if (
MRI.getType(
LoadStore->getOperand(0).getReg()).getSizeInBits() != 64)
3109 Register LdReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3114 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3117 .
addImm(AArch64::sub_32);
3125 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3126 case TargetOpcode::G_INDEXED_SEXTLOAD:
3127 return selectIndexedExtLoad(
I,
MRI);
3128 case TargetOpcode::G_INDEXED_LOAD:
3129 return selectIndexedLoad(
I,
MRI);
3130 case TargetOpcode::G_INDEXED_STORE:
3133 case TargetOpcode::G_LSHR:
3134 case TargetOpcode::G_ASHR:
3135 if (
MRI.getType(
I.getOperand(0).getReg()).isVector())
3136 return selectVectorAshrLshr(
I,
MRI);
3138 case TargetOpcode::G_SHL:
3139 if (Opcode == TargetOpcode::G_SHL &&
3140 MRI.getType(
I.getOperand(0).getReg()).isVector())
3141 return selectVectorSHL(
I,
MRI);
3148 Register SrcReg =
I.getOperand(1).getReg();
3149 Register ShiftReg =
I.getOperand(2).getReg();
3150 const LLT ShiftTy =
MRI.getType(ShiftReg);
3151 const LLT SrcTy =
MRI.getType(SrcReg);
3156 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3157 .addReg(ShiftReg, 0, AArch64::sub_32);
3158 MRI.setRegBank(Trunc.getReg(0), RBI.
getRegBank(AArch64::GPRRegBankID));
3159 I.getOperand(2).setReg(Trunc.getReg(0));
3163 case TargetOpcode::G_OR: {
3170 const Register DefReg =
I.getOperand(0).getReg();
3174 if (NewOpc ==
I.getOpcode())
3177 I.setDesc(
TII.get(NewOpc));
3185 case TargetOpcode::G_PTR_ADD: {
3186 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3187 I.eraseFromParent();
3191 case TargetOpcode::G_SADDE:
3192 case TargetOpcode::G_UADDE:
3193 case TargetOpcode::G_SSUBE:
3194 case TargetOpcode::G_USUBE:
3195 case TargetOpcode::G_SADDO:
3196 case TargetOpcode::G_UADDO:
3197 case TargetOpcode::G_SSUBO:
3198 case TargetOpcode::G_USUBO:
3199 return selectOverflowOp(
I,
MRI);
3201 case TargetOpcode::G_PTRMASK: {
3202 Register MaskReg =
I.getOperand(2).getReg();
3208 uint64_t
Mask = *MaskVal;
3209 I.setDesc(
TII.get(AArch64::ANDXri));
3210 I.getOperand(2).ChangeToImmediate(
3215 case TargetOpcode::G_PTRTOINT:
3216 case TargetOpcode::G_TRUNC: {
3217 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3218 const LLT SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3220 const Register DstReg =
I.getOperand(0).getReg();
3221 const Register SrcReg =
I.getOperand(1).getReg();
3228 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3232 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3233 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3237 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3243 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3247 if (DstRC == SrcRC) {
3249 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3253 }
else if (DstRC == &AArch64::GPR32RegClass &&
3254 SrcRC == &AArch64::GPR64RegClass) {
3255 I.getOperand(1).setSubReg(AArch64::sub_32);
3258 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3262 I.setDesc(
TII.get(TargetOpcode::COPY));
3264 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3267 I.setDesc(
TII.get(AArch64::XTNv4i16));
3273 MachineInstr *Extract = emitExtractVectorElt(
3277 I.eraseFromParent();
3282 if (Opcode == TargetOpcode::G_PTRTOINT) {
3283 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3284 I.setDesc(
TII.get(TargetOpcode::COPY));
3292 case TargetOpcode::G_ANYEXT: {
3293 if (selectUSMovFromExtend(
I,
MRI))
3296 const Register DstReg =
I.getOperand(0).getReg();
3297 const Register SrcReg =
I.getOperand(1).getReg();
3300 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3302 <<
", expected: GPR\n");
3307 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3309 <<
", expected: GPR\n");
3313 const unsigned DstSize =
MRI.getType(DstReg).getSizeInBits();
3316 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3320 if (DstSize != 64 && DstSize > 32) {
3322 <<
", expected: 32 or 64\n");
3328 Register ExtSrc =
MRI.createVirtualRegister(&AArch64::GPR64allRegClass);
3333 .
addImm(AArch64::sub_32);
3334 I.getOperand(1).setReg(ExtSrc);
3339 case TargetOpcode::G_ZEXT:
3340 case TargetOpcode::G_SEXT_INREG:
3341 case TargetOpcode::G_SEXT: {
3342 if (selectUSMovFromExtend(
I,
MRI))
3345 unsigned Opcode =
I.getOpcode();
3346 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3347 const Register DefReg =
I.getOperand(0).getReg();
3348 Register SrcReg =
I.getOperand(1).getReg();
3349 const LLT DstTy =
MRI.getType(DefReg);
3350 const LLT SrcTy =
MRI.getType(SrcReg);
3356 if (Opcode == TargetOpcode::G_SEXT_INREG)
3357 SrcSize =
I.getOperand(2).getImm();
3363 AArch64::GPRRegBankID &&
3364 "Unexpected ext regbank");
3378 if (LoadMI && IsGPR) {
3379 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3380 unsigned BytesLoaded = MemOp->getSize().getValue();
3387 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3389 MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3390 const Register ZReg = AArch64::WZR;
3391 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3394 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3397 .
addImm(AArch64::sub_32);
3401 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3411 I.eraseFromParent();
3416 if (DstSize == 64) {
3417 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3425 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3426 {&AArch64::GPR64RegClass}, {})
3433 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3437 }
else if (DstSize <= 32) {
3438 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3447 I.eraseFromParent();
3451 case TargetOpcode::G_FREEZE:
3454 case TargetOpcode::G_INTTOPTR:
3459 case TargetOpcode::G_BITCAST:
3467 case TargetOpcode::G_SELECT: {
3469 const Register CondReg = Sel.getCondReg();
3471 const Register FReg = Sel.getFalseReg();
3473 if (tryOptSelect(Sel))
3478 Register DeadVReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3479 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3482 if (!emitSelect(Sel.getReg(0), TReg, FReg,
AArch64CC::NE, MIB))
3484 Sel.eraseFromParent();
3487 case TargetOpcode::G_ICMP: {
3497 auto &PredOp =
I.getOperand(1);
3498 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3502 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3503 AArch64::WZR, InvCC, MIB);
3504 I.eraseFromParent();
3508 case TargetOpcode::G_FCMP: {
3511 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3513 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3515 I.eraseFromParent();
3518 case TargetOpcode::G_VASTART:
3520 : selectVaStartAAPCS(
I, MF,
MRI);
3521 case TargetOpcode::G_INTRINSIC:
3522 return selectIntrinsic(
I,
MRI);
3523 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3524 return selectIntrinsicWithSideEffects(
I,
MRI);
3525 case TargetOpcode::G_IMPLICIT_DEF: {
3526 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3527 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3528 const Register DstReg =
I.getOperand(0).getReg();
3530 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3534 case TargetOpcode::G_BLOCK_ADDR: {
3535 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3536 if (std::optional<uint16_t> BADisc =
3538 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3539 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3548 AArch64::GPR64RegClass,
MRI);
3549 I.eraseFromParent();
3553 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3554 I.eraseFromParent();
3557 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3558 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3559 I.getOperand(0).getReg())
3563 I.getOperand(1).getBlockAddress(), 0,
3565 I.eraseFromParent();
3569 case AArch64::G_DUP: {
3576 AArch64::GPRRegBankID)
3578 LLT VecTy =
MRI.getType(
I.getOperand(0).getReg());
3580 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3582 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3584 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3586 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3591 case TargetOpcode::G_BUILD_VECTOR:
3592 return selectBuildVector(
I,
MRI);
3593 case TargetOpcode::G_MERGE_VALUES:
3595 case TargetOpcode::G_UNMERGE_VALUES:
3597 case TargetOpcode::G_SHUFFLE_VECTOR:
3598 return selectShuffleVector(
I,
MRI);
3599 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3600 return selectExtractElt(
I,
MRI);
3601 case TargetOpcode::G_CONCAT_VECTORS:
3602 return selectConcatVectors(
I,
MRI);
3603 case TargetOpcode::G_JUMP_TABLE:
3604 return selectJumpTable(
I,
MRI);
3605 case TargetOpcode::G_MEMCPY:
3606 case TargetOpcode::G_MEMCPY_INLINE:
3607 case TargetOpcode::G_MEMMOVE:
3608 case TargetOpcode::G_MEMSET:
3609 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3610 return selectMOPS(
I,
MRI);
3616bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3617 MachineIRBuilderState OldMIBState = MIB.
getState();
3623bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3624 MachineRegisterInfo &
MRI) {
3627 case TargetOpcode::G_MEMCPY:
3628 case TargetOpcode::G_MEMCPY_INLINE:
3629 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3631 case TargetOpcode::G_MEMMOVE:
3632 Mopcode = AArch64::MOPSMemoryMovePseudo;
3634 case TargetOpcode::G_MEMSET:
3636 Mopcode = AArch64::MOPSMemorySetPseudo;
3645 const Register DstPtrCopy =
MRI.cloneVirtualRegister(DstPtr.getReg());
3646 const Register SrcValCopy =
MRI.cloneVirtualRegister(SrcOrVal.getReg());
3649 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3650 const auto &SrcValRegClass =
3651 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3666 Register DefDstPtr =
MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
3667 Register DefSize =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3669 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3670 {DstPtrCopy, SizeCopy, SrcValCopy});
3672 Register DefSrcPtr =
MRI.createVirtualRegister(&SrcValRegClass);
3673 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3674 {DstPtrCopy, SrcValCopy, SizeCopy});
3681bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3682 MachineRegisterInfo &
MRI) {
3683 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3684 Register JTAddr =
I.getOperand(0).getReg();
3685 unsigned JTI =
I.getOperand(1).getIndex();
3688 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3700 "jump table hardening only supported on MachO/ELF");
3708 I.eraseFromParent();
3712 Register TargetReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3713 Register ScratchReg =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
3715 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3716 {TargetReg, ScratchReg}, {JTAddr,
Index})
3717 .addJumpTableIndex(JTI);
3719 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3720 {
static_cast<int64_t
>(JTI)});
3722 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3723 I.eraseFromParent();
3727bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3728 MachineRegisterInfo &
MRI) {
3729 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3730 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3732 Register DstReg =
I.getOperand(0).getReg();
3733 unsigned JTI =
I.getOperand(1).getIndex();
3736 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3739 I.eraseFromParent();
3743bool AArch64InstructionSelector::selectTLSGlobalValue(
3744 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3747 MachineFunction &MF = *
I.getParent()->getParent();
3750 const auto &GlobalOp =
I.getOperand(1);
3751 assert(GlobalOp.getOffset() == 0 &&
3752 "Shouldn't have an offset on TLS globals!");
3753 const GlobalValue &GV = *GlobalOp.getGlobal();
3756 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3759 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3760 {LoadGOT.getReg(0)})
3771 assert(Opcode == AArch64::BLR);
3772 Opcode = AArch64::BLRAAZ;
3783 I.eraseFromParent();
3787MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3788 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3789 MachineIRBuilder &MIRBuilder)
const {
3790 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3792 auto BuildFn = [&](
unsigned SubregIndex) {
3796 .addImm(SubregIndex);
3804 return BuildFn(AArch64::bsub);
3806 return BuildFn(AArch64::hsub);
3808 return BuildFn(AArch64::ssub);
3810 return BuildFn(AArch64::dsub);
3817AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3818 MachineIRBuilder &MIB,
3819 MachineRegisterInfo &
MRI)
const {
3820 LLT DstTy =
MRI.getType(DstReg);
3821 const TargetRegisterClass *RC =
3823 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3830 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
3836 .addReg(SrcReg, 0,
SubReg);
3841bool AArch64InstructionSelector::selectMergeValues(
3842 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3843 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3844 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3845 const LLT SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3849 if (
I.getNumOperands() != 3)
3856 Register DstReg =
I.getOperand(0).getReg();
3857 Register Src1Reg =
I.getOperand(1).getReg();
3858 Register Src2Reg =
I.getOperand(2).getReg();
3859 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3860 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3864 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3865 Src2Reg, 1, RB, MIB);
3870 I.eraseFromParent();
3874 if (RB.
getID() != AArch64::GPRRegBankID)
3880 auto *DstRC = &AArch64::GPR64RegClass;
3881 Register SubToRegDef =
MRI.createVirtualRegister(DstRC);
3882 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3883 TII.get(TargetOpcode::SUBREG_TO_REG))
3886 .
addUse(
I.getOperand(1).getReg())
3887 .
addImm(AArch64::sub_32);
3888 Register SubToRegDef2 =
MRI.createVirtualRegister(DstRC);
3890 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3891 TII.get(TargetOpcode::SUBREG_TO_REG))
3894 .
addUse(
I.getOperand(2).getReg())
3895 .
addImm(AArch64::sub_32);
3897 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3898 .
addDef(
I.getOperand(0).getReg())
3906 I.eraseFromParent();
3911 const unsigned EltSize) {
3916 CopyOpc = AArch64::DUPi8;
3917 ExtractSubReg = AArch64::bsub;
3920 CopyOpc = AArch64::DUPi16;
3921 ExtractSubReg = AArch64::hsub;
3924 CopyOpc = AArch64::DUPi32;
3925 ExtractSubReg = AArch64::ssub;
3928 CopyOpc = AArch64::DUPi64;
3929 ExtractSubReg = AArch64::dsub;
3933 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3939MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3940 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3941 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3942 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
3943 unsigned CopyOpc = 0;
3944 unsigned ExtractSubReg = 0;
3947 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3951 const TargetRegisterClass *DstRC =
3952 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3954 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3959 const LLT &VecTy =
MRI.getType(VecReg);
3960 const TargetRegisterClass *VecRC =
3961 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3963 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3970 DstReg =
MRI.createVirtualRegister(DstRC);
3973 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3974 .addReg(VecReg, 0, ExtractSubReg);
3983 MachineInstr *ScalarToVector = emitScalarToVector(
3984 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3985 if (!ScalarToVector)
3990 MachineInstr *LaneCopyMI =
3991 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3999bool AArch64InstructionSelector::selectExtractElt(
4000 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4001 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4002 "unexpected opcode!");
4003 Register DstReg =
I.getOperand(0).getReg();
4004 const LLT NarrowTy =
MRI.getType(DstReg);
4005 const Register SrcReg =
I.getOperand(1).getReg();
4006 const LLT WideTy =
MRI.getType(SrcReg);
4009 "source register size too small!");
4010 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4013 MachineOperand &LaneIdxOp =
I.getOperand(2);
4014 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4025 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4029 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4034 I.eraseFromParent();
4038bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4039 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4040 unsigned NumElts =
I.getNumOperands() - 1;
4041 Register SrcReg =
I.getOperand(NumElts).getReg();
4042 const LLT NarrowTy =
MRI.getType(
I.getOperand(0).getReg());
4043 const LLT SrcTy =
MRI.getType(SrcReg);
4045 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4047 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4053 const RegisterBank &DstRB =
4057 MachineInstr *Extract =
4058 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4062 I.eraseFromParent();
4066bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4067 MachineRegisterInfo &
MRI) {
4068 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4069 "unexpected opcode");
4073 AArch64::FPRRegBankID ||
4075 AArch64::FPRRegBankID) {
4076 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4077 "currently unsupported.\n");
4083 unsigned NumElts =
I.getNumOperands() - 1;
4084 Register SrcReg =
I.getOperand(NumElts).getReg();
4085 const LLT NarrowTy =
MRI.getType(
I.getOperand(0).getReg());
4086 const LLT WideTy =
MRI.getType(SrcReg);
4089 "source register size too small!");
4092 return selectSplitVectorUnmerge(
I,
MRI);
4096 unsigned CopyOpc = 0;
4097 unsigned ExtractSubReg = 0;
4108 unsigned NumInsertRegs = NumElts - 1;
4121 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4126 assert(Found &&
"expected to find last operand's subeg idx");
4127 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4128 Register ImpDefReg =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
4129 MachineInstr &ImpDefMI =
4130 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4134 Register InsertReg =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
4135 MachineInstr &InsMI =
4137 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4154 Register CopyTo =
I.getOperand(0).getReg();
4155 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4156 .addReg(InsertRegs[0], 0, ExtractSubReg);
4160 unsigned LaneIdx = 1;
4161 for (
Register InsReg : InsertRegs) {
4162 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4163 MachineInstr &CopyInst =
4174 const TargetRegisterClass *RC =
4175 MRI.getRegClassOrNull(
I.getOperand(1).getReg());
4182 I.eraseFromParent();
4186bool AArch64InstructionSelector::selectConcatVectors(
4187 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4188 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4189 "Unexpected opcode");
4190 Register Dst =
I.getOperand(0).getReg();
4191 Register Op1 =
I.getOperand(1).getReg();
4192 Register Op2 =
I.getOperand(2).getReg();
4193 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4196 I.eraseFromParent();
4201AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4202 MachineFunction &MF)
const {
4210MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4211 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4212 const TargetRegisterClass *RC;
4218 RC = &AArch64::FPR128RegClass;
4219 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4222 RC = &AArch64::FPR64RegClass;
4223 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4226 RC = &AArch64::FPR32RegClass;
4227 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4230 RC = &AArch64::FPR16RegClass;
4231 Opc = AArch64::LDRHui;
4234 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4239 MachineInstr *LoadMI =
nullptr;
4240 auto &MF = MIRBuilder.
getMF();
4241 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4242 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4244 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4247 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4251 .addConstantPoolIndex(
4267static std::pair<unsigned, unsigned>
4269 unsigned Opc, SubregIdx;
4270 if (RB.
getID() == AArch64::GPRRegBankID) {
4272 Opc = AArch64::INSvi8gpr;
4273 SubregIdx = AArch64::bsub;
4274 }
else if (EltSize == 16) {
4275 Opc = AArch64::INSvi16gpr;
4276 SubregIdx = AArch64::ssub;
4277 }
else if (EltSize == 32) {
4278 Opc = AArch64::INSvi32gpr;
4279 SubregIdx = AArch64::ssub;
4280 }
else if (EltSize == 64) {
4281 Opc = AArch64::INSvi64gpr;
4282 SubregIdx = AArch64::dsub;
4288 Opc = AArch64::INSvi8lane;
4289 SubregIdx = AArch64::bsub;
4290 }
else if (EltSize == 16) {
4291 Opc = AArch64::INSvi16lane;
4292 SubregIdx = AArch64::hsub;
4293 }
else if (EltSize == 32) {
4294 Opc = AArch64::INSvi32lane;
4295 SubregIdx = AArch64::ssub;
4296 }
else if (EltSize == 64) {
4297 Opc = AArch64::INSvi64lane;
4298 SubregIdx = AArch64::dsub;
4303 return std::make_pair(
Opc, SubregIdx);
4306MachineInstr *AArch64InstructionSelector::emitInstr(
4307 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4308 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4309 const ComplexRendererFns &RenderFns)
const {
4310 assert(Opcode &&
"Expected an opcode?");
4312 "Function should only be used to produce selected instructions!");
4313 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4315 for (
auto &Fn : *RenderFns)
4321MachineInstr *AArch64InstructionSelector::emitAddSub(
4322 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4324 MachineIRBuilder &MIRBuilder)
const {
4326 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4327 auto Ty =
MRI.getType(
LHS.getReg());
4330 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4331 bool Is32Bit =
Size == 32;
4334 if (
auto Fns = selectArithImmed(
RHS))
4335 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4339 if (
auto Fns = selectNegArithImmed(
RHS))
4340 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4344 if (
auto Fns = selectArithExtendedRegister(
RHS))
4345 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4349 if (
auto Fns = selectShiftedRegister(
RHS))
4350 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4352 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4357AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4358 MachineOperand &
RHS,
4359 MachineIRBuilder &MIRBuilder)
const {
4360 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4361 {{AArch64::ADDXri, AArch64::ADDWri},
4362 {AArch64::ADDXrs, AArch64::ADDWrs},
4363 {AArch64::ADDXrr, AArch64::ADDWrr},
4364 {AArch64::SUBXri, AArch64::SUBWri},
4365 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4366 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4370AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4371 MachineOperand &
RHS,
4372 MachineIRBuilder &MIRBuilder)
const {
4373 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4374 {{AArch64::ADDSXri, AArch64::ADDSWri},
4375 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4376 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4377 {AArch64::SUBSXri, AArch64::SUBSWri},
4378 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4379 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4383AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4384 MachineOperand &
RHS,
4385 MachineIRBuilder &MIRBuilder)
const {
4386 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4387 {{AArch64::SUBSXri, AArch64::SUBSWri},
4388 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4389 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4390 {AArch64::ADDSXri, AArch64::ADDSWri},
4391 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4392 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4396AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4397 MachineOperand &
RHS,
4398 MachineIRBuilder &MIRBuilder)
const {
4399 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4400 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4401 bool Is32Bit = (
MRI->getType(
LHS.getReg()).getSizeInBits() == 32);
4402 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4403 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4407AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4408 MachineOperand &
RHS,
4409 MachineIRBuilder &MIRBuilder)
const {
4410 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4411 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4412 bool Is32Bit = (
MRI->getType(
LHS.getReg()).getSizeInBits() == 32);
4413 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4414 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4418AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4419 MachineIRBuilder &MIRBuilder)
const {
4421 bool Is32Bit =
MRI.getType(
LHS.getReg()).getSizeInBits() == 32;
4422 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4423 return emitSUBS(
MRI.createVirtualRegister(RC),
LHS,
RHS, MIRBuilder);
4427AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4428 MachineIRBuilder &MIRBuilder)
const {
4430 bool Is32Bit = (
MRI.getType(
LHS.getReg()).getSizeInBits() == 32);
4431 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4432 return emitADDS(
MRI.createVirtualRegister(RC),
LHS,
RHS, MIRBuilder);
4436AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4437 MachineIRBuilder &MIRBuilder)
const {
4438 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4440 LLT Ty =
MRI.getType(
LHS.getReg());
4442 bool Is32Bit = (
RegSize == 32);
4443 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4444 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4445 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4449 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4452 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4459 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4460 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4461 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4464MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4465 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4466 MachineIRBuilder &MIRBuilder)
const {
4467 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4470 LLT CmpTy =
MRI.getType(
LHS.getReg());
4474 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4476 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4478 return emitCMP(
LHS,
RHS, MIRBuilder);
4481MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4483 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4485 LLT Ty =
MRI.getType(Dst);
4487 "Expected a 32-bit scalar register?");
4489 const Register ZReg = AArch64::WZR;
4494 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4496 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4500 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4501 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4502 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4507MachineInstr *AArch64InstructionSelector::emitFPCompare(
4509 std::optional<CmpInst::Predicate> Pred)
const {
4510 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4511 LLT Ty =
MRI.getType(
LHS);
4515 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4526 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4530 ShouldUseImm =
true;
4534 unsigned CmpOpcTbl[2][3] = {
4535 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4536 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4538 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4550MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4552 MachineIRBuilder &MIRBuilder)
const {
4559 const LLT Op1Ty =
MRI.getType(Op1);
4560 const LLT Op2Ty =
MRI.getType(Op2);
4562 if (Op1Ty != Op2Ty) {
4563 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4566 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4569 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4581 const TargetRegisterClass *DstRC =
4584 MachineInstr *WidenedOp1 =
4585 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4586 MachineInstr *WidenedOp2 =
4587 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4588 if (!WidenedOp1 || !WidenedOp2) {
4589 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4594 unsigned InsertOpc, InsSubRegIdx;
4595 std::tie(InsertOpc, InsSubRegIdx) =
4599 Dst =
MRI.createVirtualRegister(DstRC);
4613 MachineIRBuilder &MIRBuilder)
const {
4620 Size =
TRI.getRegSizeInBits(*RC);
4622 Size =
MRI.getType(Dst).getSizeInBits();
4624 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4625 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4626 unsigned Opc = OpcTable[
Size == 64];
4627 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4632MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4634 MachineRegisterInfo *
MRI = MIB.
getMRI();
4635 unsigned Opcode =
I.getOpcode();
4639 bool NeedsNegatedCarry =
4640 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4649 MachineInstr *SrcMI =
MRI->getVRegDef(CarryReg);
4650 if (SrcMI ==
I.getPrevNode()) {
4652 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4653 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4654 CarrySrcMI->isUnsigned() &&
4655 CarrySrcMI->getCarryOutReg() == CarryReg &&
4656 selectAndRestoreState(*SrcMI))
4661 Register DeadReg =
MRI->createVirtualRegister(&AArch64::GPR32RegClass);
4663 if (NeedsNegatedCarry) {
4666 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4670 auto Fns = select12BitValueWithLeftShift(1);
4671 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4674bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4675 MachineRegisterInfo &
MRI) {
4680 emitCarryIn(
I, CarryInMI->getCarryInReg());
4684 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4685 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4687 Register CarryOutReg = CarryMI.getCarryOutReg();
4690 if (!
MRI.use_nodbg_empty(CarryOutReg)) {
4696 emitCSINC(CarryOutReg, ZReg, ZReg,
4697 getInvertedCondCode(OpAndCC.second), MIB);
4700 I.eraseFromParent();
4704std::pair<MachineInstr *, AArch64CC::CondCode>
4705AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4706 MachineOperand &
LHS,
4707 MachineOperand &
RHS,
4708 MachineIRBuilder &MIRBuilder)
const {
4712 case TargetOpcode::G_SADDO:
4714 case TargetOpcode::G_UADDO:
4716 case TargetOpcode::G_SSUBO:
4718 case TargetOpcode::G_USUBO:
4720 case TargetOpcode::G_SADDE:
4722 case TargetOpcode::G_UADDE:
4724 case TargetOpcode::G_SSUBE:
4726 case TargetOpcode::G_USUBE:
4747 unsigned Depth = 0) {
4748 if (!
MRI.hasOneNonDBGUse(Val))
4754 MustBeFirst =
false;
4760 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4761 bool IsOR = Opcode == TargetOpcode::G_OR;
4773 if (MustBeFirstL && MustBeFirstR)
4779 if (!CanNegateL && !CanNegateR)
4783 CanNegate = WillNegate && CanNegateL && CanNegateR;
4786 MustBeFirst = !CanNegate;
4788 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4791 MustBeFirst = MustBeFirstL || MustBeFirstR;
4798MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4801 MachineIRBuilder &MIB)
const {
4803 LLT OpTy =
MRI.getType(
LHS);
4805 std::optional<ValueAndVReg>
C;
4809 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4810 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4811 else if (
C->Value.ule(31))
4812 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4814 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4820 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4821 CCmpOpc = AArch64::FCCMPHrr;
4824 CCmpOpc = AArch64::FCCMPSrr;
4827 CCmpOpc = AArch64::FCCMPDrr;
4837 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4838 CCmp.
addImm(
C->Value.getZExtValue());
4839 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4840 CCmp.
addImm(
C->Value.abs().getZExtValue());
4848MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4853 MachineInstr *ValDef =
MRI.getVRegDef(Val);
4870 MachineInstr *ExtraCmp;
4872 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4884 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4885 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4886 Cmp->getOperand(3).getReg(), MIB);
4891 assert(
MRI.hasOneNonDBGUse(Val) &&
"Valid conjunction/disjunction tree");
4893 bool IsOR = Opcode == TargetOpcode::G_OR;
4899 assert(ValidL &&
"Valid conjunction/disjunction tree");
4906 assert(ValidR &&
"Valid conjunction/disjunction tree");
4911 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4920 bool NegateAfterAll;
4921 if (Opcode == TargetOpcode::G_OR) {
4924 assert(CanNegateR &&
"at least one side must be negatable");
4925 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4929 NegateAfterR =
true;
4932 NegateR = CanNegateR;
4933 NegateAfterR = !CanNegateR;
4936 NegateAfterAll = !Negate;
4938 assert(Opcode == TargetOpcode::G_AND &&
4939 "Valid conjunction/disjunction tree");
4940 assert(!Negate &&
"Valid conjunction/disjunction tree");
4944 NegateAfterR =
false;
4945 NegateAfterAll =
false;
4950 MachineInstr *CmpR =
4961MachineInstr *AArch64InstructionSelector::emitConjunction(
4963 bool DummyCanNegate;
4964 bool DummyMustBeFirst;
4971bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4972 MachineInstr &CondMI) {
4983bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4984 MachineRegisterInfo &
MRI = *MIB.
getMRI();
5003 MachineInstr *CondDef =
MRI.getVRegDef(
I.getOperand(1).getReg());
5007 if (!
MRI.hasOneNonDBGUse(CondDefReg)) {
5009 for (
const MachineInstr &UI :
MRI.use_nodbg_instructions(CondDefReg)) {
5012 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5018 unsigned CondOpc = CondDef->
getOpcode();
5019 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5020 if (tryOptSelectConjunction(
I, *CondDef))
5026 if (CondOpc == TargetOpcode::G_ICMP) {
5055 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5056 I.getOperand(3).getReg(), CondCode, MIB);
5057 I.eraseFromParent();
5061MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5062 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5063 MachineIRBuilder &MIRBuilder)
const {
5065 "Unexpected MachineOperand");
5066 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5121 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5124 if (!ValAndVReg || ValAndVReg->Value != 0)
5134bool AArch64InstructionSelector::selectShuffleVector(
5135 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5136 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5137 Register Src1Reg =
I.getOperand(1).getReg();
5138 Register Src2Reg =
I.getOperand(2).getReg();
5139 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5148 for (
int Val : Mask) {
5151 Val = Val < 0 ? 0 : Val;
5152 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5170 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5177 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5181 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5186 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5187 .addReg(TBL1.getReg(0), 0, AArch64::dsub);
5189 I.eraseFromParent();
5197 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5200 I.eraseFromParent();
5204MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5206 unsigned LaneIdx,
const RegisterBank &RB,
5207 MachineIRBuilder &MIRBuilder)
const {
5208 MachineInstr *InsElt =
nullptr;
5209 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5210 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5214 DstReg =
MRI.createVirtualRegister(DstRC);
5216 unsigned EltSize =
MRI.getType(EltReg).getSizeInBits();
5219 if (RB.
getID() == AArch64::FPRRegBankID) {
5220 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5223 .
addUse(InsSub->getOperand(0).getReg())
5235bool AArch64InstructionSelector::selectUSMovFromExtend(
5236 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5237 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5238 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5239 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5241 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5242 const Register DefReg =
MI.getOperand(0).getReg();
5243 const LLT DstTy =
MRI.getType(DefReg);
5246 if (DstSize != 32 && DstSize != 64)
5249 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5250 MI.getOperand(1).getReg(),
MRI);
5256 const LLT VecTy =
MRI.getType(Src0);
5261 const MachineInstr *ScalarToVector = emitScalarToVector(
5262 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5263 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5269 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5271 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5273 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5275 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5277 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5285 MachineInstr *ExtI =
nullptr;
5286 if (DstSize == 64 && !IsSigned) {
5287 Register NewReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
5288 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5289 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5292 .
addImm(AArch64::sub_32);
5295 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5298 MI.eraseFromParent();
5302MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5303 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5305 if (DstSize == 128) {
5306 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5308 Op = AArch64::MOVIv16b_ns;
5310 Op = AArch64::MOVIv8b_ns;
5313 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5317 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5324MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5325 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5329 if (DstSize == 128) {
5330 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5332 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5334 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5337 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5354MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5355 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5359 if (DstSize == 128) {
5360 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5362 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5364 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5367 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5390MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5391 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5394 if (DstSize == 128) {
5395 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5397 Op = AArch64::MOVIv2d_ns;
5399 Op = AArch64::MOVID;
5402 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5405 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5412MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5413 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5417 if (DstSize == 128) {
5418 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5420 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5422 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5425 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5442MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5443 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5446 bool IsWide =
false;
5447 if (DstSize == 128) {
5448 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5450 Op = AArch64::FMOVv4f32_ns;
5453 Op = AArch64::FMOVv2f32_ns;
5456 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5462 Op = AArch64::FMOVv2f64_ns;
5466 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5471bool AArch64InstructionSelector::selectIndexedExtLoad(
5472 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5475 Register WriteBack = ExtLd.getWritebackReg();
5478 LLT Ty =
MRI.getType(Dst);
5480 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5481 bool IsPre = ExtLd.isPre();
5483 unsigned InsertIntoSubReg = 0;
5489 if ((IsSExt && IsFPR) || Ty.
isVector())
5497 if (MemSizeBits == 8) {
5500 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5502 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5503 NewLdDstTy = IsDst64 ? s64 : s32;
5505 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5506 InsertIntoSubReg = AArch64::bsub;
5509 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5510 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5513 }
else if (MemSizeBits == 16) {
5516 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5518 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5519 NewLdDstTy = IsDst64 ? s64 : s32;
5521 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5522 InsertIntoSubReg = AArch64::hsub;
5525 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5526 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5529 }
else if (MemSizeBits == 32) {
5531 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5534 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5535 InsertIntoSubReg = AArch64::ssub;
5538 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5539 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5551 .addImm(Cst->getSExtValue());
5556 if (InsertIntoSubReg) {
5558 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5561 .
addImm(InsertIntoSubReg);
5564 *getRegClassForTypeOnBank(
MRI.getType(Dst),
5571 MI.eraseFromParent();
5576bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5577 MachineRegisterInfo &
MRI) {
5580 Register WriteBack = Ld.getWritebackReg();
5583 assert(
MRI.getType(Dst).getSizeInBits() <= 128 &&
5584 "Unexpected type for indexed load");
5585 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5587 if (MemSize <
MRI.getType(Dst).getSizeInBytes())
5588 return selectIndexedExtLoad(
MI,
MRI);
5592 static constexpr unsigned GPROpcodes[] = {
5593 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5595 static constexpr unsigned FPROpcodes[] = {
5596 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5599 ? FPROpcodes[
Log2_32(MemSize)]
5600 : GPROpcodes[
Log2_32(MemSize)];
5603 static constexpr unsigned GPROpcodes[] = {
5604 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5606 static constexpr unsigned FPROpcodes[] = {
5607 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5608 AArch64::LDRDpost, AArch64::LDRQpost};
5610 ? FPROpcodes[
Log2_32(MemSize)]
5611 : GPROpcodes[
Log2_32(MemSize)];
5621 MI.eraseFromParent();
5625bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5626 MachineRegisterInfo &
MRI) {
5631 assert(
MRI.getType(Val).getSizeInBits() <= 128 &&
5632 "Unexpected type for indexed store");
5634 LocationSize MemSize =
I.getMMO().getSize();
5635 unsigned MemSizeInBytes = MemSize.
getValue();
5637 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5638 "Unexpected indexed store size");
5639 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5643 static constexpr unsigned GPROpcodes[] = {
5644 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5646 static constexpr unsigned FPROpcodes[] = {
5647 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5651 Opc = FPROpcodes[MemSizeLog2];
5653 Opc = GPROpcodes[MemSizeLog2];
5655 static constexpr unsigned GPROpcodes[] = {
5656 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5658 static constexpr unsigned FPROpcodes[] = {
5659 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5660 AArch64::STRDpost, AArch64::STRQpost};
5663 Opc = FPROpcodes[MemSizeLog2];
5665 Opc = GPROpcodes[MemSizeLog2];
5673 Str.cloneMemRefs(
I);
5675 I.eraseFromParent();
5680AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5681 MachineIRBuilder &MIRBuilder,
5682 MachineRegisterInfo &
MRI) {
5683 LLT DstTy =
MRI.getType(Dst);
5685 assert((DstSize == 64 || DstSize == 128) &&
5686 "Unexpected vector constant size");
5689 if (DstSize == 128) {
5691 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5696 if (DstSize == 64) {
5699 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5702 .addReg(Mov.getReg(0), 0, AArch64::dsub);
5709 APInt SplatValueAsInt =
5712 : SplatValue->getUniqueInteger();
5715 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5716 MachineInstr *NewOp;
5740 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5744 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5745 unsigned NegOpc) -> MachineInstr * {
5748 APInt NegBits(DstSize, 0);
5749 unsigned NumElts = DstSize / NumBits;
5750 for (
unsigned i = 0; i < NumElts; i++)
5751 NegBits |= Neg << (NumBits * i);
5752 NegBits = DefBits ^ NegBits;
5756 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5758 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5760 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5765 if ((R = TryWithFNeg(DefBits, 32,
5766 DstSize == 64 ? AArch64::FNEGv2f32
5767 : AArch64::FNEGv4f32)) ||
5768 (R = TryWithFNeg(DefBits, 64,
5769 DstSize == 64 ? AArch64::FNEGDr
5770 : AArch64::FNEGv2f64)) ||
5771 (STI.hasFullFP16() &&
5772 (R = TryWithFNeg(DefBits, 16,
5773 DstSize == 64 ? AArch64::FNEGv4f16
5774 : AArch64::FNEGv8f16))))
5780 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5784 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5786 Dst, *
MRI.getRegClass(CPLoad->getOperand(0).getReg()),
MRI);
5790bool AArch64InstructionSelector::tryOptConstantBuildVec(
5791 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5792 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5794 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5800 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5806 const_cast<ConstantInt *
>(OpMI->getOperand(1).getCImm()));
5807 else if ((OpMI =
getOpcodeDef(TargetOpcode::G_FCONSTANT,
5808 I.getOperand(Idx).getReg(),
MRI)))
5810 const_cast<ConstantFP *
>(OpMI->getOperand(1).getFPImm()));
5815 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB,
MRI))
5817 I.eraseFromParent();
5821bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5822 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5827 Register Dst =
I.getOperand(0).getReg();
5828 Register EltReg =
I.getOperand(1).getReg();
5829 LLT EltTy =
MRI.getType(EltReg);
5837 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5841 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5844 const TargetRegisterClass *DstRC =
5845 getRegClassForTypeOnBank(
MRI.getType(Dst), DstRB);
5850 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5854 I.eraseFromParent();
5859bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5860 MachineRegisterInfo &
MRI) {
5861 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5864 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5865 const LLT EltTy =
MRI.getType(
I.getOperand(1).getReg());
5868 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5870 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5873 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5877 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5878 MachineInstr *ScalarToVec =
5880 I.getOperand(1).getReg(), MIB);
5889 MachineInstr *PrevMI = ScalarToVec;
5890 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5893 Register OpReg =
I.getOperand(i).getReg();
5896 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5903 if (DstSize < 128) {
5905 const TargetRegisterClass *RC =
5909 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5917 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
5918 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5924 Register DstReg =
I.getOperand(0).getReg();
5926 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, 0,
SubReg);
5927 MachineOperand &RegOp =
I.getOperand(1);
5947 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5948 const TargetRegisterClass *RC =
5958bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5961 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5963 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5965 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5968 "Destination must be 64 bits or 128 bits?");
5969 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5970 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5971 assert(
MRI.getType(Ptr).isPointer() &&
"Expected a pointer type?");
5973 Load.cloneMemRefs(
I);
5975 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5976 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5977 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5978 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
5987bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5988 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5989 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5991 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5993 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5996 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5998 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5999 [](
auto MO) { return MO.getReg(); });
6003 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6018 .
addImm(LaneNo->getZExtValue())
6020 Load.cloneMemRefs(
I);
6022 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6023 unsigned SubReg = AArch64::qsub0;
6024 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6025 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6026 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6027 : DstOp(
I.getOperand(Idx).
getReg())},
6029 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
6034 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6040void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6043 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6044 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6045 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6048 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6049 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6058bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6059 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6060 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6061 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6065 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6066 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6070 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6080 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6083 .
addImm(LaneNo->getZExtValue())
6090bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6091 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6104 case Intrinsic::aarch64_ldxp:
6105 case Intrinsic::aarch64_ldaxp: {
6107 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6108 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6114 case Intrinsic::aarch64_neon_ld1x2: {
6115 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6118 Opc = AArch64::LD1Twov8b;
6120 Opc = AArch64::LD1Twov16b;
6122 Opc = AArch64::LD1Twov4h;
6124 Opc = AArch64::LD1Twov8h;
6126 Opc = AArch64::LD1Twov2s;
6128 Opc = AArch64::LD1Twov4s;
6130 Opc = AArch64::LD1Twov2d;
6131 else if (Ty ==
S64 || Ty == P0)
6132 Opc = AArch64::LD1Twov1d;
6135 selectVectorLoadIntrinsic(
Opc, 2,
I);
6138 case Intrinsic::aarch64_neon_ld1x3: {
6139 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6142 Opc = AArch64::LD1Threev8b;
6144 Opc = AArch64::LD1Threev16b;
6146 Opc = AArch64::LD1Threev4h;
6148 Opc = AArch64::LD1Threev8h;
6150 Opc = AArch64::LD1Threev2s;
6152 Opc = AArch64::LD1Threev4s;
6154 Opc = AArch64::LD1Threev2d;
6155 else if (Ty ==
S64 || Ty == P0)
6156 Opc = AArch64::LD1Threev1d;
6159 selectVectorLoadIntrinsic(
Opc, 3,
I);
6162 case Intrinsic::aarch64_neon_ld1x4: {
6163 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6166 Opc = AArch64::LD1Fourv8b;
6168 Opc = AArch64::LD1Fourv16b;
6170 Opc = AArch64::LD1Fourv4h;
6172 Opc = AArch64::LD1Fourv8h;
6174 Opc = AArch64::LD1Fourv2s;
6176 Opc = AArch64::LD1Fourv4s;
6178 Opc = AArch64::LD1Fourv2d;
6179 else if (Ty ==
S64 || Ty == P0)
6180 Opc = AArch64::LD1Fourv1d;
6183 selectVectorLoadIntrinsic(
Opc, 4,
I);
6186 case Intrinsic::aarch64_neon_ld2: {
6187 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6190 Opc = AArch64::LD2Twov8b;
6192 Opc = AArch64::LD2Twov16b;
6194 Opc = AArch64::LD2Twov4h;
6196 Opc = AArch64::LD2Twov8h;
6198 Opc = AArch64::LD2Twov2s;
6200 Opc = AArch64::LD2Twov4s;
6202 Opc = AArch64::LD2Twov2d;
6203 else if (Ty ==
S64 || Ty == P0)
6204 Opc = AArch64::LD1Twov1d;
6207 selectVectorLoadIntrinsic(
Opc, 2,
I);
6210 case Intrinsic::aarch64_neon_ld2lane: {
6211 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6214 Opc = AArch64::LD2i8;
6216 Opc = AArch64::LD2i16;
6218 Opc = AArch64::LD2i32;
6221 Opc = AArch64::LD2i64;
6224 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6228 case Intrinsic::aarch64_neon_ld2r: {
6229 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6232 Opc = AArch64::LD2Rv8b;
6234 Opc = AArch64::LD2Rv16b;
6236 Opc = AArch64::LD2Rv4h;
6238 Opc = AArch64::LD2Rv8h;
6240 Opc = AArch64::LD2Rv2s;
6242 Opc = AArch64::LD2Rv4s;
6244 Opc = AArch64::LD2Rv2d;
6245 else if (Ty ==
S64 || Ty == P0)
6246 Opc = AArch64::LD2Rv1d;
6249 selectVectorLoadIntrinsic(
Opc, 2,
I);
6252 case Intrinsic::aarch64_neon_ld3: {
6253 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6256 Opc = AArch64::LD3Threev8b;
6258 Opc = AArch64::LD3Threev16b;
6260 Opc = AArch64::LD3Threev4h;
6262 Opc = AArch64::LD3Threev8h;
6264 Opc = AArch64::LD3Threev2s;
6266 Opc = AArch64::LD3Threev4s;
6268 Opc = AArch64::LD3Threev2d;
6269 else if (Ty ==
S64 || Ty == P0)
6270 Opc = AArch64::LD1Threev1d;
6273 selectVectorLoadIntrinsic(
Opc, 3,
I);
6276 case Intrinsic::aarch64_neon_ld3lane: {
6277 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6280 Opc = AArch64::LD3i8;
6282 Opc = AArch64::LD3i16;
6284 Opc = AArch64::LD3i32;
6287 Opc = AArch64::LD3i64;
6290 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6294 case Intrinsic::aarch64_neon_ld3r: {
6295 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6298 Opc = AArch64::LD3Rv8b;
6300 Opc = AArch64::LD3Rv16b;
6302 Opc = AArch64::LD3Rv4h;
6304 Opc = AArch64::LD3Rv8h;
6306 Opc = AArch64::LD3Rv2s;
6308 Opc = AArch64::LD3Rv4s;
6310 Opc = AArch64::LD3Rv2d;
6311 else if (Ty ==
S64 || Ty == P0)
6312 Opc = AArch64::LD3Rv1d;
6315 selectVectorLoadIntrinsic(
Opc, 3,
I);
6318 case Intrinsic::aarch64_neon_ld4: {
6319 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6322 Opc = AArch64::LD4Fourv8b;
6324 Opc = AArch64::LD4Fourv16b;
6326 Opc = AArch64::LD4Fourv4h;
6328 Opc = AArch64::LD4Fourv8h;
6330 Opc = AArch64::LD4Fourv2s;
6332 Opc = AArch64::LD4Fourv4s;
6334 Opc = AArch64::LD4Fourv2d;
6335 else if (Ty ==
S64 || Ty == P0)
6336 Opc = AArch64::LD1Fourv1d;
6339 selectVectorLoadIntrinsic(
Opc, 4,
I);
6342 case Intrinsic::aarch64_neon_ld4lane: {
6343 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6346 Opc = AArch64::LD4i8;
6348 Opc = AArch64::LD4i16;
6350 Opc = AArch64::LD4i32;
6353 Opc = AArch64::LD4i64;
6356 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6360 case Intrinsic::aarch64_neon_ld4r: {
6361 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6364 Opc = AArch64::LD4Rv8b;
6366 Opc = AArch64::LD4Rv16b;
6368 Opc = AArch64::LD4Rv4h;
6370 Opc = AArch64::LD4Rv8h;
6372 Opc = AArch64::LD4Rv2s;
6374 Opc = AArch64::LD4Rv4s;
6376 Opc = AArch64::LD4Rv2d;
6377 else if (Ty ==
S64 || Ty == P0)
6378 Opc = AArch64::LD4Rv1d;
6381 selectVectorLoadIntrinsic(
Opc, 4,
I);
6384 case Intrinsic::aarch64_neon_st1x2: {
6385 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6388 Opc = AArch64::ST1Twov8b;
6390 Opc = AArch64::ST1Twov16b;
6392 Opc = AArch64::ST1Twov4h;
6394 Opc = AArch64::ST1Twov8h;
6396 Opc = AArch64::ST1Twov2s;
6398 Opc = AArch64::ST1Twov4s;
6400 Opc = AArch64::ST1Twov2d;
6401 else if (Ty ==
S64 || Ty == P0)
6402 Opc = AArch64::ST1Twov1d;
6405 selectVectorStoreIntrinsic(
I, 2,
Opc);
6408 case Intrinsic::aarch64_neon_st1x3: {
6409 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6412 Opc = AArch64::ST1Threev8b;
6414 Opc = AArch64::ST1Threev16b;
6416 Opc = AArch64::ST1Threev4h;
6418 Opc = AArch64::ST1Threev8h;
6420 Opc = AArch64::ST1Threev2s;
6422 Opc = AArch64::ST1Threev4s;
6424 Opc = AArch64::ST1Threev2d;
6425 else if (Ty ==
S64 || Ty == P0)
6426 Opc = AArch64::ST1Threev1d;
6429 selectVectorStoreIntrinsic(
I, 3,
Opc);
6432 case Intrinsic::aarch64_neon_st1x4: {
6433 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6436 Opc = AArch64::ST1Fourv8b;
6438 Opc = AArch64::ST1Fourv16b;
6440 Opc = AArch64::ST1Fourv4h;
6442 Opc = AArch64::ST1Fourv8h;
6444 Opc = AArch64::ST1Fourv2s;
6446 Opc = AArch64::ST1Fourv4s;
6448 Opc = AArch64::ST1Fourv2d;
6449 else if (Ty ==
S64 || Ty == P0)
6450 Opc = AArch64::ST1Fourv1d;
6453 selectVectorStoreIntrinsic(
I, 4,
Opc);
6456 case Intrinsic::aarch64_neon_st2: {
6457 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6460 Opc = AArch64::ST2Twov8b;
6462 Opc = AArch64::ST2Twov16b;
6464 Opc = AArch64::ST2Twov4h;
6466 Opc = AArch64::ST2Twov8h;
6468 Opc = AArch64::ST2Twov2s;
6470 Opc = AArch64::ST2Twov4s;
6472 Opc = AArch64::ST2Twov2d;
6473 else if (Ty ==
S64 || Ty == P0)
6474 Opc = AArch64::ST1Twov1d;
6477 selectVectorStoreIntrinsic(
I, 2,
Opc);
6480 case Intrinsic::aarch64_neon_st3: {
6481 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6484 Opc = AArch64::ST3Threev8b;
6486 Opc = AArch64::ST3Threev16b;
6488 Opc = AArch64::ST3Threev4h;
6490 Opc = AArch64::ST3Threev8h;
6492 Opc = AArch64::ST3Threev2s;
6494 Opc = AArch64::ST3Threev4s;
6496 Opc = AArch64::ST3Threev2d;
6497 else if (Ty ==
S64 || Ty == P0)
6498 Opc = AArch64::ST1Threev1d;
6501 selectVectorStoreIntrinsic(
I, 3,
Opc);
6504 case Intrinsic::aarch64_neon_st4: {
6505 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6508 Opc = AArch64::ST4Fourv8b;
6510 Opc = AArch64::ST4Fourv16b;
6512 Opc = AArch64::ST4Fourv4h;
6514 Opc = AArch64::ST4Fourv8h;
6516 Opc = AArch64::ST4Fourv2s;
6518 Opc = AArch64::ST4Fourv4s;
6520 Opc = AArch64::ST4Fourv2d;
6521 else if (Ty ==
S64 || Ty == P0)
6522 Opc = AArch64::ST1Fourv1d;
6525 selectVectorStoreIntrinsic(
I, 4,
Opc);
6528 case Intrinsic::aarch64_neon_st2lane: {
6529 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6532 Opc = AArch64::ST2i8;
6534 Opc = AArch64::ST2i16;
6536 Opc = AArch64::ST2i32;
6539 Opc = AArch64::ST2i64;
6542 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6546 case Intrinsic::aarch64_neon_st3lane: {
6547 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6550 Opc = AArch64::ST3i8;
6552 Opc = AArch64::ST3i16;
6554 Opc = AArch64::ST3i32;
6557 Opc = AArch64::ST3i64;
6560 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6564 case Intrinsic::aarch64_neon_st4lane: {
6565 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6568 Opc = AArch64::ST4i8;
6570 Opc = AArch64::ST4i16;
6572 Opc = AArch64::ST4i32;
6575 Opc = AArch64::ST4i64;
6578 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6582 case Intrinsic::aarch64_mops_memset_tag: {
6595 Register DstDef =
I.getOperand(0).getReg();
6597 Register DstUse =
I.getOperand(2).getReg();
6598 Register ValUse =
I.getOperand(3).getReg();
6599 Register SizeUse =
I.getOperand(4).getReg();
6606 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6607 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6614 I.eraseFromParent();
6618bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6619 MachineRegisterInfo &
MRI) {
6625 case Intrinsic::ptrauth_resign: {
6626 Register DstReg =
I.getOperand(0).getReg();
6627 Register ValReg =
I.getOperand(2).getReg();
6628 uint64_t AUTKey =
I.getOperand(3).getImm();
6629 Register AUTDisc =
I.getOperand(4).getReg();
6630 uint64_t PACKey =
I.getOperand(5).getImm();
6631 Register PACDisc =
I.getOperand(6).getReg();
6634 uint16_t AUTConstDiscC = 0;
6635 std::tie(AUTConstDiscC, AUTAddrDisc) =
6639 uint16_t PACConstDiscC = 0;
6640 std::tie(PACConstDiscC, PACAddrDisc) =
6643 MIB.
buildCopy({AArch64::X16}, {ValReg});
6644 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6656 I.eraseFromParent();
6659 case Intrinsic::ptrauth_auth: {
6660 Register DstReg =
I.getOperand(0).getReg();
6661 Register ValReg =
I.getOperand(2).getReg();
6662 uint64_t AUTKey =
I.getOperand(3).getImm();
6663 Register AUTDisc =
I.getOperand(4).getReg();
6666 uint16_t AUTConstDiscC = 0;
6667 std::tie(AUTConstDiscC, AUTAddrDisc) =
6671 MIB.
buildCopy({AArch64::X16}, {ValReg});
6672 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6681 MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
6693 I.eraseFromParent();
6696 case Intrinsic::frameaddress:
6697 case Intrinsic::returnaddress: {
6698 MachineFunction &MF = *
I.getParent()->getParent();
6701 unsigned Depth =
I.getOperand(2).getImm();
6702 Register DstReg =
I.getOperand(0).getReg();
6705 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6706 if (!MFReturnAddr) {
6711 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6714 if (STI.hasPAuth()) {
6715 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6722 I.eraseFromParent();
6729 Register NextFrame =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
6731 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6733 FrameAddr = NextFrame;
6736 if (IntrinID == Intrinsic::frameaddress)
6741 if (STI.hasPAuth()) {
6742 Register TmpReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
6743 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6744 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6753 I.eraseFromParent();
6756 case Intrinsic::aarch64_neon_tbl2:
6757 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6759 case Intrinsic::aarch64_neon_tbl3:
6760 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6763 case Intrinsic::aarch64_neon_tbl4:
6764 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6766 case Intrinsic::aarch64_neon_tbx2:
6767 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6769 case Intrinsic::aarch64_neon_tbx3:
6770 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6772 case Intrinsic::aarch64_neon_tbx4:
6773 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6775 case Intrinsic::swift_async_context_addr:
6776 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6783 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6784 I.eraseFromParent();
6819bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6820 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6821 Register DefReg =
I.getOperand(0).getReg();
6822 Register Addr =
I.getOperand(1).getReg();
6823 uint64_t
Key =
I.getOperand(2).getImm();
6824 Register AddrDisc =
I.getOperand(3).getReg();
6825 uint64_t Disc =
I.getOperand(4).getImm();
6835 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6841 if (!
MRI.hasOneDef(Addr))
6845 const MachineInstr *
DefMI = &*
MRI.def_instr_begin(Addr);
6848 if (!
MRI.hasOneDef(OffsetReg))
6850 const MachineInstr &OffsetMI = *
MRI.def_instr_begin(OffsetReg);
6851 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6855 if (!
MRI.hasOneDef(Addr))
6858 DefMI = &*
MRI.def_instr_begin(Addr);
6863 const GlobalValue *GV;
6874 MachineIRBuilder MIB(
I);
6880 "unsupported non-GOT op flags on ptrauth global reference");
6882 "unsupported non-GOT reference to weak ptrauth global");
6885 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6892 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6893 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6894 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6897 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6902 I.eraseFromParent();
6914 "unsupported non-zero offset in weak ptrauth global reference");
6919 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6920 .addGlobalAddress(GV,
Offset)
6925 I.eraseFromParent();
6929void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6930 MachineRegisterInfo &
MRI,
6931 unsigned NumVec,
unsigned Opc1,
6932 unsigned Opc2,
bool isExt) {
6933 Register DstReg =
I.getOperand(0).getReg();
6938 for (
unsigned i = 0; i < NumVec; i++)
6939 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6942 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6943 MachineInstrBuilder
Instr;
6950 I.eraseFromParent();
6953InstructionSelector::ComplexRendererFns
6954AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6956 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6957 return std::nullopt;
6958 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6959 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6962InstructionSelector::ComplexRendererFns
6963AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6965 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6966 return std::nullopt;
6967 uint64_t Enc = 31 - *MaybeImmed;
6968 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6971InstructionSelector::ComplexRendererFns
6972AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
6974 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6975 return std::nullopt;
6976 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
6977 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6980InstructionSelector::ComplexRendererFns
6981AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
6983 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6984 return std::nullopt;
6985 uint64_t Enc = 63 - *MaybeImmed;
6986 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6994InstructionSelector::ComplexRendererFns
6995AArch64InstructionSelector::select12BitValueWithLeftShift(
6996 uint64_t Immed)
const {
6998 if (Immed >> 12 == 0) {
7000 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7002 Immed = Immed >> 12;
7004 return std::nullopt;
7008 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7009 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7016InstructionSelector::ComplexRendererFns
7017AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7024 if (MaybeImmed == std::nullopt)
7025 return std::nullopt;
7026 return select12BitValueWithLeftShift(*MaybeImmed);
7031InstructionSelector::ComplexRendererFns
7032AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7036 return std::nullopt;
7038 if (MaybeImmed == std::nullopt)
7039 return std::nullopt;
7040 uint64_t Immed = *MaybeImmed;
7046 return std::nullopt;
7051 if (
MRI.getType(Root.
getReg()).getSizeInBits() == 32)
7052 Immed = ~((uint32_t)Immed) + 1;
7054 Immed = ~Immed + 1ULL;
7056 if (Immed & 0xFFFFFFFFFF000000ULL)
7057 return std::nullopt;
7059 Immed &= 0xFFFFFFULL;
7060 return select12BitValueWithLeftShift(Immed);
7077std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7078 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7079 if (
MI.getOpcode() == AArch64::G_SHL) {
7083 MI.getOperand(2).getReg(),
MRI)) {
7084 const APInt ShiftVal = ValAndVeg->Value;
7087 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7090 return std::nullopt;
7098bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7099 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7100 bool IsAddrOperand)
const {
7104 if (
MRI.hasOneNonDBGUse(DefReg) ||
7105 MI.getParent()->getParent()->getFunction().hasOptSize())
7108 if (IsAddrOperand) {
7110 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7114 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7115 MachineInstr *OffsetInst =
7121 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7131 return all_of(
MRI.use_nodbg_instructions(DefReg),
7132 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7146InstructionSelector::ComplexRendererFns
7147AArch64InstructionSelector::selectExtendedSHL(
7148 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7149 unsigned SizeInBytes,
bool WantsExt)
const {
7150 assert(
Base.isReg() &&
"Expected base to be a register operand");
7151 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7154 MachineInstr *OffsetInst =
MRI.getVRegDef(
Offset.getReg());
7156 unsigned OffsetOpc = OffsetInst->
getOpcode();
7157 bool LookedThroughZExt =
false;
7158 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7160 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7161 return std::nullopt;
7165 LookedThroughZExt =
true;
7167 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7168 return std::nullopt;
7171 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7172 if (LegalShiftVal == 0)
7173 return std::nullopt;
7174 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7175 return std::nullopt;
7186 if (OffsetOpc == TargetOpcode::G_SHL)
7187 return std::nullopt;
7193 return std::nullopt;
7198 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7202 if (OffsetOpc == TargetOpcode::G_MUL) {
7204 return std::nullopt;
7210 if ((ImmVal & 0x7) != ImmVal)
7211 return std::nullopt;
7215 if (ImmVal != LegalShiftVal)
7216 return std::nullopt;
7218 unsigned SignExtend = 0;
7222 if (!LookedThroughZExt) {
7224 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7226 return std::nullopt;
7231 return std::nullopt;
7236 MachineIRBuilder MIB(*
MRI.getVRegDef(Root.
getReg()));
7237 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7242 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7243 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7244 [=](MachineInstrBuilder &MIB) {
7247 MIB.addImm(SignExtend);
7260InstructionSelector::ComplexRendererFns
7261AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7262 MachineOperand &Root,
unsigned SizeInBytes)
const {
7264 return std::nullopt;
7279 MachineInstr *PtrAdd =
7281 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7282 return std::nullopt;
7286 MachineInstr *OffsetInst =
7288 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7301InstructionSelector::ComplexRendererFns
7302AArch64InstructionSelector::selectAddrModeRegisterOffset(
7303 MachineOperand &Root)
const {
7307 MachineInstr *Gep =
MRI.getVRegDef(Root.
getReg());
7308 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7309 return std::nullopt;
7315 return std::nullopt;
7318 return {{[=](MachineInstrBuilder &MIB) {
7321 [=](MachineInstrBuilder &MIB) {
7324 [=](MachineInstrBuilder &MIB) {
7334InstructionSelector::ComplexRendererFns
7335AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7336 unsigned SizeInBytes)
const {
7339 return std::nullopt;
7340 MachineInstr *PtrAdd =
7343 return std::nullopt;
7361 unsigned Scale =
Log2_32(SizeInBytes);
7362 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7366 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7367 ImmOff < (0x1000 << Scale))
7368 return std::nullopt;
7373 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7377 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7383 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7384 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7389 return std::nullopt;
7393 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7399 return selectAddrModeRegisterOffset(Root);
7408InstructionSelector::ComplexRendererFns
7409AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7410 unsigned SizeInBytes)
const {
7413 MachineInstr *PtrAdd =
7415 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7416 return std::nullopt;
7437 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7446 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7447 return std::nullopt;
7451 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7453 return std::nullopt;
7456 MachineIRBuilder MIB(*PtrAdd);
7458 AArch64::GPR32RegClass, MIB);
7462 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7463 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7464 [=](MachineInstrBuilder &MIB) {
7465 MIB.addImm(SignExtend);
7475InstructionSelector::ComplexRendererFns
7476AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7477 unsigned Size)
const {
7478 MachineRegisterInfo &
MRI =
7482 return std::nullopt;
7484 if (!isBaseWithConstantOffset(Root,
MRI))
7485 return std::nullopt;
7487 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7489 MachineOperand &OffImm = RootDef->
getOperand(2);
7490 if (!OffImm.
isReg())
7491 return std::nullopt;
7493 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7494 return std::nullopt;
7496 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7498 return std::nullopt;
7501 if (RHSC >= -256 && RHSC < 256) {
7504 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7505 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7508 return std::nullopt;
7511InstructionSelector::ComplexRendererFns
7512AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7514 MachineRegisterInfo &
MRI)
const {
7515 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7516 return std::nullopt;
7519 return std::nullopt;
7524 return std::nullopt;
7528 return std::nullopt;
7532 return std::nullopt;
7535 MachineIRBuilder MIRBuilder(RootDef);
7537 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7538 [=](MachineInstrBuilder &MIB) {
7539 MIB.addGlobalAddress(GV,
Offset,
7548InstructionSelector::ComplexRendererFns
7549AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7550 unsigned Size)
const {
7555 return std::nullopt;
7557 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7558 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7560 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7561 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7569 MachineInstr *RootParent = Root.
getParent();
7571 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7573 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7578 if (isBaseWithConstantOffset(Root,
MRI)) {
7581 MachineInstr *LHSDef =
MRI.getVRegDef(
LHS.getReg());
7582 MachineInstr *RHSDef =
MRI.getVRegDef(
RHS.getReg());
7586 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7587 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7589 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7590 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7594 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7595 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7602 if (selectAddrModeUnscaled(Root,
Size))
7603 return std::nullopt;
7606 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7607 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7614 switch (
MI.getOpcode()) {
7617 case TargetOpcode::G_SHL:
7619 case TargetOpcode::G_LSHR:
7621 case TargetOpcode::G_ASHR:
7623 case TargetOpcode::G_ROTR:
7630InstructionSelector::ComplexRendererFns
7631AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7632 bool AllowROR)
const {
7634 return std::nullopt;
7635 MachineRegisterInfo &
MRI =
7640 MachineInstr *ShiftInst =
MRI.getVRegDef(Root.
getReg());
7643 return std::nullopt;
7645 return std::nullopt;
7646 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7647 return std::nullopt;
7650 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7653 return std::nullopt;
7657 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7660 unsigned NumBits =
MRI.getType(ShiftReg).getSizeInBits();
7661 unsigned Val = *Immed & (NumBits - 1);
7664 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7665 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7669 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7670 unsigned Opc =
MI.getOpcode();
7673 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7675 if (
Opc == TargetOpcode::G_SEXT)
7676 Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7678 Size =
MI.getOperand(2).getImm();
7679 assert(
Size != 64 &&
"Extend from 64 bits?");
7692 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7693 unsigned Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7694 assert(
Size != 64 &&
"Extend from 64 bits?");
7709 if (
Opc != TargetOpcode::G_AND)
7715 uint64_t AndMask = *MaybeAndMask;
7728Register AArch64InstructionSelector::moveScalarRegClass(
7729 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7730 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7731 auto Ty =
MRI.getType(
Reg);
7740 return Copy.getReg(0);
7745InstructionSelector::ComplexRendererFns
7746AArch64InstructionSelector::selectArithExtendedRegister(
7747 MachineOperand &Root)
const {
7749 return std::nullopt;
7750 MachineRegisterInfo &
MRI =
7753 uint64_t ShiftVal = 0;
7758 return std::nullopt;
7760 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7761 return std::nullopt;
7764 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7769 return std::nullopt;
7770 ShiftVal = *MaybeShiftVal;
7772 return std::nullopt;
7777 return std::nullopt;
7778 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7780 return std::nullopt;
7784 Ext = getExtendTypeForInst(*RootDef,
MRI);
7786 return std::nullopt;
7794 MachineInstr *ExtInst =
MRI.getVRegDef(ExtReg);
7795 if (isDef32(*ExtInst))
7796 return std::nullopt;
7802 MachineIRBuilder MIB(*RootDef);
7803 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7805 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7806 [=](MachineInstrBuilder &MIB) {
7807 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7811InstructionSelector::ComplexRendererFns
7812AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7814 return std::nullopt;
7815 MachineRegisterInfo &
MRI =
7819 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7824 return std::nullopt;
7826 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7829 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7832 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7837 LaneIdx->Value.getSExtValue() == 1) {
7839 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7843 return std::nullopt;
7846void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7847 const MachineInstr &
MI,
7849 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7850 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7851 "Expected G_CONSTANT");
7852 std::optional<int64_t> CstVal =
7854 assert(CstVal &&
"Expected constant value");
7858void AArch64InstructionSelector::renderLogicalImm32(
7859 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7860 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7861 "Expected G_CONSTANT");
7862 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7867void AArch64InstructionSelector::renderLogicalImm64(
7868 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7869 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7870 "Expected G_CONSTANT");
7871 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7876void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7877 const MachineInstr &
MI,
7879 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7880 "Expected G_UBSANTRAP");
7881 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7884void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7885 const MachineInstr &
MI,
7887 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7888 "Expected G_FCONSTANT");
7893void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7894 const MachineInstr &
MI,
7896 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7897 "Expected G_FCONSTANT");
7902void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7903 const MachineInstr &
MI,
7905 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7906 "Expected G_FCONSTANT");
7911void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7912 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7913 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7914 "Expected G_FCONSTANT");
7922bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7923 const MachineInstr &
MI,
unsigned NumBytes)
const {
7924 if (!
MI.mayLoadOrStore())
7927 "Expected load/store to have only one mem op!");
7928 return (*
MI.memoperands_begin())->getSize() == NumBytes;
7931bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
7932 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7933 if (
MRI.getType(
MI.getOperand(0).getReg()).getSizeInBits() != 32)
7940 switch (
MI.getOpcode()) {
7943 case TargetOpcode::COPY:
7944 case TargetOpcode::G_BITCAST:
7945 case TargetOpcode::G_TRUNC:
7946 case TargetOpcode::G_PHI:
7956 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
7959 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
7970 auto *OpDef =
MRI.getVRegDef(OpReg);
7971 const LLT &Ty =
MRI.getType(OpReg);
7977 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
7981 MRI.setRegBank(Copy.getReg(0), *DstRB);
7982 MO.setReg(Copy.getReg(0));
7987void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
7991 for (
auto &BB : MF) {
7992 for (
auto &
MI : BB) {
7993 if (
MI.getOpcode() == TargetOpcode::G_PHI)
7998 for (
auto *
MI : Phis) {
8020 bool HasGPROp =
false, HasFPROp =
false;
8024 const LLT &Ty =
MRI.getType(MO.getReg());
8029 const RegisterBank *RB =
MRI.getRegBankOrNull(MO.getReg());
8034 if (RB->
getID() == AArch64::GPRRegBankID)
8040 if (HasGPROp && HasFPROp)
8046InstructionSelector *
8050 return new AArch64InstructionSelector(TM, Subtarget, RBI);
unsigned const MachineRegisterInfo * MRI
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 bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool unsupportedBinOp(const MachineInstr &I, const AArch64RegisterBankInfo &RBI, const MachineRegisterInfo &MRI, const AArch64RegisterInfo &TRI)
Check whether I is a currently unsupported binary operation:
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineInstr unsigned OpIdx
static 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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
LLVM_ABI bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
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.
constexpr LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr bool isPointerVector() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
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 LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
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.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
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 & addReg(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
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.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
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,...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
The instances of the Type class are immutable: once they are created, they are never changed.
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 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.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Undef
Value of the register doesn't matter.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
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 bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.