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,
320 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
342 std::pair<MachineInstr *, AArch64CC::CondCode>
377 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
378 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
379 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
380 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
382 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
384 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
387 unsigned Size)
const;
389 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
390 return selectAddrModeUnscaled(Root, 1);
392 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
393 return selectAddrModeUnscaled(Root, 2);
395 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
396 return selectAddrModeUnscaled(Root, 4);
398 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
399 return selectAddrModeUnscaled(Root, 8);
401 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
402 return selectAddrModeUnscaled(Root, 16);
407 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
411 unsigned Size)
const;
413 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
414 return selectAddrModeIndexed(Root, Width / 8);
423 bool IsAddrOperand)
const;
426 unsigned SizeInBytes)
const;
434 bool WantsExt)
const;
435 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
437 unsigned SizeInBytes)
const;
439 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
440 return selectAddrModeXRO(Root, Width / 8);
444 unsigned SizeInBytes)
const;
446 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
447 return selectAddrModeWRO(Root, Width / 8);
451 bool AllowROR =
false)
const;
453 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
454 return selectShiftedRegister(Root);
457 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
458 return selectShiftedRegister(Root,
true);
468 bool IsLoadStore =
false)
const;
479 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
484 int OpIdx = -1)
const;
486 int OpIdx = -1)
const;
488 int OpIdx = -1)
const;
492 int OpIdx = -1)
const;
494 int OpIdx = -1)
const;
496 int OpIdx = -1)
const;
499 int OpIdx = -1)
const;
505 bool tryOptSelect(
GSelect &Sel);
512 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
525 bool ProduceNonFlagSettingCondBr =
false;
534#define GET_GLOBALISEL_PREDICATES_DECL
535#include "AArch64GenGlobalISel.inc"
536#undef GET_GLOBALISEL_PREDICATES_DECL
540#define GET_GLOBALISEL_TEMPORARIES_DECL
541#include "AArch64GenGlobalISel.inc"
542#undef GET_GLOBALISEL_TEMPORARIES_DECL
547#define GET_GLOBALISEL_IMPL
548#include "AArch64GenGlobalISel.inc"
549#undef GET_GLOBALISEL_IMPL
551AArch64InstructionSelector::AArch64InstructionSelector(
554 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
557#include
"AArch64GenGlobalISel.inc"
560#include
"AArch64GenGlobalISel.inc"
572 bool GetAllRegSet =
false) {
573 if (RB.
getID() == AArch64::GPRRegBankID) {
574 if (Ty.getSizeInBits() <= 32)
575 return GetAllRegSet ? &AArch64::GPR32allRegClass
576 : &AArch64::GPR32RegClass;
577 if (Ty.getSizeInBits() == 64)
578 return GetAllRegSet ? &AArch64::GPR64allRegClass
579 : &AArch64::GPR64RegClass;
580 if (Ty.getSizeInBits() == 128)
581 return &AArch64::XSeqPairsClassRegClass;
585 if (RB.
getID() == AArch64::FPRRegBankID) {
586 switch (Ty.getSizeInBits()) {
588 return &AArch64::FPR8RegClass;
590 return &AArch64::FPR16RegClass;
592 return &AArch64::FPR32RegClass;
594 return &AArch64::FPR64RegClass;
596 return &AArch64::FPR128RegClass;
608 bool GetAllRegSet =
false) {
611 "Expected FPR regbank for scalable type size");
612 return &AArch64::ZPRRegClass;
615 unsigned RegBankID = RB.
getID();
617 if (RegBankID == AArch64::GPRRegBankID) {
619 if (SizeInBits <= 32)
620 return GetAllRegSet ? &AArch64::GPR32allRegClass
621 : &AArch64::GPR32RegClass;
622 if (SizeInBits == 64)
623 return GetAllRegSet ? &AArch64::GPR64allRegClass
624 : &AArch64::GPR64RegClass;
625 if (SizeInBits == 128)
626 return &AArch64::XSeqPairsClassRegClass;
629 if (RegBankID == AArch64::FPRRegBankID) {
632 "Unexpected scalable register size");
633 return &AArch64::ZPRRegClass;
636 switch (SizeInBits) {
640 return &AArch64::FPR8RegClass;
642 return &AArch64::FPR16RegClass;
644 return &AArch64::FPR32RegClass;
646 return &AArch64::FPR64RegClass;
648 return &AArch64::FPR128RegClass;
658 switch (
TRI.getRegSizeInBits(*RC)) {
666 if (RC != &AArch64::FPR32RegClass)
676 dbgs() <<
"Couldn't find appropriate subregister for register class.");
685 switch (RB.
getID()) {
686 case AArch64::GPRRegBankID:
688 case AArch64::FPRRegBankID:
711 const unsigned RegClassIDs[],
713 unsigned NumRegs = Regs.
size();
716 assert(NumRegs >= 2 && NumRegs <= 4 &&
717 "Only support between two and 4 registers in a tuple!");
719 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
721 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
722 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
723 RegSequence.addUse(Regs[
I]);
724 RegSequence.addImm(SubRegs[
I]);
726 return RegSequence.getReg(0);
731 static const unsigned RegClassIDs[] = {
732 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
733 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
734 AArch64::dsub2, AArch64::dsub3};
735 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
740 static const unsigned RegClassIDs[] = {
741 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
742 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
743 AArch64::qsub2, AArch64::qsub3};
744 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
749 auto &
MBB = *
MI.getParent();
750 auto &MF = *
MBB.getParent();
751 auto &
MRI = MF.getRegInfo();
757 else if (Root.
isReg()) {
762 Immed = ValAndVReg->Value.getSExtValue();
778 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
785 for (
auto &MO :
I.operands()) {
788 LLVM_DEBUG(
dbgs() <<
"Generic inst non-reg operands are unsupported\n");
796 if (!MO.getReg().isVirtual()) {
797 LLVM_DEBUG(
dbgs() <<
"Generic inst has physical register operand\n");
807 if (PrevOpBank && OpBank != PrevOpBank) {
808 LLVM_DEBUG(
dbgs() <<
"Generic inst operands have different banks\n");
823 case AArch64::GPRRegBankID:
825 switch (GenericOpc) {
826 case TargetOpcode::G_SHL:
827 return AArch64::LSLVWr;
828 case TargetOpcode::G_LSHR:
829 return AArch64::LSRVWr;
830 case TargetOpcode::G_ASHR:
831 return AArch64::ASRVWr;
835 }
else if (OpSize == 64) {
836 switch (GenericOpc) {
837 case TargetOpcode::G_PTR_ADD:
838 return AArch64::ADDXrr;
839 case TargetOpcode::G_SHL:
840 return AArch64::LSLVXr;
841 case TargetOpcode::G_LSHR:
842 return AArch64::LSRVXr;
843 case TargetOpcode::G_ASHR:
844 return AArch64::ASRVXr;
850 case AArch64::FPRRegBankID:
853 switch (GenericOpc) {
854 case TargetOpcode::G_FADD:
855 return AArch64::FADDSrr;
856 case TargetOpcode::G_FSUB:
857 return AArch64::FSUBSrr;
858 case TargetOpcode::G_FMUL:
859 return AArch64::FMULSrr;
860 case TargetOpcode::G_FDIV:
861 return AArch64::FDIVSrr;
866 switch (GenericOpc) {
867 case TargetOpcode::G_FADD:
868 return AArch64::FADDDrr;
869 case TargetOpcode::G_FSUB:
870 return AArch64::FSUBDrr;
871 case TargetOpcode::G_FMUL:
872 return AArch64::FMULDrr;
873 case TargetOpcode::G_FDIV:
874 return AArch64::FDIVDrr;
875 case TargetOpcode::G_OR:
876 return AArch64::ORRv8i8;
893 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
895 case AArch64::GPRRegBankID:
898 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
900 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
902 return isStore ? AArch64::STRWui : AArch64::LDRWui;
904 return isStore ? AArch64::STRXui : AArch64::LDRXui;
907 case AArch64::FPRRegBankID:
910 return isStore ? AArch64::STRBui : AArch64::LDRBui;
912 return isStore ? AArch64::STRHui : AArch64::LDRHui;
914 return isStore ? AArch64::STRSui : AArch64::LDRSui;
916 return isStore ? AArch64::STRDui : AArch64::LDRDui;
918 return isStore ? AArch64::STRQui : AArch64::LDRQui;
932 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
933 assert(To &&
"Destination register class cannot be null");
940 RegOp.
setReg(SubRegCopy.getReg(0));
944 if (!
I.getOperand(0).getReg().isPhysical())
954static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
958 Register DstReg =
I.getOperand(0).getReg();
959 Register SrcReg =
I.getOperand(1).getReg();
974 if (SrcRegBank != DstRegBank &&
993 if (
Reg.isPhysical())
1001 RC = getRegClassForTypeOnBank(Ty, RB);
1004 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
1017 Register DstReg =
I.getOperand(0).getReg();
1018 Register SrcReg =
I.getOperand(1).getReg();
1037 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1041 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1042 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1053 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1055 }
else if (SrcSize > DstSize) {
1062 }
else if (DstSize > SrcSize) {
1069 Register PromoteReg =
MRI.createVirtualRegister(PromotionRC);
1071 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1076 RegOp.
setReg(PromoteReg);
1095 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1096 I.setDesc(
TII.get(AArch64::COPY));
1097 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1101 I.setDesc(
TII.get(AArch64::COPY));
1109 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1112 "Expected both select operands to have the same regbank?");
1113 LLT Ty =
MRI.getType(True);
1118 "Expected 32 bit or 64 bit select only?");
1119 const bool Is32Bit =
Size == 32;
1121 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1122 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1128 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1130 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &
MRI,
1145 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1162 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1181 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1197 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &
MRI,
1203 if (!TrueCst && !FalseCst)
1206 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1207 if (TrueCst && FalseCst) {
1208 int64_t
T = TrueCst->Value.getSExtValue();
1209 int64_t
F = FalseCst->Value.getSExtValue();
1211 if (
T == 0 &&
F == 1) {
1213 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1219 if (
T == 0 &&
F == -1) {
1221 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1229 int64_t
T = TrueCst->Value.getSExtValue();
1232 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1241 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1250 int64_t
F = FalseCst->Value.getSExtValue();
1253 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1260 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1268 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1269 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1271 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1273 return &*SelectInst;
1278 MachineRegisterInfo *
MRI =
nullptr) {
1291 if (ValAndVReg && ValAndVReg->Value == 0)
1298 if (ValAndVReg && ValAndVReg->Value == 0)
1402 assert(
Reg.isValid() &&
"Expected valid register!");
1403 bool HasZext =
false;
1405 unsigned Opc =
MI->getOpcode();
1407 if (!
MI->getOperand(0).isReg() ||
1408 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1415 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1416 Opc == TargetOpcode::G_TRUNC) {
1417 if (
Opc == TargetOpcode::G_ZEXT)
1420 Register NextReg =
MI->getOperand(1).getReg();
1422 if (!NextReg.
isValid() || !
MRI.hasOneNonDBGUse(NextReg))
1431 std::optional<uint64_t>
C;
1436 case TargetOpcode::G_AND:
1437 case TargetOpcode::G_XOR: {
1438 TestReg =
MI->getOperand(1).getReg();
1439 Register ConstantReg =
MI->getOperand(2).getReg();
1450 C = VRegAndVal->Value.getZExtValue();
1452 C = VRegAndVal->Value.getSExtValue();
1456 case TargetOpcode::G_ASHR:
1457 case TargetOpcode::G_LSHR:
1458 case TargetOpcode::G_SHL: {
1459 TestReg =
MI->getOperand(1).getReg();
1463 C = VRegAndVal->Value.getSExtValue();
1475 unsigned TestRegSize =
MRI.getType(TestReg).getSizeInBits();
1479 case TargetOpcode::G_AND:
1481 if ((*
C >> Bit) & 1)
1484 case TargetOpcode::G_SHL:
1487 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1492 case TargetOpcode::G_ASHR:
1497 if (Bit >= TestRegSize)
1498 Bit = TestRegSize - 1;
1500 case TargetOpcode::G_LSHR:
1502 if ((Bit + *
C) < TestRegSize) {
1507 case TargetOpcode::G_XOR:
1516 if ((*
C >> Bit) & 1)
1531MachineInstr *AArch64InstructionSelector::emitTestBit(
1532 Register TestReg, uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1533 MachineIRBuilder &MIB)
const {
1535 assert(ProduceNonFlagSettingCondBr &&
1536 "Cannot emit TB(N)Z with speculation tracking!");
1537 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1541 LLT Ty =
MRI.getType(TestReg);
1544 assert(Bit < 64 &&
"Bit is too large!");
1548 bool UseWReg =
Bit < 32;
1549 unsigned NecessarySize = UseWReg ? 32 : 64;
1550 if (
Size != NecessarySize)
1551 TestReg = moveScalarRegClass(
1552 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1555 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1556 {AArch64::TBZW, AArch64::TBNZW}};
1557 unsigned Opc = OpcTable[UseWReg][IsNegative];
1564bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1565 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1566 MachineIRBuilder &MIB)
const {
1567 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1594 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1601 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1605MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1607 MachineBasicBlock *DestMBB,
1608 MachineIRBuilder &MIB)
const {
1609 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1610 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1612 AArch64::GPRRegBankID &&
1613 "Expected GPRs only?");
1614 auto Ty =
MRI.getType(CompareReg);
1617 assert(Width <= 64 &&
"Expected width to be at most 64?");
1618 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1619 {AArch64::CBNZW, AArch64::CBNZX}};
1620 unsigned Opc = OpcTable[IsNegative][Width == 64];
1621 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1626bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1627 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1629 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1637 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1641 I.eraseFromParent();
1645bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1646 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1648 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1654 if (!ProduceNonFlagSettingCondBr)
1657 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1658 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1673 if (VRegAndVal && !AndInst) {
1674 int64_t
C = VRegAndVal->Value.getSExtValue();
1679 uint64_t
Bit =
MRI.getType(
LHS).getSizeInBits() - 1;
1680 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1681 I.eraseFromParent();
1688 uint64_t
Bit =
MRI.getType(
LHS).getSizeInBits() - 1;
1689 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1690 I.eraseFromParent();
1697 uint64_t
Bit =
MRI.getType(
LHS).getSizeInBits() - 1;
1698 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1699 I.eraseFromParent();
1713 if (VRegAndVal && VRegAndVal->Value == 0) {
1721 tryOptAndIntoCompareBranch(
1723 I.eraseFromParent();
1728 auto LHSTy =
MRI.getType(
LHS);
1729 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1731 I.eraseFromParent();
1740bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1741 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1743 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1744 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1748 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1755 I.eraseFromParent();
1759bool AArch64InstructionSelector::selectCompareBranch(
1760 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &
MRI) {
1761 Register CondReg =
I.getOperand(0).getReg();
1762 MachineInstr *CCMI =
MRI.getVRegDef(CondReg);
1766 if (CCMIOpc == TargetOpcode::G_FCMP)
1767 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1768 if (CCMIOpc == TargetOpcode::G_ICMP)
1769 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1774 if (ProduceNonFlagSettingCondBr) {
1775 emitTestBit(CondReg, 0,
true,
1776 I.getOperand(1).getMBB(), MIB);
1777 I.eraseFromParent();
1787 .
addMBB(
I.getOperand(1).getMBB());
1788 I.eraseFromParent();
1796 assert(
MRI.getType(
Reg).isVector() &&
"Expected a *vector* shift operand");
1807 return std::nullopt;
1809 int64_t Imm = *ShiftImm;
1811 return std::nullopt;
1812 switch (SrcTy.getElementType().getSizeInBits()) {
1815 return std::nullopt;
1818 return std::nullopt;
1822 return std::nullopt;
1826 return std::nullopt;
1830 return std::nullopt;
1836bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1837 MachineRegisterInfo &
MRI) {
1838 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1839 Register DstReg =
I.getOperand(0).getReg();
1840 const LLT Ty =
MRI.getType(DstReg);
1841 Register Src1Reg =
I.getOperand(1).getReg();
1842 Register Src2Reg =
I.getOperand(2).getReg();
1853 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1855 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1857 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1859 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1861 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1863 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1865 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1877 I.eraseFromParent();
1881bool AArch64InstructionSelector::selectVectorAshrLshr(
1882 MachineInstr &
I, MachineRegisterInfo &
MRI) {
1883 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1884 I.getOpcode() == TargetOpcode::G_LSHR);
1885 Register DstReg =
I.getOperand(0).getReg();
1886 const LLT Ty =
MRI.getType(DstReg);
1887 Register Src1Reg =
I.getOperand(1).getReg();
1888 Register Src2Reg =
I.getOperand(2).getReg();
1893 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1903 unsigned NegOpc = 0;
1904 const TargetRegisterClass *RC =
1905 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1907 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1908 NegOpc = AArch64::NEGv2i64;
1910 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1911 NegOpc = AArch64::NEGv4i32;
1913 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1914 NegOpc = AArch64::NEGv2i32;
1916 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1917 NegOpc = AArch64::NEGv4i16;
1919 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1920 NegOpc = AArch64::NEGv8i16;
1922 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1923 NegOpc = AArch64::NEGv16i8;
1925 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1926 NegOpc = AArch64::NEGv8i8;
1932 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1936 I.eraseFromParent();
1940bool AArch64InstructionSelector::selectVaStartAAPCS(
1941 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &
MRI)
const {
1950 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1952 const auto *PtrRegClass =
1953 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1955 const MCInstrDesc &MCIDAddAddr =
1957 const MCInstrDesc &MCIDStoreAddr =
1969 const auto VAList =
I.getOperand(0).getReg();
1972 unsigned OffsetBytes = 0;
1976 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1977 const Register Top =
MRI.createVirtualRegister(PtrRegClass);
1978 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1985 const auto *MMO = *
I.memoperands_begin();
1986 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1989 .
addImm(OffsetBytes / PtrSize)
1991 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1995 OffsetBytes += PtrSize;
2011 const auto PushIntConstant = [&](
const int32_t
Value) {
2012 constexpr int IntSize = 4;
2013 const Register Temp =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2015 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
2020 const auto *MMO = *
I.memoperands_begin();
2021 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
2024 .
addImm(OffsetBytes / IntSize)
2026 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2029 OffsetBytes += IntSize;
2033 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2036 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2040 I.eraseFromParent();
2044bool AArch64InstructionSelector::selectVaStartDarwin(
2045 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &
MRI)
const {
2046 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2047 Register ListReg =
I.getOperand(0).getReg();
2049 Register ArgsAddrReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2052 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2060 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2068 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2075 I.eraseFromParent();
2079void AArch64InstructionSelector::materializeLargeCMVal(
2080 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2085 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2096 :
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2100 GV, MovZ->getOperand(1).getOffset(), Flags));
2104 MovZ->getOperand(1).getOffset(), Flags));
2110 Register DstReg = BuildMovK(MovZ.getReg(0),
2116bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2121 switch (
I.getOpcode()) {
2122 case TargetOpcode::G_STORE: {
2123 bool Changed = contractCrossBankCopyIntoStore(
I,
MRI);
2124 MachineOperand &SrcOp =
I.getOperand(0);
2125 if (
MRI.getType(SrcOp.
getReg()).isPointer()) {
2137 case TargetOpcode::G_PTR_ADD: {
2141 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2143 return convertPtrAddToAdd(
I,
MRI);
2145 case TargetOpcode::G_LOAD: {
2150 Register DstReg =
I.getOperand(0).getReg();
2151 const LLT DstTy =
MRI.getType(DstReg);
2157 case AArch64::G_DUP: {
2159 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2163 MRI.setType(
I.getOperand(0).getReg(),
2165 MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2166 I.getOperand(1).setReg(NewSrc.getReg(0));
2169 case AArch64::G_INSERT_VECTOR_ELT: {
2171 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2172 LLT SrcVecTy =
MRI.getType(
I.getOperand(1).getReg());
2176 MRI.setType(
I.getOperand(1).getReg(),
2178 MRI.setType(
I.getOperand(0).getReg(),
2180 MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2181 I.getOperand(2).setReg(NewSrc.getReg(0));
2184 case TargetOpcode::G_UITOFP:
2185 case TargetOpcode::G_SITOFP: {
2190 Register SrcReg =
I.getOperand(1).getReg();
2191 LLT SrcTy =
MRI.getType(SrcReg);
2192 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2197 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2198 I.setDesc(
TII.get(AArch64::G_SITOF));
2200 I.setDesc(
TII.get(AArch64::G_UITOF));
2218bool AArch64InstructionSelector::convertPtrAddToAdd(
2219 MachineInstr &
I, MachineRegisterInfo &
MRI) {
2220 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2221 Register DstReg =
I.getOperand(0).getReg();
2222 Register AddOp1Reg =
I.getOperand(1).getReg();
2223 const LLT PtrTy =
MRI.getType(DstReg);
2227 const LLT CastPtrTy =
2232 MRI.setRegBank(PtrToInt.getReg(0), RBI.
getRegBank(AArch64::FPRRegBankID));
2234 MRI.setRegBank(PtrToInt.getReg(0), RBI.
getRegBank(AArch64::GPRRegBankID));
2238 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2239 MRI.setType(DstReg, CastPtrTy);
2240 I.getOperand(1).setReg(PtrToInt.getReg(0));
2241 if (!select(*PtrToInt)) {
2242 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2251 I.getOperand(2).setReg(NegatedReg);
2252 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2256bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2257 MachineRegisterInfo &
MRI) {
2261 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2262 const auto &MO =
I.getOperand(2);
2267 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2271 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2272 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2274 if (!Imm1Fn || !Imm2Fn)
2278 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2279 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2281 for (
auto &RenderFn : *Imm1Fn)
2283 for (
auto &RenderFn : *Imm2Fn)
2286 I.eraseFromParent();
2290bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2291 MachineInstr &
I, MachineRegisterInfo &
MRI) {
2292 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2310 LLT DefDstTy =
MRI.getType(DefDstReg);
2311 Register StoreSrcReg =
I.getOperand(0).getReg();
2312 LLT StoreSrcTy =
MRI.getType(StoreSrcReg);
2328 I.getOperand(0).setReg(DefDstReg);
2332bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2333 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2334 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2340 switch (
I.getOpcode()) {
2341 case AArch64::G_DUP: {
2344 Register Src =
I.getOperand(1).getReg();
2349 Register Dst =
I.getOperand(0).getReg();
2351 MRI.getType(Dst).getNumElements(),
2353 Type::getIntNTy(Ctx,
MRI.getType(Dst).getScalarSizeInBits()),
2354 ValAndVReg->Value.trunc(
MRI.getType(Dst).getScalarSizeInBits())));
2355 if (!emitConstantVector(Dst, CV, MIB,
MRI))
2357 I.eraseFromParent();
2360 case TargetOpcode::G_SEXT:
2363 if (selectUSMovFromExtend(
I,
MRI))
2366 case TargetOpcode::G_BR:
2368 case TargetOpcode::G_SHL:
2369 return earlySelectSHL(
I,
MRI);
2370 case TargetOpcode::G_CONSTANT: {
2371 bool IsZero =
false;
2372 if (
I.getOperand(1).isCImm())
2373 IsZero =
I.getOperand(1).getCImm()->isZero();
2374 else if (
I.getOperand(1).isImm())
2375 IsZero =
I.getOperand(1).getImm() == 0;
2380 Register DefReg =
I.getOperand(0).getReg();
2381 LLT Ty =
MRI.getType(DefReg);
2383 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2386 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2391 I.setDesc(
TII.get(TargetOpcode::COPY));
2395 case TargetOpcode::G_ADD: {
2404 Register AddDst =
I.getOperand(0).getReg();
2405 Register AddLHS =
I.getOperand(1).getReg();
2406 Register AddRHS =
I.getOperand(2).getReg();
2408 LLT Ty =
MRI.getType(AddLHS);
2416 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2417 if (!
MRI.hasOneNonDBGUse(
Reg))
2431 MRI.getType(
Cmp->getOperand(2).getReg()).getSizeInBits() != 64)
2437 MachineInstr *
Cmp = MatchCmp(AddRHS);
2441 Cmp = MatchCmp(AddRHS);
2445 auto &PredOp =
Cmp->getOperand(1);
2447 emitIntegerCompare(
Cmp->getOperand(2),
2448 Cmp->getOperand(3), PredOp, MIB);
2452 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2453 I.eraseFromParent();
2456 case TargetOpcode::G_OR: {
2460 Register Dst =
I.getOperand(0).getReg();
2461 LLT Ty =
MRI.getType(Dst);
2480 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2483 int64_t Immr =
Size - ShiftImm;
2484 int64_t Imms =
Size - ShiftImm - 1;
2485 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2486 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2487 I.eraseFromParent();
2490 case TargetOpcode::G_FENCE: {
2491 if (
I.getOperand(1).getImm() == 0)
2495 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2496 I.eraseFromParent();
2504bool AArch64InstructionSelector::select(MachineInstr &
I) {
2505 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2506 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2512 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2513 if (Subtarget->requiresStrictAlign()) {
2515 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2521 unsigned Opcode =
I.getOpcode();
2523 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2526 if (Opcode == TargetOpcode::LOAD_STACK_GUARD)
2529 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2530 const Register DefReg =
I.getOperand(0).getReg();
2531 const LLT DefTy =
MRI.getType(DefReg);
2534 MRI.getRegClassOrRegBank(DefReg);
2536 const TargetRegisterClass *DefRC =
2544 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2551 I.setDesc(
TII.get(TargetOpcode::PHI));
2559 if (
I.isDebugInstr())
2566 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2568 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2575 if (preISelLower(
I)) {
2576 Opcode =
I.getOpcode();
2587 if (selectImpl(
I, *CoverageInfo))
2591 I.getOperand(0).isReg() ?
MRI.getType(
I.getOperand(0).getReg()) : LLT{};
2594 case TargetOpcode::G_SBFX:
2595 case TargetOpcode::G_UBFX: {
2596 static const unsigned OpcTable[2][2] = {
2597 {AArch64::UBFMWri, AArch64::UBFMXri},
2598 {AArch64::SBFMWri, AArch64::SBFMXri}};
2599 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2601 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2604 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2607 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2608 auto LSB = Cst1->Value.getZExtValue();
2609 auto Width = Cst2->Value.getZExtValue();
2613 .
addImm(LSB + Width - 1);
2614 I.eraseFromParent();
2617 case TargetOpcode::G_BRCOND:
2618 return selectCompareBranch(
I, MF,
MRI);
2620 case TargetOpcode::G_BRINDIRECT: {
2622 if (std::optional<uint16_t> BADisc =
2624 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2627 MI.addReg(AArch64::XZR);
2628 I.eraseFromParent();
2631 I.setDesc(
TII.get(AArch64::BR));
2635 case TargetOpcode::G_BRJT:
2636 return selectBrJT(
I,
MRI);
2638 case AArch64::G_ADD_LOW: {
2643 MachineInstr *BaseMI =
MRI.getVRegDef(
I.getOperand(1).getReg());
2644 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2645 I.setDesc(
TII.get(AArch64::ADDXri));
2650 "Expected small code model");
2652 auto Op2 =
I.getOperand(2);
2653 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2654 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2655 Op1.getTargetFlags())
2657 Op2.getTargetFlags());
2658 I.eraseFromParent();
2662 case TargetOpcode::G_FCONSTANT:
2663 case TargetOpcode::G_CONSTANT: {
2664 const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
2673 const Register DefReg =
I.getOperand(0).getReg();
2674 const LLT DefTy =
MRI.getType(DefReg);
2680 if (Ty != s16 && Ty != s32 && Ty != s64 && Ty != s128) {
2682 <<
" constant, expected: " << s16 <<
" or " << s32
2683 <<
" or " << s64 <<
" or " << s128 <<
'\n');
2687 if (RB.
getID() != AArch64::FPRRegBankID) {
2689 <<
" constant on bank: " << RB
2690 <<
", expected: FPR\n");
2698 if (DefSize != 128 &&
I.getOperand(1).getFPImm()->isExactlyValue(0.0))
2702 if (Ty != p0 && Ty != s8 && Ty != s16) {
2704 <<
" constant, expected: " << s32 <<
", " << s64
2705 <<
", or " << p0 <<
'\n');
2709 if (RB.
getID() != AArch64::GPRRegBankID) {
2711 <<
" constant on bank: " << RB
2712 <<
", expected: GPR\n");
2718 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2725 bool OptForSize = shouldOptForSize(&MF);
2729 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2736 auto *FPImm =
I.getOperand(1).getFPImm();
2739 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2742 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2743 I.eraseFromParent();
2748 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2750 const Register DefGPRReg =
MRI.createVirtualRegister(
2751 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2752 MachineOperand &RegOp =
I.getOperand(0);
2758 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2762 MachineOperand &ImmOp =
I.getOperand(1);
2766 }
else if (
I.getOperand(1).isCImm()) {
2767 uint64_t Val =
I.getOperand(1).getCImm()->getZExtValue();
2768 I.getOperand(1).ChangeToImmediate(Val);
2769 }
else if (
I.getOperand(1).isImm()) {
2770 uint64_t Val =
I.getOperand(1).getImm();
2771 I.getOperand(1).ChangeToImmediate(Val);
2774 const unsigned MovOpc =
2775 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2776 I.setDesc(
TII.get(MovOpc));
2780 case TargetOpcode::G_EXTRACT: {
2781 Register DstReg =
I.getOperand(0).getReg();
2782 Register SrcReg =
I.getOperand(1).getReg();
2783 LLT SrcTy =
MRI.getType(SrcReg);
2784 LLT DstTy =
MRI.getType(DstReg);
2796 unsigned Offset =
I.getOperand(2).getImm();
2805 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2807 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2809 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2811 AArch64::GPR64RegClass, NewI->getOperand(0));
2812 I.eraseFromParent();
2818 unsigned LaneIdx =
Offset / 64;
2819 MachineInstr *Extract = emitExtractVectorElt(
2820 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2823 I.eraseFromParent();
2827 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2828 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2833 "unexpected G_EXTRACT types");
2839 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2840 .addReg(DstReg, 0, AArch64::sub_32);
2842 AArch64::GPR32RegClass,
MRI);
2843 I.getOperand(0).setReg(DstReg);
2848 case TargetOpcode::G_INSERT: {
2849 LLT SrcTy =
MRI.getType(
I.getOperand(2).getReg());
2850 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2857 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2858 unsigned LSB =
I.getOperand(3).getImm();
2859 unsigned Width =
MRI.getType(
I.getOperand(2).getReg()).getSizeInBits();
2860 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2861 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2865 "unexpected G_INSERT types");
2871 TII.get(AArch64::SUBREG_TO_REG))
2874 .
addUse(
I.getOperand(2).getReg())
2875 .
addImm(AArch64::sub_32);
2877 AArch64::GPR32RegClass,
MRI);
2878 I.getOperand(2).setReg(SrcReg);
2882 case TargetOpcode::G_FRAME_INDEX: {
2889 I.setDesc(
TII.get(AArch64::ADDXri));
2898 case TargetOpcode::G_GLOBAL_VALUE: {
2899 const GlobalValue *GV =
nullptr;
2901 if (
I.getOperand(1).isSymbol()) {
2902 OpFlags =
I.getOperand(1).getTargetFlags();
2911 return selectTLSGlobalValue(
I,
MRI);
2917 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2918 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2919 I.getOperand(1).setTargetFlags(OpFlags);
2920 I.addImplicitDefUseOperands(MF);
2924 materializeLargeCMVal(
I, GV, OpFlags);
2925 I.eraseFromParent();
2928 I.setDesc(
TII.get(AArch64::ADR));
2929 I.getOperand(1).setTargetFlags(OpFlags);
2931 I.setDesc(
TII.get(AArch64::MOVaddr));
2933 MachineInstrBuilder MIB(MF,
I);
2934 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2940 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2941 return selectPtrAuthGlobalValue(
I,
MRI);
2943 case TargetOpcode::G_ZEXTLOAD:
2944 case TargetOpcode::G_LOAD:
2945 case TargetOpcode::G_STORE: {
2947 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2962 assert(MemSizeInBytes <= 8 &&
2963 "128-bit atomics should already be custom-legalized");
2966 static constexpr unsigned LDAPROpcodes[] = {
2967 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2968 static constexpr unsigned LDAROpcodes[] = {
2969 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2970 ArrayRef<unsigned> Opcodes =
2971 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2974 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2976 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2977 AArch64::STLRW, AArch64::STLRX};
2979 if (
MRI.getType(ValReg).getSizeInBits() == 64 && MemSizeInBits != 64) {
2981 Register NewVal =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2982 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2983 .addReg(
I.getOperand(0).getReg(), 0, AArch64::sub_32);
2984 I.getOperand(0).setReg(NewVal);
2986 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2997 "Load/Store pointer operand isn't a GPR");
2998 assert(
MRI.getType(PtrReg).isPointer() &&
2999 "Load/Store pointer operand isn't a pointer");
3004 LLT ValTy =
MRI.getType(ValReg);
3011 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3017 .addReg(ValReg, 0,
SubReg)
3024 if (RB.
getID() == AArch64::FPRRegBankID) {
3027 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3034 MRI.setRegBank(NewDst, RB);
3037 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3041 auto SubRegRC = getRegClassForTypeOnBank(
MRI.getType(OldDst), RB);
3050 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3052 const unsigned NewOpc =
3054 if (NewOpc ==
I.getOpcode())
3058 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3061 I.setDesc(
TII.get(NewOpc));
3067 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3068 Register CurValReg =
I.getOperand(0).getReg();
3069 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3070 NewInst.cloneMemRefs(
I);
3071 for (
auto &Fn : *AddrModeFns)
3073 I.eraseFromParent();
3077 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3082 if (Opcode == TargetOpcode::G_STORE) {
3085 if (CVal && CVal->Value == 0) {
3087 case AArch64::STRWui:
3088 case AArch64::STRHHui:
3089 case AArch64::STRBBui:
3090 LoadStore->getOperand(0).setReg(AArch64::WZR);
3092 case AArch64::STRXui:
3093 LoadStore->getOperand(0).setReg(AArch64::XZR);
3099 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3100 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3103 if (
MRI.getType(
LoadStore->getOperand(0).getReg()).getSizeInBits() != 64)
3107 Register LdReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3112 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3115 .
addImm(AArch64::sub_32);
3123 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3124 case TargetOpcode::G_INDEXED_SEXTLOAD:
3125 return selectIndexedExtLoad(
I,
MRI);
3126 case TargetOpcode::G_INDEXED_LOAD:
3127 return selectIndexedLoad(
I,
MRI);
3128 case TargetOpcode::G_INDEXED_STORE:
3131 case TargetOpcode::G_LSHR:
3132 case TargetOpcode::G_ASHR:
3133 if (
MRI.getType(
I.getOperand(0).getReg()).isVector())
3134 return selectVectorAshrLshr(
I,
MRI);
3136 case TargetOpcode::G_SHL:
3137 if (Opcode == TargetOpcode::G_SHL &&
3138 MRI.getType(
I.getOperand(0).getReg()).isVector())
3139 return selectVectorSHL(
I,
MRI);
3146 Register SrcReg =
I.getOperand(1).getReg();
3147 Register ShiftReg =
I.getOperand(2).getReg();
3148 const LLT ShiftTy =
MRI.getType(ShiftReg);
3149 const LLT SrcTy =
MRI.getType(SrcReg);
3154 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3155 .addReg(ShiftReg, 0, AArch64::sub_32);
3156 MRI.setRegBank(Trunc.getReg(0), RBI.
getRegBank(AArch64::GPRRegBankID));
3157 I.getOperand(2).setReg(Trunc.getReg(0));
3161 case TargetOpcode::G_OR: {
3168 const Register DefReg =
I.getOperand(0).getReg();
3172 if (NewOpc ==
I.getOpcode())
3175 I.setDesc(
TII.get(NewOpc));
3183 case TargetOpcode::G_PTR_ADD: {
3184 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3185 I.eraseFromParent();
3189 case TargetOpcode::G_SADDE:
3190 case TargetOpcode::G_UADDE:
3191 case TargetOpcode::G_SSUBE:
3192 case TargetOpcode::G_USUBE:
3193 case TargetOpcode::G_SADDO:
3194 case TargetOpcode::G_UADDO:
3195 case TargetOpcode::G_SSUBO:
3196 case TargetOpcode::G_USUBO:
3197 return selectOverflowOp(
I,
MRI);
3199 case TargetOpcode::G_PTRMASK: {
3200 Register MaskReg =
I.getOperand(2).getReg();
3206 uint64_t
Mask = *MaskVal;
3207 I.setDesc(
TII.get(AArch64::ANDXri));
3208 I.getOperand(2).ChangeToImmediate(
3213 case TargetOpcode::G_PTRTOINT:
3214 case TargetOpcode::G_TRUNC: {
3215 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3216 const LLT SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3218 const Register DstReg =
I.getOperand(0).getReg();
3219 const Register SrcReg =
I.getOperand(1).getReg();
3226 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3230 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3231 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3235 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3241 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3245 if (DstRC == SrcRC) {
3247 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3251 }
else if (DstRC == &AArch64::GPR32RegClass &&
3252 SrcRC == &AArch64::GPR64RegClass) {
3253 I.getOperand(1).setSubReg(AArch64::sub_32);
3256 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3260 I.setDesc(
TII.get(TargetOpcode::COPY));
3262 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3265 I.setDesc(
TII.get(AArch64::XTNv4i16));
3271 MachineInstr *Extract = emitExtractVectorElt(
3275 I.eraseFromParent();
3280 if (Opcode == TargetOpcode::G_PTRTOINT) {
3281 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3282 I.setDesc(
TII.get(TargetOpcode::COPY));
3290 case TargetOpcode::G_ANYEXT: {
3291 if (selectUSMovFromExtend(
I,
MRI))
3294 const Register DstReg =
I.getOperand(0).getReg();
3295 const Register SrcReg =
I.getOperand(1).getReg();
3298 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3300 <<
", expected: GPR\n");
3305 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3307 <<
", expected: GPR\n");
3311 const unsigned DstSize =
MRI.getType(DstReg).getSizeInBits();
3314 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3318 if (DstSize != 64 && DstSize > 32) {
3320 <<
", expected: 32 or 64\n");
3326 Register ExtSrc =
MRI.createVirtualRegister(&AArch64::GPR64allRegClass);
3331 .
addImm(AArch64::sub_32);
3332 I.getOperand(1).setReg(ExtSrc);
3337 case TargetOpcode::G_ZEXT:
3338 case TargetOpcode::G_SEXT_INREG:
3339 case TargetOpcode::G_SEXT: {
3340 if (selectUSMovFromExtend(
I,
MRI))
3343 unsigned Opcode =
I.getOpcode();
3344 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3345 const Register DefReg =
I.getOperand(0).getReg();
3346 Register SrcReg =
I.getOperand(1).getReg();
3347 const LLT DstTy =
MRI.getType(DefReg);
3348 const LLT SrcTy =
MRI.getType(SrcReg);
3354 if (Opcode == TargetOpcode::G_SEXT_INREG)
3355 SrcSize =
I.getOperand(2).getImm();
3361 AArch64::GPRRegBankID &&
3362 "Unexpected ext regbank");
3376 if (LoadMI && IsGPR) {
3377 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3378 unsigned BytesLoaded = MemOp->getSize().getValue();
3385 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3387 MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3388 const Register ZReg = AArch64::WZR;
3389 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3392 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3395 .
addImm(AArch64::sub_32);
3399 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3409 I.eraseFromParent();
3414 if (DstSize == 64) {
3415 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3423 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3424 {&AArch64::GPR64RegClass}, {})
3431 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3435 }
else if (DstSize <= 32) {
3436 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3445 I.eraseFromParent();
3449 case TargetOpcode::G_FREEZE:
3452 case TargetOpcode::G_INTTOPTR:
3457 case TargetOpcode::G_BITCAST:
3465 case TargetOpcode::G_SELECT: {
3467 const Register CondReg = Sel.getCondReg();
3469 const Register FReg = Sel.getFalseReg();
3471 if (tryOptSelect(Sel))
3476 Register DeadVReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3477 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3480 if (!emitSelect(Sel.getReg(0), TReg, FReg,
AArch64CC::NE, MIB))
3482 Sel.eraseFromParent();
3485 case TargetOpcode::G_ICMP: {
3495 auto &PredOp =
I.getOperand(1);
3496 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3500 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3501 AArch64::WZR, InvCC, MIB);
3502 I.eraseFromParent();
3506 case TargetOpcode::G_FCMP: {
3509 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3511 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3513 I.eraseFromParent();
3516 case TargetOpcode::G_VASTART:
3518 : selectVaStartAAPCS(
I, MF,
MRI);
3519 case TargetOpcode::G_INTRINSIC:
3520 return selectIntrinsic(
I,
MRI);
3521 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3522 return selectIntrinsicWithSideEffects(
I,
MRI);
3523 case TargetOpcode::G_IMPLICIT_DEF: {
3524 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3525 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3526 const Register DstReg =
I.getOperand(0).getReg();
3528 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3532 case TargetOpcode::G_BLOCK_ADDR: {
3533 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3534 if (std::optional<uint16_t> BADisc =
3536 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3537 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3546 AArch64::GPR64RegClass,
MRI);
3547 I.eraseFromParent();
3551 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3552 I.eraseFromParent();
3555 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3556 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3557 I.getOperand(0).getReg())
3561 I.getOperand(1).getBlockAddress(), 0,
3563 I.eraseFromParent();
3567 case AArch64::G_DUP: {
3574 AArch64::GPRRegBankID)
3576 LLT VecTy =
MRI.getType(
I.getOperand(0).getReg());
3578 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3580 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3582 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3584 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3589 case TargetOpcode::G_BUILD_VECTOR:
3590 return selectBuildVector(
I,
MRI);
3591 case TargetOpcode::G_MERGE_VALUES:
3593 case TargetOpcode::G_UNMERGE_VALUES:
3595 case TargetOpcode::G_SHUFFLE_VECTOR:
3596 return selectShuffleVector(
I,
MRI);
3597 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3598 return selectExtractElt(
I,
MRI);
3599 case TargetOpcode::G_CONCAT_VECTORS:
3600 return selectConcatVectors(
I,
MRI);
3601 case TargetOpcode::G_JUMP_TABLE:
3602 return selectJumpTable(
I,
MRI);
3603 case TargetOpcode::G_MEMCPY:
3604 case TargetOpcode::G_MEMCPY_INLINE:
3605 case TargetOpcode::G_MEMMOVE:
3606 case TargetOpcode::G_MEMSET:
3607 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3608 return selectMOPS(
I,
MRI);
3614bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3615 MachineIRBuilderState OldMIBState = MIB.
getState();
3621bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3622 MachineRegisterInfo &
MRI) {
3625 case TargetOpcode::G_MEMCPY:
3626 case TargetOpcode::G_MEMCPY_INLINE:
3627 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3629 case TargetOpcode::G_MEMMOVE:
3630 Mopcode = AArch64::MOPSMemoryMovePseudo;
3632 case TargetOpcode::G_MEMSET:
3634 Mopcode = AArch64::MOPSMemorySetPseudo;
3643 const Register DstPtrCopy =
MRI.cloneVirtualRegister(DstPtr.getReg());
3644 const Register SrcValCopy =
MRI.cloneVirtualRegister(SrcOrVal.getReg());
3647 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3648 const auto &SrcValRegClass =
3649 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3664 Register DefDstPtr =
MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
3665 Register DefSize =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3667 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3668 {DstPtrCopy, SizeCopy, SrcValCopy});
3670 Register DefSrcPtr =
MRI.createVirtualRegister(&SrcValRegClass);
3671 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3672 {DstPtrCopy, SrcValCopy, SizeCopy});
3679bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3680 MachineRegisterInfo &
MRI) {
3681 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3682 Register JTAddr =
I.getOperand(0).getReg();
3683 unsigned JTI =
I.getOperand(1).getIndex();
3686 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3698 "jump table hardening only supported on MachO/ELF");
3706 I.eraseFromParent();
3710 Register TargetReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3711 Register ScratchReg =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
3713 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3714 {TargetReg, ScratchReg}, {JTAddr,
Index})
3715 .addJumpTableIndex(JTI);
3717 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3718 {
static_cast<int64_t
>(JTI)});
3720 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3721 I.eraseFromParent();
3725bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3726 MachineRegisterInfo &
MRI) {
3727 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3728 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3730 Register DstReg =
I.getOperand(0).getReg();
3731 unsigned JTI =
I.getOperand(1).getIndex();
3734 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3737 I.eraseFromParent();
3741bool AArch64InstructionSelector::selectTLSGlobalValue(
3742 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3745 MachineFunction &MF = *
I.getParent()->getParent();
3748 const auto &GlobalOp =
I.getOperand(1);
3749 assert(GlobalOp.getOffset() == 0 &&
3750 "Shouldn't have an offset on TLS globals!");
3751 const GlobalValue &GV = *GlobalOp.getGlobal();
3754 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3757 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3758 {LoadGOT.getReg(0)})
3769 assert(Opcode == AArch64::BLR);
3770 Opcode = AArch64::BLRAAZ;
3781 I.eraseFromParent();
3785MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3786 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3787 MachineIRBuilder &MIRBuilder)
const {
3788 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3790 auto BuildFn = [&](
unsigned SubregIndex) {
3794 .addImm(SubregIndex);
3802 return BuildFn(AArch64::bsub);
3804 return BuildFn(AArch64::hsub);
3806 return BuildFn(AArch64::ssub);
3808 return BuildFn(AArch64::dsub);
3815AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3816 MachineIRBuilder &MIB,
3817 MachineRegisterInfo &
MRI)
const {
3818 LLT DstTy =
MRI.getType(DstReg);
3819 const TargetRegisterClass *RC =
3821 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3828 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
3834 .addReg(SrcReg, 0,
SubReg);
3839bool AArch64InstructionSelector::selectMergeValues(
3840 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3841 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3842 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3843 const LLT SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3847 if (
I.getNumOperands() != 3)
3854 Register DstReg =
I.getOperand(0).getReg();
3855 Register Src1Reg =
I.getOperand(1).getReg();
3856 Register Src2Reg =
I.getOperand(2).getReg();
3857 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3858 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3862 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3863 Src2Reg, 1, RB, MIB);
3868 I.eraseFromParent();
3872 if (RB.
getID() != AArch64::GPRRegBankID)
3878 auto *DstRC = &AArch64::GPR64RegClass;
3879 Register SubToRegDef =
MRI.createVirtualRegister(DstRC);
3880 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3881 TII.get(TargetOpcode::SUBREG_TO_REG))
3884 .
addUse(
I.getOperand(1).getReg())
3885 .
addImm(AArch64::sub_32);
3886 Register SubToRegDef2 =
MRI.createVirtualRegister(DstRC);
3888 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3889 TII.get(TargetOpcode::SUBREG_TO_REG))
3892 .
addUse(
I.getOperand(2).getReg())
3893 .
addImm(AArch64::sub_32);
3895 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3896 .
addDef(
I.getOperand(0).getReg())
3904 I.eraseFromParent();
3909 const unsigned EltSize) {
3914 CopyOpc = AArch64::DUPi8;
3915 ExtractSubReg = AArch64::bsub;
3918 CopyOpc = AArch64::DUPi16;
3919 ExtractSubReg = AArch64::hsub;
3922 CopyOpc = AArch64::DUPi32;
3923 ExtractSubReg = AArch64::ssub;
3926 CopyOpc = AArch64::DUPi64;
3927 ExtractSubReg = AArch64::dsub;
3931 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3937MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3938 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3939 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3940 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
3941 unsigned CopyOpc = 0;
3942 unsigned ExtractSubReg = 0;
3945 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3949 const TargetRegisterClass *DstRC =
3950 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3952 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3957 const LLT &VecTy =
MRI.getType(VecReg);
3958 const TargetRegisterClass *VecRC =
3959 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3961 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3968 DstReg =
MRI.createVirtualRegister(DstRC);
3971 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3972 .addReg(VecReg, 0, ExtractSubReg);
3981 MachineInstr *ScalarToVector = emitScalarToVector(
3982 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3983 if (!ScalarToVector)
3988 MachineInstr *LaneCopyMI =
3989 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3997bool AArch64InstructionSelector::selectExtractElt(
3998 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3999 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4000 "unexpected opcode!");
4001 Register DstReg =
I.getOperand(0).getReg();
4002 const LLT NarrowTy =
MRI.getType(DstReg);
4003 const Register SrcReg =
I.getOperand(1).getReg();
4004 const LLT WideTy =
MRI.getType(SrcReg);
4007 "source register size too small!");
4008 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4011 MachineOperand &LaneIdxOp =
I.getOperand(2);
4012 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4023 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4027 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4032 I.eraseFromParent();
4036bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4037 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4038 unsigned NumElts =
I.getNumOperands() - 1;
4039 Register SrcReg =
I.getOperand(NumElts).getReg();
4040 const LLT NarrowTy =
MRI.getType(
I.getOperand(0).getReg());
4041 const LLT SrcTy =
MRI.getType(SrcReg);
4043 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4045 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4051 const RegisterBank &DstRB =
4055 MachineInstr *Extract =
4056 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4060 I.eraseFromParent();
4064bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4065 MachineRegisterInfo &
MRI) {
4066 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4067 "unexpected opcode");
4071 AArch64::FPRRegBankID ||
4073 AArch64::FPRRegBankID) {
4074 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4075 "currently unsupported.\n");
4081 unsigned NumElts =
I.getNumOperands() - 1;
4082 Register SrcReg =
I.getOperand(NumElts).getReg();
4083 const LLT NarrowTy =
MRI.getType(
I.getOperand(0).getReg());
4084 const LLT WideTy =
MRI.getType(SrcReg);
4087 "can only unmerge from vector or s128 types!");
4089 "source register size too small!");
4092 return selectSplitVectorUnmerge(
I,
MRI);
4096 unsigned CopyOpc = 0;
4097 unsigned ExtractSubReg = 0;
4108 unsigned NumInsertRegs = NumElts - 1;
4118 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4124 assert(Found &&
"expected to find last operand's subeg idx");
4125 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4126 Register ImpDefReg =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
4127 MachineInstr &ImpDefMI =
4128 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4132 Register InsertReg =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
4133 MachineInstr &InsMI =
4135 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4152 Register CopyTo =
I.getOperand(0).getReg();
4153 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4154 .addReg(InsertRegs[0], 0, ExtractSubReg);
4158 unsigned LaneIdx = 1;
4159 for (
Register InsReg : InsertRegs) {
4160 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4161 MachineInstr &CopyInst =
4172 const TargetRegisterClass *RC =
4173 MRI.getRegClassOrNull(
I.getOperand(1).getReg());
4180 I.eraseFromParent();
4184bool AArch64InstructionSelector::selectConcatVectors(
4185 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4186 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4187 "Unexpected opcode");
4188 Register Dst =
I.getOperand(0).getReg();
4189 Register Op1 =
I.getOperand(1).getReg();
4190 Register Op2 =
I.getOperand(2).getReg();
4191 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4194 I.eraseFromParent();
4199AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4200 MachineFunction &MF)
const {
4208MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4209 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4210 const TargetRegisterClass *RC;
4216 RC = &AArch64::FPR128RegClass;
4217 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4220 RC = &AArch64::FPR64RegClass;
4221 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4224 RC = &AArch64::FPR32RegClass;
4225 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4228 RC = &AArch64::FPR16RegClass;
4229 Opc = AArch64::LDRHui;
4232 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4237 MachineInstr *LoadMI =
nullptr;
4238 auto &MF = MIRBuilder.
getMF();
4239 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4240 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4242 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4245 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4249 .addConstantPoolIndex(
4265static std::pair<unsigned, unsigned>
4267 unsigned Opc, SubregIdx;
4268 if (RB.
getID() == AArch64::GPRRegBankID) {
4270 Opc = AArch64::INSvi8gpr;
4271 SubregIdx = AArch64::bsub;
4272 }
else if (EltSize == 16) {
4273 Opc = AArch64::INSvi16gpr;
4274 SubregIdx = AArch64::ssub;
4275 }
else if (EltSize == 32) {
4276 Opc = AArch64::INSvi32gpr;
4277 SubregIdx = AArch64::ssub;
4278 }
else if (EltSize == 64) {
4279 Opc = AArch64::INSvi64gpr;
4280 SubregIdx = AArch64::dsub;
4286 Opc = AArch64::INSvi8lane;
4287 SubregIdx = AArch64::bsub;
4288 }
else if (EltSize == 16) {
4289 Opc = AArch64::INSvi16lane;
4290 SubregIdx = AArch64::hsub;
4291 }
else if (EltSize == 32) {
4292 Opc = AArch64::INSvi32lane;
4293 SubregIdx = AArch64::ssub;
4294 }
else if (EltSize == 64) {
4295 Opc = AArch64::INSvi64lane;
4296 SubregIdx = AArch64::dsub;
4301 return std::make_pair(
Opc, SubregIdx);
4304MachineInstr *AArch64InstructionSelector::emitInstr(
4305 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4306 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4307 const ComplexRendererFns &RenderFns)
const {
4308 assert(Opcode &&
"Expected an opcode?");
4310 "Function should only be used to produce selected instructions!");
4311 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4313 for (
auto &Fn : *RenderFns)
4319MachineInstr *AArch64InstructionSelector::emitAddSub(
4320 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4322 MachineIRBuilder &MIRBuilder)
const {
4324 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4325 auto Ty =
MRI.getType(
LHS.getReg());
4328 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4329 bool Is32Bit =
Size == 32;
4332 if (
auto Fns = selectArithImmed(
RHS))
4333 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4337 if (
auto Fns = selectNegArithImmed(
RHS))
4338 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4342 if (
auto Fns = selectArithExtendedRegister(
RHS))
4343 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4347 if (
auto Fns = selectShiftedRegister(
RHS))
4348 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4350 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4355AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4356 MachineOperand &
RHS,
4357 MachineIRBuilder &MIRBuilder)
const {
4358 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4359 {{AArch64::ADDXri, AArch64::ADDWri},
4360 {AArch64::ADDXrs, AArch64::ADDWrs},
4361 {AArch64::ADDXrr, AArch64::ADDWrr},
4362 {AArch64::SUBXri, AArch64::SUBWri},
4363 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4364 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4368AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4369 MachineOperand &
RHS,
4370 MachineIRBuilder &MIRBuilder)
const {
4371 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4372 {{AArch64::ADDSXri, AArch64::ADDSWri},
4373 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4374 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4375 {AArch64::SUBSXri, AArch64::SUBSWri},
4376 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4377 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4381AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4382 MachineOperand &
RHS,
4383 MachineIRBuilder &MIRBuilder)
const {
4384 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4385 {{AArch64::SUBSXri, AArch64::SUBSWri},
4386 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4387 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4388 {AArch64::ADDSXri, AArch64::ADDSWri},
4389 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4390 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4394AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4395 MachineOperand &
RHS,
4396 MachineIRBuilder &MIRBuilder)
const {
4397 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4398 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4399 bool Is32Bit = (
MRI->getType(
LHS.getReg()).getSizeInBits() == 32);
4400 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4401 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4405AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4406 MachineOperand &
RHS,
4407 MachineIRBuilder &MIRBuilder)
const {
4408 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4409 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4410 bool Is32Bit = (
MRI->getType(
LHS.getReg()).getSizeInBits() == 32);
4411 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4412 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4416AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4417 MachineIRBuilder &MIRBuilder)
const {
4419 bool Is32Bit = (
MRI.getType(
LHS.getReg()).getSizeInBits() == 32);
4420 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4421 return emitADDS(
MRI.createVirtualRegister(RC),
LHS,
RHS, MIRBuilder);
4425AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4426 MachineIRBuilder &MIRBuilder)
const {
4427 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4429 LLT Ty =
MRI.getType(
LHS.getReg());
4431 bool Is32Bit = (
RegSize == 32);
4432 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4433 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4434 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4438 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4441 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4448 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4449 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4450 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4453MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4454 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4455 MachineIRBuilder &MIRBuilder)
const {
4456 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4459 LLT CmpTy =
MRI.getType(
LHS.getReg());
4463 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4465 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4467 auto Dst =
MRI.cloneVirtualRegister(
LHS.getReg());
4468 return emitSUBS(Dst,
LHS,
RHS, MIRBuilder);
4471MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4473 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4475 LLT Ty =
MRI.getType(Dst);
4477 "Expected a 32-bit scalar register?");
4479 const Register ZReg = AArch64::WZR;
4484 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4486 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4490 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4491 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4492 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4497MachineInstr *AArch64InstructionSelector::emitFPCompare(
4499 std::optional<CmpInst::Predicate> Pred)
const {
4500 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4501 LLT Ty =
MRI.getType(
LHS);
4505 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4516 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4520 ShouldUseImm =
true;
4524 unsigned CmpOpcTbl[2][3] = {
4525 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4526 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4528 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4540MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4542 MachineIRBuilder &MIRBuilder)
const {
4549 const LLT Op1Ty =
MRI.getType(Op1);
4550 const LLT Op2Ty =
MRI.getType(Op2);
4552 if (Op1Ty != Op2Ty) {
4553 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4556 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4559 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4571 const TargetRegisterClass *DstRC =
4574 MachineInstr *WidenedOp1 =
4575 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4576 MachineInstr *WidenedOp2 =
4577 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4578 if (!WidenedOp1 || !WidenedOp2) {
4579 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4584 unsigned InsertOpc, InsSubRegIdx;
4585 std::tie(InsertOpc, InsSubRegIdx) =
4589 Dst =
MRI.createVirtualRegister(DstRC);
4603 MachineIRBuilder &MIRBuilder)
const {
4610 Size =
TRI.getRegSizeInBits(*RC);
4612 Size =
MRI.getType(Dst).getSizeInBits();
4614 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4615 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4616 unsigned Opc = OpcTable[
Size == 64];
4622MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4624 MachineRegisterInfo *
MRI = MIB.
getMRI();
4625 unsigned Opcode =
I.getOpcode();
4629 bool NeedsNegatedCarry =
4630 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4639 MachineInstr *SrcMI =
MRI->getVRegDef(CarryReg);
4640 if (SrcMI ==
I.getPrevNode()) {
4642 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4643 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4644 CarrySrcMI->isUnsigned() &&
4645 CarrySrcMI->getCarryOutReg() == CarryReg &&
4646 selectAndRestoreState(*SrcMI))
4651 Register DeadReg =
MRI->createVirtualRegister(&AArch64::GPR32RegClass);
4653 if (NeedsNegatedCarry) {
4656 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4660 auto Fns = select12BitValueWithLeftShift(1);
4661 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4664bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4665 MachineRegisterInfo &
MRI) {
4670 emitCarryIn(
I, CarryInMI->getCarryInReg());
4674 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4675 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4677 Register CarryOutReg = CarryMI.getCarryOutReg();
4680 if (!
MRI.use_nodbg_empty(CarryOutReg)) {
4686 emitCSINC(CarryOutReg, ZReg, ZReg,
4687 getInvertedCondCode(OpAndCC.second), MIB);
4690 I.eraseFromParent();
4694std::pair<MachineInstr *, AArch64CC::CondCode>
4695AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4696 MachineOperand &
LHS,
4697 MachineOperand &
RHS,
4698 MachineIRBuilder &MIRBuilder)
const {
4702 case TargetOpcode::G_SADDO:
4704 case TargetOpcode::G_UADDO:
4706 case TargetOpcode::G_SSUBO:
4708 case TargetOpcode::G_USUBO:
4710 case TargetOpcode::G_SADDE:
4712 case TargetOpcode::G_UADDE:
4714 case TargetOpcode::G_SSUBE:
4716 case TargetOpcode::G_USUBE:
4737 unsigned Depth = 0) {
4738 if (!
MRI.hasOneNonDBGUse(Val))
4744 MustBeFirst =
false;
4750 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4751 bool IsOR = Opcode == TargetOpcode::G_OR;
4763 if (MustBeFirstL && MustBeFirstR)
4769 if (!CanNegateL && !CanNegateR)
4773 CanNegate = WillNegate && CanNegateL && CanNegateR;
4776 MustBeFirst = !CanNegate;
4778 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4781 MustBeFirst = MustBeFirstL || MustBeFirstR;
4788MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4791 MachineIRBuilder &MIB)
const {
4793 LLT OpTy =
MRI.getType(
LHS);
4795 std::optional<ValueAndVReg>
C;
4799 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4800 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4801 else if (
C->Value.ule(31))
4802 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4804 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4810 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4811 CCmpOpc = AArch64::FCCMPHrr;
4814 CCmpOpc = AArch64::FCCMPSrr;
4817 CCmpOpc = AArch64::FCCMPDrr;
4827 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4828 CCmp.
addImm(
C->Value.getZExtValue());
4829 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4830 CCmp.
addImm(
C->Value.abs().getZExtValue());
4838MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4843 MachineInstr *ValDef =
MRI.getVRegDef(Val);
4860 MachineInstr *ExtraCmp;
4862 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4873 auto Dst =
MRI.cloneVirtualRegister(
LHS);
4875 return emitSUBS(Dst,
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4876 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4877 Cmp->getOperand(3).getReg(), MIB);
4882 assert(
MRI.hasOneNonDBGUse(Val) &&
"Valid conjunction/disjunction tree");
4884 bool IsOR = Opcode == TargetOpcode::G_OR;
4890 assert(ValidL &&
"Valid conjunction/disjunction tree");
4897 assert(ValidR &&
"Valid conjunction/disjunction tree");
4902 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4911 bool NegateAfterAll;
4912 if (Opcode == TargetOpcode::G_OR) {
4915 assert(CanNegateR &&
"at least one side must be negatable");
4916 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4920 NegateAfterR =
true;
4923 NegateR = CanNegateR;
4924 NegateAfterR = !CanNegateR;
4927 NegateAfterAll = !Negate;
4929 assert(Opcode == TargetOpcode::G_AND &&
4930 "Valid conjunction/disjunction tree");
4931 assert(!Negate &&
"Valid conjunction/disjunction tree");
4935 NegateAfterR =
false;
4936 NegateAfterAll =
false;
4941 MachineInstr *CmpR =
4952MachineInstr *AArch64InstructionSelector::emitConjunction(
4954 bool DummyCanNegate;
4955 bool DummyMustBeFirst;
4962bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4963 MachineInstr &CondMI) {
4974bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4975 MachineRegisterInfo &
MRI = *MIB.
getMRI();
4994 MachineInstr *CondDef =
MRI.getVRegDef(
I.getOperand(1).getReg());
4998 if (!
MRI.hasOneNonDBGUse(CondDefReg)) {
5000 for (
const MachineInstr &UI :
MRI.use_nodbg_instructions(CondDefReg)) {
5003 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5009 unsigned CondOpc = CondDef->
getOpcode();
5010 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5011 if (tryOptSelectConjunction(
I, *CondDef))
5017 if (CondOpc == TargetOpcode::G_ICMP) {
5046 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5047 I.getOperand(3).getReg(), CondCode, MIB);
5048 I.eraseFromParent();
5052MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5053 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5054 MachineIRBuilder &MIRBuilder)
const {
5056 "Unexpected MachineOperand");
5057 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5112 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5115 if (!ValAndVReg || ValAndVReg->Value != 0)
5125bool AArch64InstructionSelector::selectShuffleVector(
5126 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5127 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5128 Register Src1Reg =
I.getOperand(1).getReg();
5129 const LLT Src1Ty =
MRI.getType(Src1Reg);
5130 Register Src2Reg =
I.getOperand(2).getReg();
5131 const LLT Src2Ty =
MRI.getType(Src2Reg);
5132 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5142 LLVM_DEBUG(
dbgs() <<
"Could not select a \"scalar\" G_SHUFFLE_VECTOR\n");
5149 for (
int Val : Mask) {
5152 Val = Val < 0 ? 0 : Val;
5153 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5171 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5178 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5182 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5187 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5188 .addReg(TBL1.getReg(0), 0, AArch64::dsub);
5190 I.eraseFromParent();
5198 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5201 I.eraseFromParent();
5205MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5207 unsigned LaneIdx,
const RegisterBank &RB,
5208 MachineIRBuilder &MIRBuilder)
const {
5209 MachineInstr *InsElt =
nullptr;
5210 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5211 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5215 DstReg =
MRI.createVirtualRegister(DstRC);
5217 unsigned EltSize =
MRI.getType(EltReg).getSizeInBits();
5220 if (RB.
getID() == AArch64::FPRRegBankID) {
5221 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5224 .
addUse(InsSub->getOperand(0).getReg())
5236bool AArch64InstructionSelector::selectUSMovFromExtend(
5237 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5238 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5239 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5240 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5242 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5243 const Register DefReg =
MI.getOperand(0).getReg();
5244 const LLT DstTy =
MRI.getType(DefReg);
5247 if (DstSize != 32 && DstSize != 64)
5250 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5251 MI.getOperand(1).getReg(),
MRI);
5257 const LLT VecTy =
MRI.getType(Src0);
5262 const MachineInstr *ScalarToVector = emitScalarToVector(
5263 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5264 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5270 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5272 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5274 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5276 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5278 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5286 MachineInstr *ExtI =
nullptr;
5287 if (DstSize == 64 && !IsSigned) {
5288 Register NewReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
5289 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5290 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5293 .
addImm(AArch64::sub_32);
5296 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5299 MI.eraseFromParent();
5303MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5304 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5306 if (DstSize == 128) {
5307 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5309 Op = AArch64::MOVIv16b_ns;
5311 Op = AArch64::MOVIv8b_ns;
5314 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5318 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5325MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5326 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5330 if (DstSize == 128) {
5331 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5333 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5335 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5338 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5355MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5356 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5360 if (DstSize == 128) {
5361 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5363 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5365 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5368 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5391MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5392 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5395 if (DstSize == 128) {
5396 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5398 Op = AArch64::MOVIv2d_ns;
5400 Op = AArch64::MOVID;
5403 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5406 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5413MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5414 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5418 if (DstSize == 128) {
5419 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5421 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5423 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5426 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5443MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5444 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5447 bool IsWide =
false;
5448 if (DstSize == 128) {
5449 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5451 Op = AArch64::FMOVv4f32_ns;
5454 Op = AArch64::FMOVv2f32_ns;
5457 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5463 Op = AArch64::FMOVv2f64_ns;
5467 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5472bool AArch64InstructionSelector::selectIndexedExtLoad(
5473 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5476 Register WriteBack = ExtLd.getWritebackReg();
5479 LLT Ty =
MRI.getType(Dst);
5481 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5482 bool IsPre = ExtLd.isPre();
5484 unsigned InsertIntoSubReg = 0;
5490 if ((IsSExt && IsFPR) || Ty.
isVector())
5498 if (MemSizeBits == 8) {
5501 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5503 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5504 NewLdDstTy = IsDst64 ? s64 : s32;
5506 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5507 InsertIntoSubReg = AArch64::bsub;
5510 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5511 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5514 }
else if (MemSizeBits == 16) {
5517 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5519 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5520 NewLdDstTy = IsDst64 ? s64 : s32;
5522 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5523 InsertIntoSubReg = AArch64::hsub;
5526 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5527 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5530 }
else if (MemSizeBits == 32) {
5532 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5535 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5536 InsertIntoSubReg = AArch64::ssub;
5539 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5540 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5552 .addImm(Cst->getSExtValue());
5557 if (InsertIntoSubReg) {
5559 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5562 .
addImm(InsertIntoSubReg);
5565 *getRegClassForTypeOnBank(
MRI.getType(Dst),
5572 MI.eraseFromParent();
5577bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5578 MachineRegisterInfo &
MRI) {
5581 Register WriteBack = Ld.getWritebackReg();
5584 assert(
MRI.getType(Dst).getSizeInBits() <= 128 &&
5585 "Unexpected type for indexed load");
5586 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5588 if (MemSize <
MRI.getType(Dst).getSizeInBytes())
5589 return selectIndexedExtLoad(
MI,
MRI);
5593 static constexpr unsigned GPROpcodes[] = {
5594 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5596 static constexpr unsigned FPROpcodes[] = {
5597 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5604 static constexpr unsigned GPROpcodes[] = {
5605 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5607 static constexpr unsigned FPROpcodes[] = {
5608 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5609 AArch64::LDRDpost, AArch64::LDRQpost};
5622 MI.eraseFromParent();
5626bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5627 MachineRegisterInfo &
MRI) {
5632 LLT ValTy =
MRI.getType(Val);
5637 static constexpr unsigned GPROpcodes[] = {
5638 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5640 static constexpr unsigned FPROpcodes[] = {
5641 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5649 static constexpr unsigned GPROpcodes[] = {
5650 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5652 static constexpr unsigned FPROpcodes[] = {
5653 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5654 AArch64::STRDpost, AArch64::STRQpost};
5667 Str.cloneMemRefs(
I);
5669 I.eraseFromParent();
5674AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5675 MachineIRBuilder &MIRBuilder,
5676 MachineRegisterInfo &
MRI) {
5677 LLT DstTy =
MRI.getType(Dst);
5680 if (DstSize == 128) {
5682 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5687 if (DstSize == 64) {
5690 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5693 .addReg(Mov.getReg(0), 0, AArch64::dsub);
5700 APInt SplatValueAsInt =
5703 : SplatValue->getUniqueInteger();
5706 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5707 MachineInstr *NewOp;
5731 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5735 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5736 unsigned NegOpc) -> MachineInstr * {
5739 APInt NegBits(DstSize, 0);
5740 unsigned NumElts = DstSize / NumBits;
5741 for (
unsigned i = 0; i < NumElts; i++)
5742 NegBits |= Neg << (NumBits * i);
5743 NegBits = DefBits ^ NegBits;
5747 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5748 Register NewDst =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
5750 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5755 if ((R = TryWithFNeg(DefBits, 32, AArch64::FNEGv4f32)) ||
5756 (R = TryWithFNeg(DefBits, 64, AArch64::FNEGv2f64)) ||
5757 (STI.hasFullFP16() &&
5758 (R = TryWithFNeg(DefBits, 16, AArch64::FNEGv8f16))))
5764 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5768 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5770 Dst, *
MRI.getRegClass(CPLoad->getOperand(0).getReg()),
MRI);
5774bool AArch64InstructionSelector::tryOptConstantBuildVec(
5775 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5776 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5778 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5784 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5790 const_cast<ConstantInt *
>(OpMI->getOperand(1).getCImm()));
5791 else if ((OpMI =
getOpcodeDef(TargetOpcode::G_FCONSTANT,
5792 I.getOperand(Idx).getReg(),
MRI)))
5794 const_cast<ConstantFP *
>(OpMI->getOperand(1).getFPImm()));
5799 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB,
MRI))
5801 I.eraseFromParent();
5805bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5806 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5811 Register Dst =
I.getOperand(0).getReg();
5812 Register EltReg =
I.getOperand(1).getReg();
5813 LLT EltTy =
MRI.getType(EltReg);
5821 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5825 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5828 const TargetRegisterClass *DstRC =
5829 getRegClassForTypeOnBank(
MRI.getType(Dst), DstRB);
5834 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5838 I.eraseFromParent();
5843bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5844 MachineRegisterInfo &
MRI) {
5845 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5848 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5849 const LLT EltTy =
MRI.getType(
I.getOperand(1).getReg());
5852 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5854 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5857 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5861 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5862 MachineInstr *ScalarToVec =
5864 I.getOperand(1).getReg(), MIB);
5873 MachineInstr *PrevMI = ScalarToVec;
5874 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5877 Register OpReg =
I.getOperand(i).getReg();
5880 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5887 if (DstSize < 128) {
5889 const TargetRegisterClass *RC =
5893 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5901 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
5902 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5908 Register DstReg =
I.getOperand(0).getReg();
5910 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, 0,
SubReg);
5911 MachineOperand &RegOp =
I.getOperand(1);
5931 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5932 const TargetRegisterClass *RC =
5942bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5945 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5947 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5949 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5952 "Destination must be 64 bits or 128 bits?");
5953 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5954 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5955 assert(
MRI.getType(
Ptr).isPointer() &&
"Expected a pointer type?");
5957 Load.cloneMemRefs(
I);
5959 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5960 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5961 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5962 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
5971bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5972 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5973 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5975 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5977 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5980 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5982 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5983 [](
auto MO) { return MO.getReg(); });
5987 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6002 .
addImm(LaneNo->getZExtValue())
6004 Load.cloneMemRefs(
I);
6006 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6007 unsigned SubReg = AArch64::qsub0;
6008 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6009 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6010 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6011 : DstOp(
I.getOperand(Idx).
getReg())},
6013 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
6018 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6024void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6027 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6028 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6032 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6033 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6042bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6043 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6044 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6045 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6049 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6050 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6054 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6067 .
addImm(LaneNo->getZExtValue())
6074bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6075 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6088 case Intrinsic::aarch64_ldxp:
6089 case Intrinsic::aarch64_ldaxp: {
6091 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6092 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6098 case Intrinsic::aarch64_neon_ld1x2: {
6099 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6102 Opc = AArch64::LD1Twov8b;
6104 Opc = AArch64::LD1Twov16b;
6106 Opc = AArch64::LD1Twov4h;
6108 Opc = AArch64::LD1Twov8h;
6110 Opc = AArch64::LD1Twov2s;
6112 Opc = AArch64::LD1Twov4s;
6114 Opc = AArch64::LD1Twov2d;
6115 else if (Ty ==
S64 || Ty == P0)
6116 Opc = AArch64::LD1Twov1d;
6119 selectVectorLoadIntrinsic(
Opc, 2,
I);
6122 case Intrinsic::aarch64_neon_ld1x3: {
6123 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6126 Opc = AArch64::LD1Threev8b;
6128 Opc = AArch64::LD1Threev16b;
6130 Opc = AArch64::LD1Threev4h;
6132 Opc = AArch64::LD1Threev8h;
6134 Opc = AArch64::LD1Threev2s;
6136 Opc = AArch64::LD1Threev4s;
6138 Opc = AArch64::LD1Threev2d;
6139 else if (Ty ==
S64 || Ty == P0)
6140 Opc = AArch64::LD1Threev1d;
6143 selectVectorLoadIntrinsic(
Opc, 3,
I);
6146 case Intrinsic::aarch64_neon_ld1x4: {
6147 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6150 Opc = AArch64::LD1Fourv8b;
6152 Opc = AArch64::LD1Fourv16b;
6154 Opc = AArch64::LD1Fourv4h;
6156 Opc = AArch64::LD1Fourv8h;
6158 Opc = AArch64::LD1Fourv2s;
6160 Opc = AArch64::LD1Fourv4s;
6162 Opc = AArch64::LD1Fourv2d;
6163 else if (Ty ==
S64 || Ty == P0)
6164 Opc = AArch64::LD1Fourv1d;
6167 selectVectorLoadIntrinsic(
Opc, 4,
I);
6170 case Intrinsic::aarch64_neon_ld2: {
6171 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6174 Opc = AArch64::LD2Twov8b;
6176 Opc = AArch64::LD2Twov16b;
6178 Opc = AArch64::LD2Twov4h;
6180 Opc = AArch64::LD2Twov8h;
6182 Opc = AArch64::LD2Twov2s;
6184 Opc = AArch64::LD2Twov4s;
6186 Opc = AArch64::LD2Twov2d;
6187 else if (Ty ==
S64 || Ty == P0)
6188 Opc = AArch64::LD1Twov1d;
6191 selectVectorLoadIntrinsic(
Opc, 2,
I);
6194 case Intrinsic::aarch64_neon_ld2lane: {
6195 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6198 Opc = AArch64::LD2i8;
6200 Opc = AArch64::LD2i16;
6202 Opc = AArch64::LD2i32;
6205 Opc = AArch64::LD2i64;
6208 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6212 case Intrinsic::aarch64_neon_ld2r: {
6213 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6216 Opc = AArch64::LD2Rv8b;
6218 Opc = AArch64::LD2Rv16b;
6220 Opc = AArch64::LD2Rv4h;
6222 Opc = AArch64::LD2Rv8h;
6224 Opc = AArch64::LD2Rv2s;
6226 Opc = AArch64::LD2Rv4s;
6228 Opc = AArch64::LD2Rv2d;
6229 else if (Ty ==
S64 || Ty == P0)
6230 Opc = AArch64::LD2Rv1d;
6233 selectVectorLoadIntrinsic(
Opc, 2,
I);
6236 case Intrinsic::aarch64_neon_ld3: {
6237 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6240 Opc = AArch64::LD3Threev8b;
6242 Opc = AArch64::LD3Threev16b;
6244 Opc = AArch64::LD3Threev4h;
6246 Opc = AArch64::LD3Threev8h;
6248 Opc = AArch64::LD3Threev2s;
6250 Opc = AArch64::LD3Threev4s;
6252 Opc = AArch64::LD3Threev2d;
6253 else if (Ty ==
S64 || Ty == P0)
6254 Opc = AArch64::LD1Threev1d;
6257 selectVectorLoadIntrinsic(
Opc, 3,
I);
6260 case Intrinsic::aarch64_neon_ld3lane: {
6261 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6264 Opc = AArch64::LD3i8;
6266 Opc = AArch64::LD3i16;
6268 Opc = AArch64::LD3i32;
6271 Opc = AArch64::LD3i64;
6274 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6278 case Intrinsic::aarch64_neon_ld3r: {
6279 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6282 Opc = AArch64::LD3Rv8b;
6284 Opc = AArch64::LD3Rv16b;
6286 Opc = AArch64::LD3Rv4h;
6288 Opc = AArch64::LD3Rv8h;
6290 Opc = AArch64::LD3Rv2s;
6292 Opc = AArch64::LD3Rv4s;
6294 Opc = AArch64::LD3Rv2d;
6295 else if (Ty ==
S64 || Ty == P0)
6296 Opc = AArch64::LD3Rv1d;
6299 selectVectorLoadIntrinsic(
Opc, 3,
I);
6302 case Intrinsic::aarch64_neon_ld4: {
6303 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6306 Opc = AArch64::LD4Fourv8b;
6308 Opc = AArch64::LD4Fourv16b;
6310 Opc = AArch64::LD4Fourv4h;
6312 Opc = AArch64::LD4Fourv8h;
6314 Opc = AArch64::LD4Fourv2s;
6316 Opc = AArch64::LD4Fourv4s;
6318 Opc = AArch64::LD4Fourv2d;
6319 else if (Ty ==
S64 || Ty == P0)
6320 Opc = AArch64::LD1Fourv1d;
6323 selectVectorLoadIntrinsic(
Opc, 4,
I);
6326 case Intrinsic::aarch64_neon_ld4lane: {
6327 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6330 Opc = AArch64::LD4i8;
6332 Opc = AArch64::LD4i16;
6334 Opc = AArch64::LD4i32;
6337 Opc = AArch64::LD4i64;
6340 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6344 case Intrinsic::aarch64_neon_ld4r: {
6345 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6348 Opc = AArch64::LD4Rv8b;
6350 Opc = AArch64::LD4Rv16b;
6352 Opc = AArch64::LD4Rv4h;
6354 Opc = AArch64::LD4Rv8h;
6356 Opc = AArch64::LD4Rv2s;
6358 Opc = AArch64::LD4Rv4s;
6360 Opc = AArch64::LD4Rv2d;
6361 else if (Ty ==
S64 || Ty == P0)
6362 Opc = AArch64::LD4Rv1d;
6365 selectVectorLoadIntrinsic(
Opc, 4,
I);
6368 case Intrinsic::aarch64_neon_st1x2: {
6369 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6372 Opc = AArch64::ST1Twov8b;
6374 Opc = AArch64::ST1Twov16b;
6376 Opc = AArch64::ST1Twov4h;
6378 Opc = AArch64::ST1Twov8h;
6380 Opc = AArch64::ST1Twov2s;
6382 Opc = AArch64::ST1Twov4s;
6384 Opc = AArch64::ST1Twov2d;
6385 else if (Ty ==
S64 || Ty == P0)
6386 Opc = AArch64::ST1Twov1d;
6389 selectVectorStoreIntrinsic(
I, 2,
Opc);
6392 case Intrinsic::aarch64_neon_st1x3: {
6393 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6396 Opc = AArch64::ST1Threev8b;
6398 Opc = AArch64::ST1Threev16b;
6400 Opc = AArch64::ST1Threev4h;
6402 Opc = AArch64::ST1Threev8h;
6404 Opc = AArch64::ST1Threev2s;
6406 Opc = AArch64::ST1Threev4s;
6408 Opc = AArch64::ST1Threev2d;
6409 else if (Ty ==
S64 || Ty == P0)
6410 Opc = AArch64::ST1Threev1d;
6413 selectVectorStoreIntrinsic(
I, 3,
Opc);
6416 case Intrinsic::aarch64_neon_st1x4: {
6417 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6420 Opc = AArch64::ST1Fourv8b;
6422 Opc = AArch64::ST1Fourv16b;
6424 Opc = AArch64::ST1Fourv4h;
6426 Opc = AArch64::ST1Fourv8h;
6428 Opc = AArch64::ST1Fourv2s;
6430 Opc = AArch64::ST1Fourv4s;
6432 Opc = AArch64::ST1Fourv2d;
6433 else if (Ty ==
S64 || Ty == P0)
6434 Opc = AArch64::ST1Fourv1d;
6437 selectVectorStoreIntrinsic(
I, 4,
Opc);
6440 case Intrinsic::aarch64_neon_st2: {
6441 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6444 Opc = AArch64::ST2Twov8b;
6446 Opc = AArch64::ST2Twov16b;
6448 Opc = AArch64::ST2Twov4h;
6450 Opc = AArch64::ST2Twov8h;
6452 Opc = AArch64::ST2Twov2s;
6454 Opc = AArch64::ST2Twov4s;
6456 Opc = AArch64::ST2Twov2d;
6457 else if (Ty ==
S64 || Ty == P0)
6458 Opc = AArch64::ST1Twov1d;
6461 selectVectorStoreIntrinsic(
I, 2,
Opc);
6464 case Intrinsic::aarch64_neon_st3: {
6465 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6468 Opc = AArch64::ST3Threev8b;
6470 Opc = AArch64::ST3Threev16b;
6472 Opc = AArch64::ST3Threev4h;
6474 Opc = AArch64::ST3Threev8h;
6476 Opc = AArch64::ST3Threev2s;
6478 Opc = AArch64::ST3Threev4s;
6480 Opc = AArch64::ST3Threev2d;
6481 else if (Ty ==
S64 || Ty == P0)
6482 Opc = AArch64::ST1Threev1d;
6485 selectVectorStoreIntrinsic(
I, 3,
Opc);
6488 case Intrinsic::aarch64_neon_st4: {
6489 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6492 Opc = AArch64::ST4Fourv8b;
6494 Opc = AArch64::ST4Fourv16b;
6496 Opc = AArch64::ST4Fourv4h;
6498 Opc = AArch64::ST4Fourv8h;
6500 Opc = AArch64::ST4Fourv2s;
6502 Opc = AArch64::ST4Fourv4s;
6504 Opc = AArch64::ST4Fourv2d;
6505 else if (Ty ==
S64 || Ty == P0)
6506 Opc = AArch64::ST1Fourv1d;
6509 selectVectorStoreIntrinsic(
I, 4,
Opc);
6512 case Intrinsic::aarch64_neon_st2lane: {
6513 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6516 Opc = AArch64::ST2i8;
6518 Opc = AArch64::ST2i16;
6520 Opc = AArch64::ST2i32;
6523 Opc = AArch64::ST2i64;
6526 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6530 case Intrinsic::aarch64_neon_st3lane: {
6531 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6534 Opc = AArch64::ST3i8;
6536 Opc = AArch64::ST3i16;
6538 Opc = AArch64::ST3i32;
6541 Opc = AArch64::ST3i64;
6544 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6548 case Intrinsic::aarch64_neon_st4lane: {
6549 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6552 Opc = AArch64::ST4i8;
6554 Opc = AArch64::ST4i16;
6556 Opc = AArch64::ST4i32;
6559 Opc = AArch64::ST4i64;
6562 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6566 case Intrinsic::aarch64_mops_memset_tag: {
6579 Register DstDef =
I.getOperand(0).getReg();
6581 Register DstUse =
I.getOperand(2).getReg();
6582 Register ValUse =
I.getOperand(3).getReg();
6583 Register SizeUse =
I.getOperand(4).getReg();
6590 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6591 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6598 I.eraseFromParent();
6602bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6603 MachineRegisterInfo &
MRI) {
6609 case Intrinsic::ptrauth_resign: {
6610 Register DstReg =
I.getOperand(0).getReg();
6611 Register ValReg =
I.getOperand(2).getReg();
6612 uint64_t AUTKey =
I.getOperand(3).getImm();
6613 Register AUTDisc =
I.getOperand(4).getReg();
6614 uint64_t PACKey =
I.getOperand(5).getImm();
6615 Register PACDisc =
I.getOperand(6).getReg();
6618 uint16_t AUTConstDiscC = 0;
6619 std::tie(AUTConstDiscC, AUTAddrDisc) =
6623 uint16_t PACConstDiscC = 0;
6624 std::tie(PACConstDiscC, PACAddrDisc) =
6627 MIB.
buildCopy({AArch64::X16}, {ValReg});
6628 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6640 I.eraseFromParent();
6643 case Intrinsic::ptrauth_auth: {
6644 Register DstReg =
I.getOperand(0).getReg();
6645 Register ValReg =
I.getOperand(2).getReg();
6646 uint64_t AUTKey =
I.getOperand(3).getImm();
6647 Register AUTDisc =
I.getOperand(4).getReg();
6650 uint16_t AUTConstDiscC = 0;
6651 std::tie(AUTConstDiscC, AUTAddrDisc) =
6655 MIB.
buildCopy({AArch64::X16}, {ValReg});
6656 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6665 MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
6677 I.eraseFromParent();
6680 case Intrinsic::frameaddress:
6681 case Intrinsic::returnaddress: {
6682 MachineFunction &MF = *
I.getParent()->getParent();
6685 unsigned Depth =
I.getOperand(2).getImm();
6686 Register DstReg =
I.getOperand(0).getReg();
6689 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6690 if (!MFReturnAddr) {
6695 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6698 if (STI.hasPAuth()) {
6699 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6706 I.eraseFromParent();
6713 Register NextFrame =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
6715 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6717 FrameAddr = NextFrame;
6720 if (IntrinID == Intrinsic::frameaddress)
6725 if (STI.hasPAuth()) {
6726 Register TmpReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
6727 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6728 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6737 I.eraseFromParent();
6740 case Intrinsic::aarch64_neon_tbl2:
6741 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6743 case Intrinsic::aarch64_neon_tbl3:
6744 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6747 case Intrinsic::aarch64_neon_tbl4:
6748 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6750 case Intrinsic::aarch64_neon_tbx2:
6751 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6753 case Intrinsic::aarch64_neon_tbx3:
6754 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6756 case Intrinsic::aarch64_neon_tbx4:
6757 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6759 case Intrinsic::swift_async_context_addr:
6760 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6767 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6768 I.eraseFromParent();
6803bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6804 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6805 Register DefReg =
I.getOperand(0).getReg();
6806 Register Addr =
I.getOperand(1).getReg();
6807 uint64_t
Key =
I.getOperand(2).getImm();
6808 Register AddrDisc =
I.getOperand(3).getReg();
6809 uint64_t Disc =
I.getOperand(4).getImm();
6819 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6825 if (!
MRI.hasOneDef(Addr))
6829 const MachineInstr *
DefMI = &*
MRI.def_instr_begin(Addr);
6832 if (!
MRI.hasOneDef(OffsetReg))
6834 const MachineInstr &OffsetMI = *
MRI.def_instr_begin(OffsetReg);
6835 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6839 if (!
MRI.hasOneDef(Addr))
6842 DefMI = &*
MRI.def_instr_begin(Addr);
6847 const GlobalValue *GV;
6858 MachineIRBuilder MIB(
I);
6864 "unsupported non-GOT op flags on ptrauth global reference");
6866 "unsupported non-GOT reference to weak ptrauth global");
6869 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6876 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6877 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6878 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6881 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6886 I.eraseFromParent();
6898 "unsupported non-zero offset in weak ptrauth global reference");
6903 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6904 .addGlobalAddress(GV,
Offset)
6909 I.eraseFromParent();
6913void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6914 MachineRegisterInfo &
MRI,
6915 unsigned NumVec,
unsigned Opc1,
6916 unsigned Opc2,
bool isExt) {
6917 Register DstReg =
I.getOperand(0).getReg();
6922 for (
unsigned i = 0; i < NumVec; i++)
6923 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6926 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6927 MachineInstrBuilder
Instr;
6934 I.eraseFromParent();
6937InstructionSelector::ComplexRendererFns
6938AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6940 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6941 return std::nullopt;
6942 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6943 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6946InstructionSelector::ComplexRendererFns
6947AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6949 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6950 return std::nullopt;
6951 uint64_t Enc = 31 - *MaybeImmed;
6952 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6955InstructionSelector::ComplexRendererFns
6956AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
6958 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6959 return std::nullopt;
6960 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
6961 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6964InstructionSelector::ComplexRendererFns
6965AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
6967 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6968 return std::nullopt;
6969 uint64_t Enc = 63 - *MaybeImmed;
6970 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6978InstructionSelector::ComplexRendererFns
6979AArch64InstructionSelector::select12BitValueWithLeftShift(
6980 uint64_t Immed)
const {
6982 if (Immed >> 12 == 0) {
6984 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
6986 Immed = Immed >> 12;
6988 return std::nullopt;
6992 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
6993 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7000InstructionSelector::ComplexRendererFns
7001AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7008 if (MaybeImmed == std::nullopt)
7009 return std::nullopt;
7010 return select12BitValueWithLeftShift(*MaybeImmed);
7015InstructionSelector::ComplexRendererFns
7016AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7020 return std::nullopt;
7022 if (MaybeImmed == std::nullopt)
7023 return std::nullopt;
7024 uint64_t Immed = *MaybeImmed;
7030 return std::nullopt;
7035 if (
MRI.getType(Root.
getReg()).getSizeInBits() == 32)
7036 Immed = ~((uint32_t)Immed) + 1;
7038 Immed = ~Immed + 1ULL;
7040 if (Immed & 0xFFFFFFFFFF000000ULL)
7041 return std::nullopt;
7043 Immed &= 0xFFFFFFULL;
7044 return select12BitValueWithLeftShift(Immed);
7061std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7062 MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7063 if (
MI.getOpcode() == AArch64::G_SHL) {
7067 MI.getOperand(2).getReg(),
MRI)) {
7068 const APInt ShiftVal = ValAndVeg->Value;
7071 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7074 return std::nullopt;
7082bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7083 MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7084 bool IsAddrOperand)
const {
7088 if (
MRI.hasOneNonDBGUse(DefReg) ||
7089 MI.getParent()->getParent()->getFunction().hasOptSize())
7092 if (IsAddrOperand) {
7094 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7098 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7099 MachineInstr *OffsetInst =
7105 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7115 return all_of(
MRI.use_nodbg_instructions(DefReg),
7116 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7130InstructionSelector::ComplexRendererFns
7131AArch64InstructionSelector::selectExtendedSHL(
7132 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7133 unsigned SizeInBytes,
bool WantsExt)
const {
7134 assert(
Base.isReg() &&
"Expected base to be a register operand");
7135 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7138 MachineInstr *OffsetInst =
MRI.getVRegDef(
Offset.getReg());
7140 unsigned OffsetOpc = OffsetInst->
getOpcode();
7141 bool LookedThroughZExt =
false;
7142 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7144 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7145 return std::nullopt;
7149 LookedThroughZExt =
true;
7151 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7152 return std::nullopt;
7155 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7156 if (LegalShiftVal == 0)
7157 return std::nullopt;
7158 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7159 return std::nullopt;
7170 if (OffsetOpc == TargetOpcode::G_SHL)
7171 return std::nullopt;
7177 return std::nullopt;
7182 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7186 if (OffsetOpc == TargetOpcode::G_MUL) {
7188 return std::nullopt;
7194 if ((ImmVal & 0x7) != ImmVal)
7195 return std::nullopt;
7199 if (ImmVal != LegalShiftVal)
7200 return std::nullopt;
7202 unsigned SignExtend = 0;
7206 if (!LookedThroughZExt) {
7208 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7210 return std::nullopt;
7215 return std::nullopt;
7220 MachineIRBuilder MIB(*
MRI.getVRegDef(Root.
getReg()));
7221 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7226 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7227 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7228 [=](MachineInstrBuilder &MIB) {
7231 MIB.addImm(SignExtend);
7244InstructionSelector::ComplexRendererFns
7245AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7246 MachineOperand &Root,
unsigned SizeInBytes)
const {
7248 return std::nullopt;
7263 MachineInstr *PtrAdd =
7265 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7266 return std::nullopt;
7270 MachineInstr *OffsetInst =
7272 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7285InstructionSelector::ComplexRendererFns
7286AArch64InstructionSelector::selectAddrModeRegisterOffset(
7287 MachineOperand &Root)
const {
7291 MachineInstr *Gep =
MRI.getVRegDef(Root.
getReg());
7292 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7293 return std::nullopt;
7299 return std::nullopt;
7302 return {{[=](MachineInstrBuilder &MIB) {
7305 [=](MachineInstrBuilder &MIB) {
7308 [=](MachineInstrBuilder &MIB) {
7318InstructionSelector::ComplexRendererFns
7319AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7320 unsigned SizeInBytes)
const {
7323 return std::nullopt;
7324 MachineInstr *PtrAdd =
7327 return std::nullopt;
7345 unsigned Scale =
Log2_32(SizeInBytes);
7346 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7350 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7351 ImmOff < (0x1000 << Scale))
7352 return std::nullopt;
7357 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7361 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7367 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7368 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7373 return std::nullopt;
7377 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7383 return selectAddrModeRegisterOffset(Root);
7392InstructionSelector::ComplexRendererFns
7393AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7394 unsigned SizeInBytes)
const {
7397 MachineInstr *PtrAdd =
7399 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7400 return std::nullopt;
7421 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7430 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7431 return std::nullopt;
7435 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7437 return std::nullopt;
7440 MachineIRBuilder MIB(*PtrAdd);
7442 AArch64::GPR32RegClass, MIB);
7446 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7447 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7448 [=](MachineInstrBuilder &MIB) {
7449 MIB.addImm(SignExtend);
7459InstructionSelector::ComplexRendererFns
7460AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7461 unsigned Size)
const {
7462 MachineRegisterInfo &
MRI =
7466 return std::nullopt;
7468 if (!isBaseWithConstantOffset(Root,
MRI))
7469 return std::nullopt;
7471 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7473 MachineOperand &OffImm = RootDef->
getOperand(2);
7474 if (!OffImm.
isReg())
7475 return std::nullopt;
7477 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7478 return std::nullopt;
7480 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7482 return std::nullopt;
7485 if (RHSC >= -256 && RHSC < 256) {
7488 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7489 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7492 return std::nullopt;
7495InstructionSelector::ComplexRendererFns
7496AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7498 MachineRegisterInfo &
MRI)
const {
7499 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7500 return std::nullopt;
7503 return std::nullopt;
7508 return std::nullopt;
7512 return std::nullopt;
7516 return std::nullopt;
7519 MachineIRBuilder MIRBuilder(RootDef);
7521 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7522 [=](MachineInstrBuilder &MIB) {
7523 MIB.addGlobalAddress(GV,
Offset,
7532InstructionSelector::ComplexRendererFns
7533AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7534 unsigned Size)
const {
7539 return std::nullopt;
7541 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7542 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7544 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7545 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7553 MachineInstr *RootParent = Root.
getParent();
7555 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7557 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7562 if (isBaseWithConstantOffset(Root,
MRI)) {
7565 MachineInstr *LHSDef =
MRI.getVRegDef(
LHS.getReg());
7566 MachineInstr *RHSDef =
MRI.getVRegDef(
RHS.getReg());
7570 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7571 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7573 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7574 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7578 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7579 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7586 if (selectAddrModeUnscaled(Root,
Size))
7587 return std::nullopt;
7590 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7591 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7598 switch (
MI.getOpcode()) {
7601 case TargetOpcode::G_SHL:
7603 case TargetOpcode::G_LSHR:
7605 case TargetOpcode::G_ASHR:
7607 case TargetOpcode::G_ROTR:
7614InstructionSelector::ComplexRendererFns
7615AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7616 bool AllowROR)
const {
7618 return std::nullopt;
7619 MachineRegisterInfo &
MRI =
7624 MachineInstr *ShiftInst =
MRI.getVRegDef(Root.
getReg());
7627 return std::nullopt;
7629 return std::nullopt;
7630 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7631 return std::nullopt;
7634 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7637 return std::nullopt;
7641 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7644 unsigned NumBits =
MRI.getType(ShiftReg).getSizeInBits();
7645 unsigned Val = *Immed & (NumBits - 1);
7648 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7649 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7653 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7654 unsigned Opc =
MI.getOpcode();
7657 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7659 if (
Opc == TargetOpcode::G_SEXT)
7660 Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7662 Size =
MI.getOperand(2).getImm();
7663 assert(
Size != 64 &&
"Extend from 64 bits?");
7676 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7677 unsigned Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7678 assert(
Size != 64 &&
"Extend from 64 bits?");
7693 if (
Opc != TargetOpcode::G_AND)
7699 uint64_t AndMask = *MaybeAndMask;
7712Register AArch64InstructionSelector::moveScalarRegClass(
7713 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7714 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7715 auto Ty =
MRI.getType(
Reg);
7724 return Copy.getReg(0);
7729InstructionSelector::ComplexRendererFns
7730AArch64InstructionSelector::selectArithExtendedRegister(
7731 MachineOperand &Root)
const {
7733 return std::nullopt;
7734 MachineRegisterInfo &
MRI =
7737 uint64_t ShiftVal = 0;
7742 return std::nullopt;
7744 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7745 return std::nullopt;
7748 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7753 return std::nullopt;
7754 ShiftVal = *MaybeShiftVal;
7756 return std::nullopt;
7761 return std::nullopt;
7762 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7764 return std::nullopt;
7768 Ext = getExtendTypeForInst(*RootDef,
MRI);
7770 return std::nullopt;
7778 MachineInstr *ExtInst =
MRI.getVRegDef(ExtReg);
7779 if (isDef32(*ExtInst))
7780 return std::nullopt;
7786 MachineIRBuilder MIB(*RootDef);
7787 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7789 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7790 [=](MachineInstrBuilder &MIB) {
7791 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7795InstructionSelector::ComplexRendererFns
7796AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7798 return std::nullopt;
7799 MachineRegisterInfo &
MRI =
7803 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7808 return std::nullopt;
7810 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7813 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7816 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7821 LaneIdx->Value.getSExtValue() == 1) {
7823 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7827 return std::nullopt;
7830void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7831 const MachineInstr &
MI,
7833 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7834 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7835 "Expected G_CONSTANT");
7836 std::optional<int64_t> CstVal =
7838 assert(CstVal &&
"Expected constant value");
7842void AArch64InstructionSelector::renderLogicalImm32(
7843 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7844 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7845 "Expected G_CONSTANT");
7846 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7851void AArch64InstructionSelector::renderLogicalImm64(
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::renderUbsanTrap(MachineInstrBuilder &MIB,
7861 const MachineInstr &
MI,
7863 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7864 "Expected G_UBSANTRAP");
7865 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7868void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7869 const MachineInstr &
MI,
7871 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7872 "Expected G_FCONSTANT");
7877void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7878 const MachineInstr &
MI,
7880 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7881 "Expected G_FCONSTANT");
7886void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7887 const MachineInstr &
MI,
7889 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7890 "Expected G_FCONSTANT");
7895void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7896 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7897 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7898 "Expected G_FCONSTANT");
7906bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7907 const MachineInstr &
MI,
unsigned NumBytes)
const {
7908 if (!
MI.mayLoadOrStore())
7911 "Expected load/store to have only one mem op!");
7912 return (*
MI.memoperands_begin())->getSize() == NumBytes;
7915bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
7916 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7917 if (
MRI.getType(
MI.getOperand(0).getReg()).getSizeInBits() != 32)
7924 switch (
MI.getOpcode()) {
7927 case TargetOpcode::COPY:
7928 case TargetOpcode::G_BITCAST:
7929 case TargetOpcode::G_TRUNC:
7930 case TargetOpcode::G_PHI:
7940 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
7943 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
7954 auto *OpDef =
MRI.getVRegDef(OpReg);
7955 const LLT &Ty =
MRI.getType(OpReg);
7961 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
7965 MRI.setRegBank(Copy.getReg(0), *DstRB);
7966 MO.setReg(Copy.getReg(0));
7971void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
7975 for (
auto &BB : MF) {
7976 for (
auto &
MI : BB) {
7977 if (
MI.getOpcode() == TargetOpcode::G_PHI)
7982 for (
auto *
MI : Phis) {
8004 bool HasGPROp =
false, HasFPROp =
false;
8008 const LLT &Ty =
MRI.getType(MO.getReg());
8013 const RegisterBank *RB =
MRI.getRegBankOrNull(MO.getReg());
8018 if (RB->
getID() == AArch64::GPRRegBankID)
8024 if (HasGPROp && HasFPROp)
8030InstructionSelector *
8034 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 bool canEmitConjunction(const SDValue Val, bool &CanNegate, bool &MustBeFirst, 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 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 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 unsigned 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()
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.
SpecificConstantMatch m_SpecificICst(APInt RequestedValue)
Matches a constant equal to RequestedValue.
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.