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 "can only unmerge from vector or s128 types!");
4091 "source register size too small!");
4094 return selectSplitVectorUnmerge(
I,
MRI);
4098 unsigned CopyOpc = 0;
4099 unsigned ExtractSubReg = 0;
4110 unsigned NumInsertRegs = NumElts - 1;
4120 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,
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};
5621 MI.eraseFromParent();
5625bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5626 MachineRegisterInfo &
MRI) {
5631 LLT ValTy =
MRI.getType(Val);
5636 static constexpr unsigned GPROpcodes[] = {
5637 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5639 static constexpr unsigned FPROpcodes[] = {
5640 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5648 static constexpr unsigned GPROpcodes[] = {
5649 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5651 static constexpr unsigned FPROpcodes[] = {
5652 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5653 AArch64::STRDpost, AArch64::STRQpost};
5666 Str.cloneMemRefs(
I);
5668 I.eraseFromParent();
5673AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5674 MachineIRBuilder &MIRBuilder,
5675 MachineRegisterInfo &
MRI) {
5676 LLT DstTy =
MRI.getType(Dst);
5678 assert((DstSize == 64 || DstSize == 128) &&
5679 "Unexpected vector constant size");
5682 if (DstSize == 128) {
5684 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5689 if (DstSize == 64) {
5692 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5695 .addReg(Mov.getReg(0), 0, AArch64::dsub);
5702 APInt SplatValueAsInt =
5705 : SplatValue->getUniqueInteger();
5708 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5709 MachineInstr *NewOp;
5733 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5737 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5738 unsigned NegOpc) -> MachineInstr * {
5741 APInt NegBits(DstSize, 0);
5742 unsigned NumElts = DstSize / NumBits;
5743 for (
unsigned i = 0; i < NumElts; i++)
5744 NegBits |= Neg << (NumBits * i);
5745 NegBits = DefBits ^ NegBits;
5749 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5751 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5753 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5758 if ((R = TryWithFNeg(DefBits, 32,
5759 DstSize == 64 ? AArch64::FNEGv2f32
5760 : AArch64::FNEGv4f32)) ||
5761 (R = TryWithFNeg(DefBits, 64,
5762 DstSize == 64 ? AArch64::FNEGDr
5763 : AArch64::FNEGv2f64)) ||
5764 (STI.hasFullFP16() &&
5765 (R = TryWithFNeg(DefBits, 16,
5766 DstSize == 64 ? AArch64::FNEGv4f16
5767 : AArch64::FNEGv8f16))))
5773 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5777 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5779 Dst, *
MRI.getRegClass(CPLoad->getOperand(0).getReg()),
MRI);
5783bool AArch64InstructionSelector::tryOptConstantBuildVec(
5784 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5785 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5787 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5793 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5799 const_cast<ConstantInt *
>(OpMI->getOperand(1).getCImm()));
5800 else if ((OpMI =
getOpcodeDef(TargetOpcode::G_FCONSTANT,
5801 I.getOperand(Idx).getReg(),
MRI)))
5803 const_cast<ConstantFP *
>(OpMI->getOperand(1).getFPImm()));
5808 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB,
MRI))
5810 I.eraseFromParent();
5814bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5815 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5820 Register Dst =
I.getOperand(0).getReg();
5821 Register EltReg =
I.getOperand(1).getReg();
5822 LLT EltTy =
MRI.getType(EltReg);
5830 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5834 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5837 const TargetRegisterClass *DstRC =
5838 getRegClassForTypeOnBank(
MRI.getType(Dst), DstRB);
5843 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5847 I.eraseFromParent();
5852bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5853 MachineRegisterInfo &
MRI) {
5854 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5857 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5858 const LLT EltTy =
MRI.getType(
I.getOperand(1).getReg());
5861 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5863 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5866 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5870 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5871 MachineInstr *ScalarToVec =
5873 I.getOperand(1).getReg(), MIB);
5882 MachineInstr *PrevMI = ScalarToVec;
5883 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5886 Register OpReg =
I.getOperand(i).getReg();
5889 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5896 if (DstSize < 128) {
5898 const TargetRegisterClass *RC =
5902 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5910 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
5911 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5917 Register DstReg =
I.getOperand(0).getReg();
5919 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, 0,
SubReg);
5920 MachineOperand &RegOp =
I.getOperand(1);
5940 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5941 const TargetRegisterClass *RC =
5951bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5954 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5956 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5958 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5961 "Destination must be 64 bits or 128 bits?");
5962 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5963 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5964 assert(
MRI.getType(Ptr).isPointer() &&
"Expected a pointer type?");
5966 Load.cloneMemRefs(
I);
5968 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5969 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5970 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5971 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
5980bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5981 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5982 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5984 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5986 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5989 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5991 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5992 [](
auto MO) { return MO.getReg(); });
5996 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6011 .
addImm(LaneNo->getZExtValue())
6013 Load.cloneMemRefs(
I);
6015 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6016 unsigned SubReg = AArch64::qsub0;
6017 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6018 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6019 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6020 : DstOp(
I.getOperand(Idx).
getReg())},
6022 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
6027 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6033void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6036 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6037 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6038 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6041 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6042 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6051bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6052 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6053 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6054 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6058 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6059 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6063 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6073 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6076 .
addImm(LaneNo->getZExtValue())
6083bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6084 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6097 case Intrinsic::aarch64_ldxp:
6098 case Intrinsic::aarch64_ldaxp: {
6100 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6101 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6107 case Intrinsic::aarch64_neon_ld1x2: {
6108 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6111 Opc = AArch64::LD1Twov8b;
6113 Opc = AArch64::LD1Twov16b;
6115 Opc = AArch64::LD1Twov4h;
6117 Opc = AArch64::LD1Twov8h;
6119 Opc = AArch64::LD1Twov2s;
6121 Opc = AArch64::LD1Twov4s;
6123 Opc = AArch64::LD1Twov2d;
6124 else if (Ty ==
S64 || Ty == P0)
6125 Opc = AArch64::LD1Twov1d;
6128 selectVectorLoadIntrinsic(
Opc, 2,
I);
6131 case Intrinsic::aarch64_neon_ld1x3: {
6132 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6135 Opc = AArch64::LD1Threev8b;
6137 Opc = AArch64::LD1Threev16b;
6139 Opc = AArch64::LD1Threev4h;
6141 Opc = AArch64::LD1Threev8h;
6143 Opc = AArch64::LD1Threev2s;
6145 Opc = AArch64::LD1Threev4s;
6147 Opc = AArch64::LD1Threev2d;
6148 else if (Ty ==
S64 || Ty == P0)
6149 Opc = AArch64::LD1Threev1d;
6152 selectVectorLoadIntrinsic(
Opc, 3,
I);
6155 case Intrinsic::aarch64_neon_ld1x4: {
6156 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6159 Opc = AArch64::LD1Fourv8b;
6161 Opc = AArch64::LD1Fourv16b;
6163 Opc = AArch64::LD1Fourv4h;
6165 Opc = AArch64::LD1Fourv8h;
6167 Opc = AArch64::LD1Fourv2s;
6169 Opc = AArch64::LD1Fourv4s;
6171 Opc = AArch64::LD1Fourv2d;
6172 else if (Ty ==
S64 || Ty == P0)
6173 Opc = AArch64::LD1Fourv1d;
6176 selectVectorLoadIntrinsic(
Opc, 4,
I);
6179 case Intrinsic::aarch64_neon_ld2: {
6180 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6183 Opc = AArch64::LD2Twov8b;
6185 Opc = AArch64::LD2Twov16b;
6187 Opc = AArch64::LD2Twov4h;
6189 Opc = AArch64::LD2Twov8h;
6191 Opc = AArch64::LD2Twov2s;
6193 Opc = AArch64::LD2Twov4s;
6195 Opc = AArch64::LD2Twov2d;
6196 else if (Ty ==
S64 || Ty == P0)
6197 Opc = AArch64::LD1Twov1d;
6200 selectVectorLoadIntrinsic(
Opc, 2,
I);
6203 case Intrinsic::aarch64_neon_ld2lane: {
6204 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6207 Opc = AArch64::LD2i8;
6209 Opc = AArch64::LD2i16;
6211 Opc = AArch64::LD2i32;
6214 Opc = AArch64::LD2i64;
6217 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6221 case Intrinsic::aarch64_neon_ld2r: {
6222 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6225 Opc = AArch64::LD2Rv8b;
6227 Opc = AArch64::LD2Rv16b;
6229 Opc = AArch64::LD2Rv4h;
6231 Opc = AArch64::LD2Rv8h;
6233 Opc = AArch64::LD2Rv2s;
6235 Opc = AArch64::LD2Rv4s;
6237 Opc = AArch64::LD2Rv2d;
6238 else if (Ty ==
S64 || Ty == P0)
6239 Opc = AArch64::LD2Rv1d;
6242 selectVectorLoadIntrinsic(
Opc, 2,
I);
6245 case Intrinsic::aarch64_neon_ld3: {
6246 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6249 Opc = AArch64::LD3Threev8b;
6251 Opc = AArch64::LD3Threev16b;
6253 Opc = AArch64::LD3Threev4h;
6255 Opc = AArch64::LD3Threev8h;
6257 Opc = AArch64::LD3Threev2s;
6259 Opc = AArch64::LD3Threev4s;
6261 Opc = AArch64::LD3Threev2d;
6262 else if (Ty ==
S64 || Ty == P0)
6263 Opc = AArch64::LD1Threev1d;
6266 selectVectorLoadIntrinsic(
Opc, 3,
I);
6269 case Intrinsic::aarch64_neon_ld3lane: {
6270 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6273 Opc = AArch64::LD3i8;
6275 Opc = AArch64::LD3i16;
6277 Opc = AArch64::LD3i32;
6280 Opc = AArch64::LD3i64;
6283 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6287 case Intrinsic::aarch64_neon_ld3r: {
6288 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6291 Opc = AArch64::LD3Rv8b;
6293 Opc = AArch64::LD3Rv16b;
6295 Opc = AArch64::LD3Rv4h;
6297 Opc = AArch64::LD3Rv8h;
6299 Opc = AArch64::LD3Rv2s;
6301 Opc = AArch64::LD3Rv4s;
6303 Opc = AArch64::LD3Rv2d;
6304 else if (Ty ==
S64 || Ty == P0)
6305 Opc = AArch64::LD3Rv1d;
6308 selectVectorLoadIntrinsic(
Opc, 3,
I);
6311 case Intrinsic::aarch64_neon_ld4: {
6312 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6315 Opc = AArch64::LD4Fourv8b;
6317 Opc = AArch64::LD4Fourv16b;
6319 Opc = AArch64::LD4Fourv4h;
6321 Opc = AArch64::LD4Fourv8h;
6323 Opc = AArch64::LD4Fourv2s;
6325 Opc = AArch64::LD4Fourv4s;
6327 Opc = AArch64::LD4Fourv2d;
6328 else if (Ty ==
S64 || Ty == P0)
6329 Opc = AArch64::LD1Fourv1d;
6332 selectVectorLoadIntrinsic(
Opc, 4,
I);
6335 case Intrinsic::aarch64_neon_ld4lane: {
6336 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6339 Opc = AArch64::LD4i8;
6341 Opc = AArch64::LD4i16;
6343 Opc = AArch64::LD4i32;
6346 Opc = AArch64::LD4i64;
6349 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6353 case Intrinsic::aarch64_neon_ld4r: {
6354 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6357 Opc = AArch64::LD4Rv8b;
6359 Opc = AArch64::LD4Rv16b;
6361 Opc = AArch64::LD4Rv4h;
6363 Opc = AArch64::LD4Rv8h;
6365 Opc = AArch64::LD4Rv2s;
6367 Opc = AArch64::LD4Rv4s;
6369 Opc = AArch64::LD4Rv2d;
6370 else if (Ty ==
S64 || Ty == P0)
6371 Opc = AArch64::LD4Rv1d;
6374 selectVectorLoadIntrinsic(
Opc, 4,
I);
6377 case Intrinsic::aarch64_neon_st1x2: {
6378 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6381 Opc = AArch64::ST1Twov8b;
6383 Opc = AArch64::ST1Twov16b;
6385 Opc = AArch64::ST1Twov4h;
6387 Opc = AArch64::ST1Twov8h;
6389 Opc = AArch64::ST1Twov2s;
6391 Opc = AArch64::ST1Twov4s;
6393 Opc = AArch64::ST1Twov2d;
6394 else if (Ty ==
S64 || Ty == P0)
6395 Opc = AArch64::ST1Twov1d;
6398 selectVectorStoreIntrinsic(
I, 2,
Opc);
6401 case Intrinsic::aarch64_neon_st1x3: {
6402 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6405 Opc = AArch64::ST1Threev8b;
6407 Opc = AArch64::ST1Threev16b;
6409 Opc = AArch64::ST1Threev4h;
6411 Opc = AArch64::ST1Threev8h;
6413 Opc = AArch64::ST1Threev2s;
6415 Opc = AArch64::ST1Threev4s;
6417 Opc = AArch64::ST1Threev2d;
6418 else if (Ty ==
S64 || Ty == P0)
6419 Opc = AArch64::ST1Threev1d;
6422 selectVectorStoreIntrinsic(
I, 3,
Opc);
6425 case Intrinsic::aarch64_neon_st1x4: {
6426 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6429 Opc = AArch64::ST1Fourv8b;
6431 Opc = AArch64::ST1Fourv16b;
6433 Opc = AArch64::ST1Fourv4h;
6435 Opc = AArch64::ST1Fourv8h;
6437 Opc = AArch64::ST1Fourv2s;
6439 Opc = AArch64::ST1Fourv4s;
6441 Opc = AArch64::ST1Fourv2d;
6442 else if (Ty ==
S64 || Ty == P0)
6443 Opc = AArch64::ST1Fourv1d;
6446 selectVectorStoreIntrinsic(
I, 4,
Opc);
6449 case Intrinsic::aarch64_neon_st2: {
6450 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6453 Opc = AArch64::ST2Twov8b;
6455 Opc = AArch64::ST2Twov16b;
6457 Opc = AArch64::ST2Twov4h;
6459 Opc = AArch64::ST2Twov8h;
6461 Opc = AArch64::ST2Twov2s;
6463 Opc = AArch64::ST2Twov4s;
6465 Opc = AArch64::ST2Twov2d;
6466 else if (Ty ==
S64 || Ty == P0)
6467 Opc = AArch64::ST1Twov1d;
6470 selectVectorStoreIntrinsic(
I, 2,
Opc);
6473 case Intrinsic::aarch64_neon_st3: {
6474 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6477 Opc = AArch64::ST3Threev8b;
6479 Opc = AArch64::ST3Threev16b;
6481 Opc = AArch64::ST3Threev4h;
6483 Opc = AArch64::ST3Threev8h;
6485 Opc = AArch64::ST3Threev2s;
6487 Opc = AArch64::ST3Threev4s;
6489 Opc = AArch64::ST3Threev2d;
6490 else if (Ty ==
S64 || Ty == P0)
6491 Opc = AArch64::ST1Threev1d;
6494 selectVectorStoreIntrinsic(
I, 3,
Opc);
6497 case Intrinsic::aarch64_neon_st4: {
6498 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6501 Opc = AArch64::ST4Fourv8b;
6503 Opc = AArch64::ST4Fourv16b;
6505 Opc = AArch64::ST4Fourv4h;
6507 Opc = AArch64::ST4Fourv8h;
6509 Opc = AArch64::ST4Fourv2s;
6511 Opc = AArch64::ST4Fourv4s;
6513 Opc = AArch64::ST4Fourv2d;
6514 else if (Ty ==
S64 || Ty == P0)
6515 Opc = AArch64::ST1Fourv1d;
6518 selectVectorStoreIntrinsic(
I, 4,
Opc);
6521 case Intrinsic::aarch64_neon_st2lane: {
6522 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6525 Opc = AArch64::ST2i8;
6527 Opc = AArch64::ST2i16;
6529 Opc = AArch64::ST2i32;
6532 Opc = AArch64::ST2i64;
6535 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6539 case Intrinsic::aarch64_neon_st3lane: {
6540 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6543 Opc = AArch64::ST3i8;
6545 Opc = AArch64::ST3i16;
6547 Opc = AArch64::ST3i32;
6550 Opc = AArch64::ST3i64;
6553 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6557 case Intrinsic::aarch64_neon_st4lane: {
6558 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6561 Opc = AArch64::ST4i8;
6563 Opc = AArch64::ST4i16;
6565 Opc = AArch64::ST4i32;
6568 Opc = AArch64::ST4i64;
6571 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6575 case Intrinsic::aarch64_mops_memset_tag: {
6588 Register DstDef =
I.getOperand(0).getReg();
6590 Register DstUse =
I.getOperand(2).getReg();
6591 Register ValUse =
I.getOperand(3).getReg();
6592 Register SizeUse =
I.getOperand(4).getReg();
6599 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6600 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6607 I.eraseFromParent();
6611bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6612 MachineRegisterInfo &
MRI) {
6618 case Intrinsic::ptrauth_resign: {
6619 Register DstReg =
I.getOperand(0).getReg();
6620 Register ValReg =
I.getOperand(2).getReg();
6621 uint64_t AUTKey =
I.getOperand(3).getImm();
6622 Register AUTDisc =
I.getOperand(4).getReg();
6623 uint64_t PACKey =
I.getOperand(5).getImm();
6624 Register PACDisc =
I.getOperand(6).getReg();
6627 uint16_t AUTConstDiscC = 0;
6628 std::tie(AUTConstDiscC, AUTAddrDisc) =
6632 uint16_t PACConstDiscC = 0;
6633 std::tie(PACConstDiscC, PACAddrDisc) =
6636 MIB.
buildCopy({AArch64::X16}, {ValReg});
6637 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6649 I.eraseFromParent();
6652 case Intrinsic::ptrauth_auth: {
6653 Register DstReg =
I.getOperand(0).getReg();
6654 Register ValReg =
I.getOperand(2).getReg();
6655 uint64_t AUTKey =
I.getOperand(3).getImm();
6656 Register AUTDisc =
I.getOperand(4).getReg();
6659 uint16_t AUTConstDiscC = 0;
6660 std::tie(AUTConstDiscC, AUTAddrDisc) =
6664 MIB.
buildCopy({AArch64::X16}, {ValReg});
6665 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6674 MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
6686 I.eraseFromParent();
6689 case Intrinsic::frameaddress:
6690 case Intrinsic::returnaddress: {
6691 MachineFunction &MF = *
I.getParent()->getParent();
6694 unsigned Depth =
I.getOperand(2).getImm();
6695 Register DstReg =
I.getOperand(0).getReg();
6698 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6699 if (!MFReturnAddr) {
6704 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6707 if (STI.hasPAuth()) {
6708 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6715 I.eraseFromParent();
6722 Register NextFrame =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
6724 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6726 FrameAddr = NextFrame;
6729 if (IntrinID == Intrinsic::frameaddress)
6734 if (STI.hasPAuth()) {
6735 Register TmpReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
6736 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6737 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6746 I.eraseFromParent();
6749 case Intrinsic::aarch64_neon_tbl2:
6750 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6752 case Intrinsic::aarch64_neon_tbl3:
6753 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6756 case Intrinsic::aarch64_neon_tbl4:
6757 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6759 case Intrinsic::aarch64_neon_tbx2:
6760 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6762 case Intrinsic::aarch64_neon_tbx3:
6763 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6765 case Intrinsic::aarch64_neon_tbx4:
6766 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6768 case Intrinsic::swift_async_context_addr:
6769 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6776 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6777 I.eraseFromParent();
6812bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6813 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6814 Register DefReg =
I.getOperand(0).getReg();
6815 Register Addr =
I.getOperand(1).getReg();
6816 uint64_t
Key =
I.getOperand(2).getImm();
6817 Register AddrDisc =
I.getOperand(3).getReg();
6818 uint64_t Disc =
I.getOperand(4).getImm();
6828 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6834 if (!
MRI.hasOneDef(Addr))
6838 const MachineInstr *
DefMI = &*
MRI.def_instr_begin(Addr);
6841 if (!
MRI.hasOneDef(OffsetReg))
6843 const MachineInstr &OffsetMI = *
MRI.def_instr_begin(OffsetReg);
6844 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6848 if (!
MRI.hasOneDef(Addr))
6851 DefMI = &*
MRI.def_instr_begin(Addr);
6856 const GlobalValue *GV;
6867 MachineIRBuilder MIB(
I);
6873 "unsupported non-GOT op flags on ptrauth global reference");
6875 "unsupported non-GOT reference to weak ptrauth global");
6878 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6885 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6886 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6887 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6890 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6895 I.eraseFromParent();
6907 "unsupported non-zero offset in weak ptrauth global reference");
6912 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6913 .addGlobalAddress(GV,
Offset)
6918 I.eraseFromParent();
6922void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6923 MachineRegisterInfo &
MRI,
6924 unsigned NumVec,
unsigned Opc1,
6925 unsigned Opc2,
bool isExt) {
6926 Register DstReg =
I.getOperand(0).getReg();
6931 for (
unsigned i = 0; i < NumVec; i++)
6932 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6935 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6936 MachineInstrBuilder
Instr;
6943 I.eraseFromParent();
6946InstructionSelector::ComplexRendererFns
6947AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6949 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6950 return std::nullopt;
6951 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6952 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6955InstructionSelector::ComplexRendererFns
6956AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6958 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6959 return std::nullopt;
6960 uint64_t Enc = 31 - *MaybeImmed;
6961 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6964InstructionSelector::ComplexRendererFns
6965AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
6967 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6968 return std::nullopt;
6969 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
6970 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6973InstructionSelector::ComplexRendererFns
6974AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
6976 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6977 return std::nullopt;
6978 uint64_t Enc = 63 - *MaybeImmed;
6979 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6987InstructionSelector::ComplexRendererFns
6988AArch64InstructionSelector::select12BitValueWithLeftShift(
6989 uint64_t Immed)
const {
6991 if (Immed >> 12 == 0) {
6993 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
6995 Immed = Immed >> 12;
6997 return std::nullopt;
7001 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7002 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7009InstructionSelector::ComplexRendererFns
7010AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7017 if (MaybeImmed == std::nullopt)
7018 return std::nullopt;
7019 return select12BitValueWithLeftShift(*MaybeImmed);
7024InstructionSelector::ComplexRendererFns
7025AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7029 return std::nullopt;
7031 if (MaybeImmed == std::nullopt)
7032 return std::nullopt;
7033 uint64_t Immed = *MaybeImmed;
7039 return std::nullopt;
7044 if (
MRI.getType(Root.
getReg()).getSizeInBits() == 32)
7045 Immed = ~((uint32_t)Immed) + 1;
7047 Immed = ~Immed + 1ULL;
7049 if (Immed & 0xFFFFFFFFFF000000ULL)
7050 return std::nullopt;
7052 Immed &= 0xFFFFFFULL;
7053 return select12BitValueWithLeftShift(Immed);
7070std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7071 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7072 if (
MI.getOpcode() == AArch64::G_SHL) {
7076 MI.getOperand(2).getReg(),
MRI)) {
7077 const APInt ShiftVal = ValAndVeg->Value;
7080 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7083 return std::nullopt;
7091bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7092 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7093 bool IsAddrOperand)
const {
7097 if (
MRI.hasOneNonDBGUse(DefReg) ||
7098 MI.getParent()->getParent()->getFunction().hasOptSize())
7101 if (IsAddrOperand) {
7103 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7107 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7108 MachineInstr *OffsetInst =
7114 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7124 return all_of(
MRI.use_nodbg_instructions(DefReg),
7125 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7139InstructionSelector::ComplexRendererFns
7140AArch64InstructionSelector::selectExtendedSHL(
7141 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7142 unsigned SizeInBytes,
bool WantsExt)
const {
7143 assert(
Base.isReg() &&
"Expected base to be a register operand");
7144 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7147 MachineInstr *OffsetInst =
MRI.getVRegDef(
Offset.getReg());
7149 unsigned OffsetOpc = OffsetInst->
getOpcode();
7150 bool LookedThroughZExt =
false;
7151 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7153 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7154 return std::nullopt;
7158 LookedThroughZExt =
true;
7160 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7161 return std::nullopt;
7164 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7165 if (LegalShiftVal == 0)
7166 return std::nullopt;
7167 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7168 return std::nullopt;
7179 if (OffsetOpc == TargetOpcode::G_SHL)
7180 return std::nullopt;
7186 return std::nullopt;
7191 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7195 if (OffsetOpc == TargetOpcode::G_MUL) {
7197 return std::nullopt;
7203 if ((ImmVal & 0x7) != ImmVal)
7204 return std::nullopt;
7208 if (ImmVal != LegalShiftVal)
7209 return std::nullopt;
7211 unsigned SignExtend = 0;
7215 if (!LookedThroughZExt) {
7217 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7219 return std::nullopt;
7224 return std::nullopt;
7229 MachineIRBuilder MIB(*
MRI.getVRegDef(Root.
getReg()));
7230 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7235 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7236 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7237 [=](MachineInstrBuilder &MIB) {
7240 MIB.addImm(SignExtend);
7253InstructionSelector::ComplexRendererFns
7254AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7255 MachineOperand &Root,
unsigned SizeInBytes)
const {
7257 return std::nullopt;
7272 MachineInstr *PtrAdd =
7274 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7275 return std::nullopt;
7279 MachineInstr *OffsetInst =
7281 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7294InstructionSelector::ComplexRendererFns
7295AArch64InstructionSelector::selectAddrModeRegisterOffset(
7296 MachineOperand &Root)
const {
7300 MachineInstr *Gep =
MRI.getVRegDef(Root.
getReg());
7301 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7302 return std::nullopt;
7308 return std::nullopt;
7311 return {{[=](MachineInstrBuilder &MIB) {
7314 [=](MachineInstrBuilder &MIB) {
7317 [=](MachineInstrBuilder &MIB) {
7327InstructionSelector::ComplexRendererFns
7328AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7329 unsigned SizeInBytes)
const {
7332 return std::nullopt;
7333 MachineInstr *PtrAdd =
7336 return std::nullopt;
7354 unsigned Scale =
Log2_32(SizeInBytes);
7355 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7359 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7360 ImmOff < (0x1000 << Scale))
7361 return std::nullopt;
7366 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7370 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7376 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7377 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7382 return std::nullopt;
7386 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7392 return selectAddrModeRegisterOffset(Root);
7401InstructionSelector::ComplexRendererFns
7402AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7403 unsigned SizeInBytes)
const {
7406 MachineInstr *PtrAdd =
7408 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7409 return std::nullopt;
7430 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7439 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7440 return std::nullopt;
7444 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7446 return std::nullopt;
7449 MachineIRBuilder MIB(*PtrAdd);
7451 AArch64::GPR32RegClass, MIB);
7455 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7456 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7457 [=](MachineInstrBuilder &MIB) {
7458 MIB.addImm(SignExtend);
7468InstructionSelector::ComplexRendererFns
7469AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7470 unsigned Size)
const {
7471 MachineRegisterInfo &
MRI =
7475 return std::nullopt;
7477 if (!isBaseWithConstantOffset(Root,
MRI))
7478 return std::nullopt;
7480 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7482 MachineOperand &OffImm = RootDef->
getOperand(2);
7483 if (!OffImm.
isReg())
7484 return std::nullopt;
7486 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7487 return std::nullopt;
7489 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7491 return std::nullopt;
7494 if (RHSC >= -256 && RHSC < 256) {
7497 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7498 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7501 return std::nullopt;
7504InstructionSelector::ComplexRendererFns
7505AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7507 MachineRegisterInfo &
MRI)
const {
7508 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7509 return std::nullopt;
7512 return std::nullopt;
7517 return std::nullopt;
7521 return std::nullopt;
7525 return std::nullopt;
7528 MachineIRBuilder MIRBuilder(RootDef);
7530 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7531 [=](MachineInstrBuilder &MIB) {
7532 MIB.addGlobalAddress(GV,
Offset,
7541InstructionSelector::ComplexRendererFns
7542AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7543 unsigned Size)
const {
7548 return std::nullopt;
7550 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7551 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7553 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7554 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7562 MachineInstr *RootParent = Root.
getParent();
7564 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7566 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7571 if (isBaseWithConstantOffset(Root,
MRI)) {
7574 MachineInstr *LHSDef =
MRI.getVRegDef(
LHS.getReg());
7575 MachineInstr *RHSDef =
MRI.getVRegDef(
RHS.getReg());
7579 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7580 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7582 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7583 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7587 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7588 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7595 if (selectAddrModeUnscaled(Root,
Size))
7596 return std::nullopt;
7599 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7600 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7607 switch (
MI.getOpcode()) {
7610 case TargetOpcode::G_SHL:
7612 case TargetOpcode::G_LSHR:
7614 case TargetOpcode::G_ASHR:
7616 case TargetOpcode::G_ROTR:
7623InstructionSelector::ComplexRendererFns
7624AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7625 bool AllowROR)
const {
7627 return std::nullopt;
7628 MachineRegisterInfo &
MRI =
7633 MachineInstr *ShiftInst =
MRI.getVRegDef(Root.
getReg());
7636 return std::nullopt;
7638 return std::nullopt;
7639 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7640 return std::nullopt;
7643 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7646 return std::nullopt;
7650 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7653 unsigned NumBits =
MRI.getType(ShiftReg).getSizeInBits();
7654 unsigned Val = *Immed & (NumBits - 1);
7657 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7658 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7662 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7663 unsigned Opc =
MI.getOpcode();
7666 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7668 if (
Opc == TargetOpcode::G_SEXT)
7669 Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7671 Size =
MI.getOperand(2).getImm();
7672 assert(
Size != 64 &&
"Extend from 64 bits?");
7685 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7686 unsigned Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7687 assert(
Size != 64 &&
"Extend from 64 bits?");
7702 if (
Opc != TargetOpcode::G_AND)
7708 uint64_t AndMask = *MaybeAndMask;
7721Register AArch64InstructionSelector::moveScalarRegClass(
7722 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7723 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7724 auto Ty =
MRI.getType(
Reg);
7733 return Copy.getReg(0);
7738InstructionSelector::ComplexRendererFns
7739AArch64InstructionSelector::selectArithExtendedRegister(
7740 MachineOperand &Root)
const {
7742 return std::nullopt;
7743 MachineRegisterInfo &
MRI =
7746 uint64_t ShiftVal = 0;
7751 return std::nullopt;
7753 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7754 return std::nullopt;
7757 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7762 return std::nullopt;
7763 ShiftVal = *MaybeShiftVal;
7765 return std::nullopt;
7770 return std::nullopt;
7771 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7773 return std::nullopt;
7777 Ext = getExtendTypeForInst(*RootDef,
MRI);
7779 return std::nullopt;
7787 MachineInstr *ExtInst =
MRI.getVRegDef(ExtReg);
7788 if (isDef32(*ExtInst))
7789 return std::nullopt;
7795 MachineIRBuilder MIB(*RootDef);
7796 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7798 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7799 [=](MachineInstrBuilder &MIB) {
7800 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7804InstructionSelector::ComplexRendererFns
7805AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7807 return std::nullopt;
7808 MachineRegisterInfo &
MRI =
7812 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7817 return std::nullopt;
7819 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7822 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7825 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7830 LaneIdx->Value.getSExtValue() == 1) {
7832 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7836 return std::nullopt;
7839void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7840 const MachineInstr &
MI,
7842 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7843 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7844 "Expected G_CONSTANT");
7845 std::optional<int64_t> CstVal =
7847 assert(CstVal &&
"Expected constant value");
7851void AArch64InstructionSelector::renderLogicalImm32(
7852 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7853 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7854 "Expected G_CONSTANT");
7855 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7860void AArch64InstructionSelector::renderLogicalImm64(
7861 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7862 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7863 "Expected G_CONSTANT");
7864 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7869void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7870 const MachineInstr &
MI,
7872 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7873 "Expected G_UBSANTRAP");
7874 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7877void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7878 const MachineInstr &
MI,
7880 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7881 "Expected G_FCONSTANT");
7886void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7887 const MachineInstr &
MI,
7889 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7890 "Expected G_FCONSTANT");
7895void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7896 const MachineInstr &
MI,
7898 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7899 "Expected G_FCONSTANT");
7904void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7905 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7906 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7907 "Expected G_FCONSTANT");
7915bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7916 const MachineInstr &
MI,
unsigned NumBytes)
const {
7917 if (!
MI.mayLoadOrStore())
7920 "Expected load/store to have only one mem op!");
7921 return (*
MI.memoperands_begin())->getSize() == NumBytes;
7924bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
7925 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7926 if (
MRI.getType(
MI.getOperand(0).getReg()).getSizeInBits() != 32)
7933 switch (
MI.getOpcode()) {
7936 case TargetOpcode::COPY:
7937 case TargetOpcode::G_BITCAST:
7938 case TargetOpcode::G_TRUNC:
7939 case TargetOpcode::G_PHI:
7949 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
7952 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
7963 auto *OpDef =
MRI.getVRegDef(OpReg);
7964 const LLT &Ty =
MRI.getType(OpReg);
7970 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
7974 MRI.setRegBank(Copy.getReg(0), *DstRB);
7975 MO.setReg(Copy.getReg(0));
7980void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
7984 for (
auto &BB : MF) {
7985 for (
auto &
MI : BB) {
7986 if (
MI.getOpcode() == TargetOpcode::G_PHI)
7991 for (
auto *
MI : Phis) {
8013 bool HasGPROp =
false, HasFPROp =
false;
8017 const LLT &Ty =
MRI.getType(MO.getReg());
8022 const RegisterBank *RB =
MRI.getRegBankOrNull(MO.getReg());
8027 if (RB->
getID() == AArch64::GPRRegBankID)
8033 if (HasGPROp && HasFPROp)
8039InstructionSelector *
8043 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.