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 Register Src2Reg =
I.getOperand(2).getReg();
5130 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5139 for (
int Val : Mask) {
5142 Val = Val < 0 ? 0 : Val;
5143 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5161 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5168 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5172 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5177 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5178 .addReg(TBL1.getReg(0), 0, AArch64::dsub);
5180 I.eraseFromParent();
5188 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5191 I.eraseFromParent();
5195MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5197 unsigned LaneIdx,
const RegisterBank &RB,
5198 MachineIRBuilder &MIRBuilder)
const {
5199 MachineInstr *InsElt =
nullptr;
5200 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5201 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5205 DstReg =
MRI.createVirtualRegister(DstRC);
5207 unsigned EltSize =
MRI.getType(EltReg).getSizeInBits();
5210 if (RB.
getID() == AArch64::FPRRegBankID) {
5211 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5214 .
addUse(InsSub->getOperand(0).getReg())
5226bool AArch64InstructionSelector::selectUSMovFromExtend(
5227 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5228 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5229 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5230 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5232 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5233 const Register DefReg =
MI.getOperand(0).getReg();
5234 const LLT DstTy =
MRI.getType(DefReg);
5237 if (DstSize != 32 && DstSize != 64)
5240 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5241 MI.getOperand(1).getReg(),
MRI);
5247 const LLT VecTy =
MRI.getType(Src0);
5252 const MachineInstr *ScalarToVector = emitScalarToVector(
5253 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5254 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5260 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5262 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5264 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5266 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5268 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5276 MachineInstr *ExtI =
nullptr;
5277 if (DstSize == 64 && !IsSigned) {
5278 Register NewReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
5279 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5280 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5283 .
addImm(AArch64::sub_32);
5286 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5289 MI.eraseFromParent();
5293MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5294 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5296 if (DstSize == 128) {
5297 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5299 Op = AArch64::MOVIv16b_ns;
5301 Op = AArch64::MOVIv8b_ns;
5304 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5308 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5315MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5316 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5320 if (DstSize == 128) {
5321 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5323 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5325 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5328 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5345MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5346 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5350 if (DstSize == 128) {
5351 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5353 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5355 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5358 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5381MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5382 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5385 if (DstSize == 128) {
5386 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5388 Op = AArch64::MOVIv2d_ns;
5390 Op = AArch64::MOVID;
5393 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5396 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5403MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5404 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5408 if (DstSize == 128) {
5409 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5411 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5413 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5416 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5433MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5434 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5437 bool IsWide =
false;
5438 if (DstSize == 128) {
5439 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5441 Op = AArch64::FMOVv4f32_ns;
5444 Op = AArch64::FMOVv2f32_ns;
5447 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5453 Op = AArch64::FMOVv2f64_ns;
5457 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5462bool AArch64InstructionSelector::selectIndexedExtLoad(
5463 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5466 Register WriteBack = ExtLd.getWritebackReg();
5469 LLT Ty =
MRI.getType(Dst);
5471 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5472 bool IsPre = ExtLd.isPre();
5474 unsigned InsertIntoSubReg = 0;
5480 if ((IsSExt && IsFPR) || Ty.
isVector())
5488 if (MemSizeBits == 8) {
5491 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5493 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5494 NewLdDstTy = IsDst64 ? s64 : s32;
5496 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5497 InsertIntoSubReg = AArch64::bsub;
5500 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5501 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5504 }
else if (MemSizeBits == 16) {
5507 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5509 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5510 NewLdDstTy = IsDst64 ? s64 : s32;
5512 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5513 InsertIntoSubReg = AArch64::hsub;
5516 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5517 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5520 }
else if (MemSizeBits == 32) {
5522 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5525 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5526 InsertIntoSubReg = AArch64::ssub;
5529 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5530 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5542 .addImm(Cst->getSExtValue());
5547 if (InsertIntoSubReg) {
5549 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5552 .
addImm(InsertIntoSubReg);
5555 *getRegClassForTypeOnBank(
MRI.getType(Dst),
5562 MI.eraseFromParent();
5567bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5568 MachineRegisterInfo &
MRI) {
5571 Register WriteBack = Ld.getWritebackReg();
5574 assert(
MRI.getType(Dst).getSizeInBits() <= 128 &&
5575 "Unexpected type for indexed load");
5576 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5578 if (MemSize <
MRI.getType(Dst).getSizeInBytes())
5579 return selectIndexedExtLoad(
MI,
MRI);
5583 static constexpr unsigned GPROpcodes[] = {
5584 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5586 static constexpr unsigned FPROpcodes[] = {
5587 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5594 static constexpr unsigned GPROpcodes[] = {
5595 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5597 static constexpr unsigned FPROpcodes[] = {
5598 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5599 AArch64::LDRDpost, AArch64::LDRQpost};
5612 MI.eraseFromParent();
5616bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5617 MachineRegisterInfo &
MRI) {
5622 LLT ValTy =
MRI.getType(Val);
5627 static constexpr unsigned GPROpcodes[] = {
5628 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5630 static constexpr unsigned FPROpcodes[] = {
5631 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5639 static constexpr unsigned GPROpcodes[] = {
5640 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5642 static constexpr unsigned FPROpcodes[] = {
5643 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5644 AArch64::STRDpost, AArch64::STRQpost};
5657 Str.cloneMemRefs(
I);
5659 I.eraseFromParent();
5664AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5665 MachineIRBuilder &MIRBuilder,
5666 MachineRegisterInfo &
MRI) {
5667 LLT DstTy =
MRI.getType(Dst);
5670 if (DstSize == 128) {
5672 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5677 if (DstSize == 64) {
5680 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5683 .addReg(Mov.getReg(0), 0, AArch64::dsub);
5690 APInt SplatValueAsInt =
5693 : SplatValue->getUniqueInteger();
5696 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5697 MachineInstr *NewOp;
5721 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5725 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5726 unsigned NegOpc) -> MachineInstr * {
5729 APInt NegBits(DstSize, 0);
5730 unsigned NumElts = DstSize / NumBits;
5731 for (
unsigned i = 0; i < NumElts; i++)
5732 NegBits |= Neg << (NumBits * i);
5733 NegBits = DefBits ^ NegBits;
5737 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5738 Register NewDst =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
5740 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5745 if ((R = TryWithFNeg(DefBits, 32, AArch64::FNEGv4f32)) ||
5746 (R = TryWithFNeg(DefBits, 64, AArch64::FNEGv2f64)) ||
5747 (STI.hasFullFP16() &&
5748 (R = TryWithFNeg(DefBits, 16, AArch64::FNEGv8f16))))
5754 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5758 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5760 Dst, *
MRI.getRegClass(CPLoad->getOperand(0).getReg()),
MRI);
5764bool AArch64InstructionSelector::tryOptConstantBuildVec(
5765 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5766 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5768 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5774 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5780 const_cast<ConstantInt *
>(OpMI->getOperand(1).getCImm()));
5781 else if ((OpMI =
getOpcodeDef(TargetOpcode::G_FCONSTANT,
5782 I.getOperand(Idx).getReg(),
MRI)))
5784 const_cast<ConstantFP *
>(OpMI->getOperand(1).getFPImm()));
5789 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB,
MRI))
5791 I.eraseFromParent();
5795bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5796 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5801 Register Dst =
I.getOperand(0).getReg();
5802 Register EltReg =
I.getOperand(1).getReg();
5803 LLT EltTy =
MRI.getType(EltReg);
5811 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5815 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5818 const TargetRegisterClass *DstRC =
5819 getRegClassForTypeOnBank(
MRI.getType(Dst), DstRB);
5824 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5828 I.eraseFromParent();
5833bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5834 MachineRegisterInfo &
MRI) {
5835 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5838 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5839 const LLT EltTy =
MRI.getType(
I.getOperand(1).getReg());
5842 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5844 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5847 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5851 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5852 MachineInstr *ScalarToVec =
5854 I.getOperand(1).getReg(), MIB);
5863 MachineInstr *PrevMI = ScalarToVec;
5864 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5867 Register OpReg =
I.getOperand(i).getReg();
5870 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5877 if (DstSize < 128) {
5879 const TargetRegisterClass *RC =
5883 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5891 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
5892 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5898 Register DstReg =
I.getOperand(0).getReg();
5900 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, 0,
SubReg);
5901 MachineOperand &RegOp =
I.getOperand(1);
5921 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5922 const TargetRegisterClass *RC =
5932bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5935 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5937 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5939 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5942 "Destination must be 64 bits or 128 bits?");
5943 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5944 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5945 assert(
MRI.getType(
Ptr).isPointer() &&
"Expected a pointer type?");
5947 Load.cloneMemRefs(
I);
5949 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5950 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5951 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5952 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
5961bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5962 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5963 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5965 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5967 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5970 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5972 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5973 [](
auto MO) { return MO.getReg(); });
5977 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
5992 .
addImm(LaneNo->getZExtValue())
5994 Load.cloneMemRefs(
I);
5996 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5997 unsigned SubReg = AArch64::qsub0;
5998 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5999 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6000 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6001 : DstOp(
I.getOperand(Idx).
getReg())},
6003 .addReg(SelectedLoadDst, 0,
SubReg + Idx);
6008 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6014void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6017 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6018 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6022 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6023 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6032bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6033 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6034 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6035 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6039 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6040 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6044 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6057 .
addImm(LaneNo->getZExtValue())
6064bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6065 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6078 case Intrinsic::aarch64_ldxp:
6079 case Intrinsic::aarch64_ldaxp: {
6081 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6082 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6088 case Intrinsic::aarch64_neon_ld1x2: {
6089 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6092 Opc = AArch64::LD1Twov8b;
6094 Opc = AArch64::LD1Twov16b;
6096 Opc = AArch64::LD1Twov4h;
6098 Opc = AArch64::LD1Twov8h;
6100 Opc = AArch64::LD1Twov2s;
6102 Opc = AArch64::LD1Twov4s;
6104 Opc = AArch64::LD1Twov2d;
6105 else if (Ty ==
S64 || Ty == P0)
6106 Opc = AArch64::LD1Twov1d;
6109 selectVectorLoadIntrinsic(
Opc, 2,
I);
6112 case Intrinsic::aarch64_neon_ld1x3: {
6113 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6116 Opc = AArch64::LD1Threev8b;
6118 Opc = AArch64::LD1Threev16b;
6120 Opc = AArch64::LD1Threev4h;
6122 Opc = AArch64::LD1Threev8h;
6124 Opc = AArch64::LD1Threev2s;
6126 Opc = AArch64::LD1Threev4s;
6128 Opc = AArch64::LD1Threev2d;
6129 else if (Ty ==
S64 || Ty == P0)
6130 Opc = AArch64::LD1Threev1d;
6133 selectVectorLoadIntrinsic(
Opc, 3,
I);
6136 case Intrinsic::aarch64_neon_ld1x4: {
6137 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6140 Opc = AArch64::LD1Fourv8b;
6142 Opc = AArch64::LD1Fourv16b;
6144 Opc = AArch64::LD1Fourv4h;
6146 Opc = AArch64::LD1Fourv8h;
6148 Opc = AArch64::LD1Fourv2s;
6150 Opc = AArch64::LD1Fourv4s;
6152 Opc = AArch64::LD1Fourv2d;
6153 else if (Ty ==
S64 || Ty == P0)
6154 Opc = AArch64::LD1Fourv1d;
6157 selectVectorLoadIntrinsic(
Opc, 4,
I);
6160 case Intrinsic::aarch64_neon_ld2: {
6161 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6164 Opc = AArch64::LD2Twov8b;
6166 Opc = AArch64::LD2Twov16b;
6168 Opc = AArch64::LD2Twov4h;
6170 Opc = AArch64::LD2Twov8h;
6172 Opc = AArch64::LD2Twov2s;
6174 Opc = AArch64::LD2Twov4s;
6176 Opc = AArch64::LD2Twov2d;
6177 else if (Ty ==
S64 || Ty == P0)
6178 Opc = AArch64::LD1Twov1d;
6181 selectVectorLoadIntrinsic(
Opc, 2,
I);
6184 case Intrinsic::aarch64_neon_ld2lane: {
6185 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6188 Opc = AArch64::LD2i8;
6190 Opc = AArch64::LD2i16;
6192 Opc = AArch64::LD2i32;
6195 Opc = AArch64::LD2i64;
6198 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6202 case Intrinsic::aarch64_neon_ld2r: {
6203 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6206 Opc = AArch64::LD2Rv8b;
6208 Opc = AArch64::LD2Rv16b;
6210 Opc = AArch64::LD2Rv4h;
6212 Opc = AArch64::LD2Rv8h;
6214 Opc = AArch64::LD2Rv2s;
6216 Opc = AArch64::LD2Rv4s;
6218 Opc = AArch64::LD2Rv2d;
6219 else if (Ty ==
S64 || Ty == P0)
6220 Opc = AArch64::LD2Rv1d;
6223 selectVectorLoadIntrinsic(
Opc, 2,
I);
6226 case Intrinsic::aarch64_neon_ld3: {
6227 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6230 Opc = AArch64::LD3Threev8b;
6232 Opc = AArch64::LD3Threev16b;
6234 Opc = AArch64::LD3Threev4h;
6236 Opc = AArch64::LD3Threev8h;
6238 Opc = AArch64::LD3Threev2s;
6240 Opc = AArch64::LD3Threev4s;
6242 Opc = AArch64::LD3Threev2d;
6243 else if (Ty ==
S64 || Ty == P0)
6244 Opc = AArch64::LD1Threev1d;
6247 selectVectorLoadIntrinsic(
Opc, 3,
I);
6250 case Intrinsic::aarch64_neon_ld3lane: {
6251 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6254 Opc = AArch64::LD3i8;
6256 Opc = AArch64::LD3i16;
6258 Opc = AArch64::LD3i32;
6261 Opc = AArch64::LD3i64;
6264 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6268 case Intrinsic::aarch64_neon_ld3r: {
6269 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6272 Opc = AArch64::LD3Rv8b;
6274 Opc = AArch64::LD3Rv16b;
6276 Opc = AArch64::LD3Rv4h;
6278 Opc = AArch64::LD3Rv8h;
6280 Opc = AArch64::LD3Rv2s;
6282 Opc = AArch64::LD3Rv4s;
6284 Opc = AArch64::LD3Rv2d;
6285 else if (Ty ==
S64 || Ty == P0)
6286 Opc = AArch64::LD3Rv1d;
6289 selectVectorLoadIntrinsic(
Opc, 3,
I);
6292 case Intrinsic::aarch64_neon_ld4: {
6293 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6296 Opc = AArch64::LD4Fourv8b;
6298 Opc = AArch64::LD4Fourv16b;
6300 Opc = AArch64::LD4Fourv4h;
6302 Opc = AArch64::LD4Fourv8h;
6304 Opc = AArch64::LD4Fourv2s;
6306 Opc = AArch64::LD4Fourv4s;
6308 Opc = AArch64::LD4Fourv2d;
6309 else if (Ty ==
S64 || Ty == P0)
6310 Opc = AArch64::LD1Fourv1d;
6313 selectVectorLoadIntrinsic(
Opc, 4,
I);
6316 case Intrinsic::aarch64_neon_ld4lane: {
6317 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6320 Opc = AArch64::LD4i8;
6322 Opc = AArch64::LD4i16;
6324 Opc = AArch64::LD4i32;
6327 Opc = AArch64::LD4i64;
6330 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6334 case Intrinsic::aarch64_neon_ld4r: {
6335 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6338 Opc = AArch64::LD4Rv8b;
6340 Opc = AArch64::LD4Rv16b;
6342 Opc = AArch64::LD4Rv4h;
6344 Opc = AArch64::LD4Rv8h;
6346 Opc = AArch64::LD4Rv2s;
6348 Opc = AArch64::LD4Rv4s;
6350 Opc = AArch64::LD4Rv2d;
6351 else if (Ty ==
S64 || Ty == P0)
6352 Opc = AArch64::LD4Rv1d;
6355 selectVectorLoadIntrinsic(
Opc, 4,
I);
6358 case Intrinsic::aarch64_neon_st1x2: {
6359 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6362 Opc = AArch64::ST1Twov8b;
6364 Opc = AArch64::ST1Twov16b;
6366 Opc = AArch64::ST1Twov4h;
6368 Opc = AArch64::ST1Twov8h;
6370 Opc = AArch64::ST1Twov2s;
6372 Opc = AArch64::ST1Twov4s;
6374 Opc = AArch64::ST1Twov2d;
6375 else if (Ty ==
S64 || Ty == P0)
6376 Opc = AArch64::ST1Twov1d;
6379 selectVectorStoreIntrinsic(
I, 2,
Opc);
6382 case Intrinsic::aarch64_neon_st1x3: {
6383 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6386 Opc = AArch64::ST1Threev8b;
6388 Opc = AArch64::ST1Threev16b;
6390 Opc = AArch64::ST1Threev4h;
6392 Opc = AArch64::ST1Threev8h;
6394 Opc = AArch64::ST1Threev2s;
6396 Opc = AArch64::ST1Threev4s;
6398 Opc = AArch64::ST1Threev2d;
6399 else if (Ty ==
S64 || Ty == P0)
6400 Opc = AArch64::ST1Threev1d;
6403 selectVectorStoreIntrinsic(
I, 3,
Opc);
6406 case Intrinsic::aarch64_neon_st1x4: {
6407 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6410 Opc = AArch64::ST1Fourv8b;
6412 Opc = AArch64::ST1Fourv16b;
6414 Opc = AArch64::ST1Fourv4h;
6416 Opc = AArch64::ST1Fourv8h;
6418 Opc = AArch64::ST1Fourv2s;
6420 Opc = AArch64::ST1Fourv4s;
6422 Opc = AArch64::ST1Fourv2d;
6423 else if (Ty ==
S64 || Ty == P0)
6424 Opc = AArch64::ST1Fourv1d;
6427 selectVectorStoreIntrinsic(
I, 4,
Opc);
6430 case Intrinsic::aarch64_neon_st2: {
6431 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6434 Opc = AArch64::ST2Twov8b;
6436 Opc = AArch64::ST2Twov16b;
6438 Opc = AArch64::ST2Twov4h;
6440 Opc = AArch64::ST2Twov8h;
6442 Opc = AArch64::ST2Twov2s;
6444 Opc = AArch64::ST2Twov4s;
6446 Opc = AArch64::ST2Twov2d;
6447 else if (Ty ==
S64 || Ty == P0)
6448 Opc = AArch64::ST1Twov1d;
6451 selectVectorStoreIntrinsic(
I, 2,
Opc);
6454 case Intrinsic::aarch64_neon_st3: {
6455 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6458 Opc = AArch64::ST3Threev8b;
6460 Opc = AArch64::ST3Threev16b;
6462 Opc = AArch64::ST3Threev4h;
6464 Opc = AArch64::ST3Threev8h;
6466 Opc = AArch64::ST3Threev2s;
6468 Opc = AArch64::ST3Threev4s;
6470 Opc = AArch64::ST3Threev2d;
6471 else if (Ty ==
S64 || Ty == P0)
6472 Opc = AArch64::ST1Threev1d;
6475 selectVectorStoreIntrinsic(
I, 3,
Opc);
6478 case Intrinsic::aarch64_neon_st4: {
6479 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6482 Opc = AArch64::ST4Fourv8b;
6484 Opc = AArch64::ST4Fourv16b;
6486 Opc = AArch64::ST4Fourv4h;
6488 Opc = AArch64::ST4Fourv8h;
6490 Opc = AArch64::ST4Fourv2s;
6492 Opc = AArch64::ST4Fourv4s;
6494 Opc = AArch64::ST4Fourv2d;
6495 else if (Ty ==
S64 || Ty == P0)
6496 Opc = AArch64::ST1Fourv1d;
6499 selectVectorStoreIntrinsic(
I, 4,
Opc);
6502 case Intrinsic::aarch64_neon_st2lane: {
6503 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6506 Opc = AArch64::ST2i8;
6508 Opc = AArch64::ST2i16;
6510 Opc = AArch64::ST2i32;
6513 Opc = AArch64::ST2i64;
6516 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6520 case Intrinsic::aarch64_neon_st3lane: {
6521 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6524 Opc = AArch64::ST3i8;
6526 Opc = AArch64::ST3i16;
6528 Opc = AArch64::ST3i32;
6531 Opc = AArch64::ST3i64;
6534 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6538 case Intrinsic::aarch64_neon_st4lane: {
6539 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6542 Opc = AArch64::ST4i8;
6544 Opc = AArch64::ST4i16;
6546 Opc = AArch64::ST4i32;
6549 Opc = AArch64::ST4i64;
6552 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6556 case Intrinsic::aarch64_mops_memset_tag: {
6569 Register DstDef =
I.getOperand(0).getReg();
6571 Register DstUse =
I.getOperand(2).getReg();
6572 Register ValUse =
I.getOperand(3).getReg();
6573 Register SizeUse =
I.getOperand(4).getReg();
6580 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6581 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6588 I.eraseFromParent();
6592bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6593 MachineRegisterInfo &
MRI) {
6599 case Intrinsic::ptrauth_resign: {
6600 Register DstReg =
I.getOperand(0).getReg();
6601 Register ValReg =
I.getOperand(2).getReg();
6602 uint64_t AUTKey =
I.getOperand(3).getImm();
6603 Register AUTDisc =
I.getOperand(4).getReg();
6604 uint64_t PACKey =
I.getOperand(5).getImm();
6605 Register PACDisc =
I.getOperand(6).getReg();
6608 uint16_t AUTConstDiscC = 0;
6609 std::tie(AUTConstDiscC, AUTAddrDisc) =
6613 uint16_t PACConstDiscC = 0;
6614 std::tie(PACConstDiscC, PACAddrDisc) =
6617 MIB.
buildCopy({AArch64::X16}, {ValReg});
6618 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6630 I.eraseFromParent();
6633 case Intrinsic::ptrauth_auth: {
6634 Register DstReg =
I.getOperand(0).getReg();
6635 Register ValReg =
I.getOperand(2).getReg();
6636 uint64_t AUTKey =
I.getOperand(3).getImm();
6637 Register AUTDisc =
I.getOperand(4).getReg();
6640 uint16_t AUTConstDiscC = 0;
6641 std::tie(AUTConstDiscC, AUTAddrDisc) =
6645 MIB.
buildCopy({AArch64::X16}, {ValReg});
6646 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6655 MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
6667 I.eraseFromParent();
6670 case Intrinsic::frameaddress:
6671 case Intrinsic::returnaddress: {
6672 MachineFunction &MF = *
I.getParent()->getParent();
6675 unsigned Depth =
I.getOperand(2).getImm();
6676 Register DstReg =
I.getOperand(0).getReg();
6679 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6680 if (!MFReturnAddr) {
6685 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6688 if (STI.hasPAuth()) {
6689 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6696 I.eraseFromParent();
6703 Register NextFrame =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
6705 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6707 FrameAddr = NextFrame;
6710 if (IntrinID == Intrinsic::frameaddress)
6715 if (STI.hasPAuth()) {
6716 Register TmpReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
6717 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6718 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6727 I.eraseFromParent();
6730 case Intrinsic::aarch64_neon_tbl2:
6731 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6733 case Intrinsic::aarch64_neon_tbl3:
6734 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6737 case Intrinsic::aarch64_neon_tbl4:
6738 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6740 case Intrinsic::aarch64_neon_tbx2:
6741 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6743 case Intrinsic::aarch64_neon_tbx3:
6744 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6746 case Intrinsic::aarch64_neon_tbx4:
6747 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6749 case Intrinsic::swift_async_context_addr:
6750 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6757 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6758 I.eraseFromParent();
6793bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6794 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6795 Register DefReg =
I.getOperand(0).getReg();
6796 Register Addr =
I.getOperand(1).getReg();
6797 uint64_t
Key =
I.getOperand(2).getImm();
6798 Register AddrDisc =
I.getOperand(3).getReg();
6799 uint64_t Disc =
I.getOperand(4).getImm();
6809 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6815 if (!
MRI.hasOneDef(Addr))
6819 const MachineInstr *
DefMI = &*
MRI.def_instr_begin(Addr);
6822 if (!
MRI.hasOneDef(OffsetReg))
6824 const MachineInstr &OffsetMI = *
MRI.def_instr_begin(OffsetReg);
6825 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6829 if (!
MRI.hasOneDef(Addr))
6832 DefMI = &*
MRI.def_instr_begin(Addr);
6837 const GlobalValue *GV;
6848 MachineIRBuilder MIB(
I);
6854 "unsupported non-GOT op flags on ptrauth global reference");
6856 "unsupported non-GOT reference to weak ptrauth global");
6859 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6866 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6867 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6868 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6871 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6876 I.eraseFromParent();
6888 "unsupported non-zero offset in weak ptrauth global reference");
6893 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6894 .addGlobalAddress(GV,
Offset)
6899 I.eraseFromParent();
6903void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6904 MachineRegisterInfo &
MRI,
6905 unsigned NumVec,
unsigned Opc1,
6906 unsigned Opc2,
bool isExt) {
6907 Register DstReg =
I.getOperand(0).getReg();
6912 for (
unsigned i = 0; i < NumVec; i++)
6913 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6916 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6917 MachineInstrBuilder
Instr;
6924 I.eraseFromParent();
6927InstructionSelector::ComplexRendererFns
6928AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6930 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6931 return std::nullopt;
6932 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6933 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6936InstructionSelector::ComplexRendererFns
6937AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6939 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6940 return std::nullopt;
6941 uint64_t Enc = 31 - *MaybeImmed;
6942 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6945InstructionSelector::ComplexRendererFns
6946AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
6948 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6949 return std::nullopt;
6950 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
6951 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6954InstructionSelector::ComplexRendererFns
6955AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
6957 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6958 return std::nullopt;
6959 uint64_t Enc = 63 - *MaybeImmed;
6960 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6968InstructionSelector::ComplexRendererFns
6969AArch64InstructionSelector::select12BitValueWithLeftShift(
6970 uint64_t Immed)
const {
6972 if (Immed >> 12 == 0) {
6974 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
6976 Immed = Immed >> 12;
6978 return std::nullopt;
6982 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
6983 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
6990InstructionSelector::ComplexRendererFns
6991AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
6998 if (MaybeImmed == std::nullopt)
6999 return std::nullopt;
7000 return select12BitValueWithLeftShift(*MaybeImmed);
7005InstructionSelector::ComplexRendererFns
7006AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7010 return std::nullopt;
7012 if (MaybeImmed == std::nullopt)
7013 return std::nullopt;
7014 uint64_t Immed = *MaybeImmed;
7020 return std::nullopt;
7025 if (
MRI.getType(Root.
getReg()).getSizeInBits() == 32)
7026 Immed = ~((uint32_t)Immed) + 1;
7028 Immed = ~Immed + 1ULL;
7030 if (Immed & 0xFFFFFFFFFF000000ULL)
7031 return std::nullopt;
7033 Immed &= 0xFFFFFFULL;
7034 return select12BitValueWithLeftShift(Immed);
7051std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7052 MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7053 if (
MI.getOpcode() == AArch64::G_SHL) {
7057 MI.getOperand(2).getReg(),
MRI)) {
7058 const APInt ShiftVal = ValAndVeg->Value;
7061 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7064 return std::nullopt;
7072bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7073 MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7074 bool IsAddrOperand)
const {
7078 if (
MRI.hasOneNonDBGUse(DefReg) ||
7079 MI.getParent()->getParent()->getFunction().hasOptSize())
7082 if (IsAddrOperand) {
7084 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7088 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7089 MachineInstr *OffsetInst =
7095 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7105 return all_of(
MRI.use_nodbg_instructions(DefReg),
7106 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7120InstructionSelector::ComplexRendererFns
7121AArch64InstructionSelector::selectExtendedSHL(
7122 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7123 unsigned SizeInBytes,
bool WantsExt)
const {
7124 assert(
Base.isReg() &&
"Expected base to be a register operand");
7125 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7128 MachineInstr *OffsetInst =
MRI.getVRegDef(
Offset.getReg());
7130 unsigned OffsetOpc = OffsetInst->
getOpcode();
7131 bool LookedThroughZExt =
false;
7132 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7134 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7135 return std::nullopt;
7139 LookedThroughZExt =
true;
7141 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7142 return std::nullopt;
7145 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7146 if (LegalShiftVal == 0)
7147 return std::nullopt;
7148 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7149 return std::nullopt;
7160 if (OffsetOpc == TargetOpcode::G_SHL)
7161 return std::nullopt;
7167 return std::nullopt;
7172 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7176 if (OffsetOpc == TargetOpcode::G_MUL) {
7178 return std::nullopt;
7184 if ((ImmVal & 0x7) != ImmVal)
7185 return std::nullopt;
7189 if (ImmVal != LegalShiftVal)
7190 return std::nullopt;
7192 unsigned SignExtend = 0;
7196 if (!LookedThroughZExt) {
7198 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7200 return std::nullopt;
7205 return std::nullopt;
7210 MachineIRBuilder MIB(*
MRI.getVRegDef(Root.
getReg()));
7211 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7216 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7217 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7218 [=](MachineInstrBuilder &MIB) {
7221 MIB.addImm(SignExtend);
7234InstructionSelector::ComplexRendererFns
7235AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7236 MachineOperand &Root,
unsigned SizeInBytes)
const {
7238 return std::nullopt;
7253 MachineInstr *PtrAdd =
7255 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7256 return std::nullopt;
7260 MachineInstr *OffsetInst =
7262 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7275InstructionSelector::ComplexRendererFns
7276AArch64InstructionSelector::selectAddrModeRegisterOffset(
7277 MachineOperand &Root)
const {
7281 MachineInstr *Gep =
MRI.getVRegDef(Root.
getReg());
7282 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7283 return std::nullopt;
7289 return std::nullopt;
7292 return {{[=](MachineInstrBuilder &MIB) {
7295 [=](MachineInstrBuilder &MIB) {
7298 [=](MachineInstrBuilder &MIB) {
7308InstructionSelector::ComplexRendererFns
7309AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7310 unsigned SizeInBytes)
const {
7313 return std::nullopt;
7314 MachineInstr *PtrAdd =
7317 return std::nullopt;
7335 unsigned Scale =
Log2_32(SizeInBytes);
7336 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7340 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7341 ImmOff < (0x1000 << Scale))
7342 return std::nullopt;
7347 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7351 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7357 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7358 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7363 return std::nullopt;
7367 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7373 return selectAddrModeRegisterOffset(Root);
7382InstructionSelector::ComplexRendererFns
7383AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7384 unsigned SizeInBytes)
const {
7387 MachineInstr *PtrAdd =
7389 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7390 return std::nullopt;
7411 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7420 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7421 return std::nullopt;
7425 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7427 return std::nullopt;
7430 MachineIRBuilder MIB(*PtrAdd);
7432 AArch64::GPR32RegClass, MIB);
7436 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7437 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7438 [=](MachineInstrBuilder &MIB) {
7439 MIB.addImm(SignExtend);
7449InstructionSelector::ComplexRendererFns
7450AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7451 unsigned Size)
const {
7452 MachineRegisterInfo &
MRI =
7456 return std::nullopt;
7458 if (!isBaseWithConstantOffset(Root,
MRI))
7459 return std::nullopt;
7461 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7463 MachineOperand &OffImm = RootDef->
getOperand(2);
7464 if (!OffImm.
isReg())
7465 return std::nullopt;
7467 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7468 return std::nullopt;
7470 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7472 return std::nullopt;
7475 if (RHSC >= -256 && RHSC < 256) {
7478 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7479 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7482 return std::nullopt;
7485InstructionSelector::ComplexRendererFns
7486AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7488 MachineRegisterInfo &
MRI)
const {
7489 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7490 return std::nullopt;
7493 return std::nullopt;
7498 return std::nullopt;
7502 return std::nullopt;
7506 return std::nullopt;
7509 MachineIRBuilder MIRBuilder(RootDef);
7511 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7512 [=](MachineInstrBuilder &MIB) {
7513 MIB.addGlobalAddress(GV,
Offset,
7522InstructionSelector::ComplexRendererFns
7523AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7524 unsigned Size)
const {
7529 return std::nullopt;
7531 MachineInstr *RootDef =
MRI.getVRegDef(Root.
getReg());
7532 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7534 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7535 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7543 MachineInstr *RootParent = Root.
getParent();
7545 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7547 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7552 if (isBaseWithConstantOffset(Root,
MRI)) {
7555 MachineInstr *LHSDef =
MRI.getVRegDef(
LHS.getReg());
7556 MachineInstr *RHSDef =
MRI.getVRegDef(
RHS.getReg());
7560 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7561 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7563 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7564 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7568 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7569 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7576 if (selectAddrModeUnscaled(Root,
Size))
7577 return std::nullopt;
7580 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7581 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7588 switch (
MI.getOpcode()) {
7591 case TargetOpcode::G_SHL:
7593 case TargetOpcode::G_LSHR:
7595 case TargetOpcode::G_ASHR:
7597 case TargetOpcode::G_ROTR:
7604InstructionSelector::ComplexRendererFns
7605AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7606 bool AllowROR)
const {
7608 return std::nullopt;
7609 MachineRegisterInfo &
MRI =
7614 MachineInstr *ShiftInst =
MRI.getVRegDef(Root.
getReg());
7617 return std::nullopt;
7619 return std::nullopt;
7620 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7621 return std::nullopt;
7624 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7627 return std::nullopt;
7631 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7634 unsigned NumBits =
MRI.getType(ShiftReg).getSizeInBits();
7635 unsigned Val = *Immed & (NumBits - 1);
7638 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7639 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7643 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7644 unsigned Opc =
MI.getOpcode();
7647 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7649 if (
Opc == TargetOpcode::G_SEXT)
7650 Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7652 Size =
MI.getOperand(2).getImm();
7653 assert(
Size != 64 &&
"Extend from 64 bits?");
7666 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7667 unsigned Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7668 assert(
Size != 64 &&
"Extend from 64 bits?");
7683 if (
Opc != TargetOpcode::G_AND)
7689 uint64_t AndMask = *MaybeAndMask;
7702Register AArch64InstructionSelector::moveScalarRegClass(
7703 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7704 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7705 auto Ty =
MRI.getType(
Reg);
7714 return Copy.getReg(0);
7719InstructionSelector::ComplexRendererFns
7720AArch64InstructionSelector::selectArithExtendedRegister(
7721 MachineOperand &Root)
const {
7723 return std::nullopt;
7724 MachineRegisterInfo &
MRI =
7727 uint64_t ShiftVal = 0;
7732 return std::nullopt;
7734 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7735 return std::nullopt;
7738 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7743 return std::nullopt;
7744 ShiftVal = *MaybeShiftVal;
7746 return std::nullopt;
7751 return std::nullopt;
7752 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7754 return std::nullopt;
7758 Ext = getExtendTypeForInst(*RootDef,
MRI);
7760 return std::nullopt;
7768 MachineInstr *ExtInst =
MRI.getVRegDef(ExtReg);
7769 if (isDef32(*ExtInst))
7770 return std::nullopt;
7776 MachineIRBuilder MIB(*RootDef);
7777 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7779 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7780 [=](MachineInstrBuilder &MIB) {
7781 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7785InstructionSelector::ComplexRendererFns
7786AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7788 return std::nullopt;
7789 MachineRegisterInfo &
MRI =
7793 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7798 return std::nullopt;
7800 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7803 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7806 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7811 LaneIdx->Value.getSExtValue() == 1) {
7813 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7817 return std::nullopt;
7820void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7821 const MachineInstr &
MI,
7823 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7824 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7825 "Expected G_CONSTANT");
7826 std::optional<int64_t> CstVal =
7828 assert(CstVal &&
"Expected constant value");
7832void AArch64InstructionSelector::renderLogicalImm32(
7833 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7834 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7835 "Expected G_CONSTANT");
7836 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7841void AArch64InstructionSelector::renderLogicalImm64(
7842 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7843 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7844 "Expected G_CONSTANT");
7845 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7850void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7851 const MachineInstr &
MI,
7853 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7854 "Expected G_UBSANTRAP");
7855 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7858void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7859 const MachineInstr &
MI,
7861 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7862 "Expected G_FCONSTANT");
7867void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7868 const MachineInstr &
MI,
7870 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7871 "Expected G_FCONSTANT");
7876void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7877 const MachineInstr &
MI,
7879 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7880 "Expected G_FCONSTANT");
7885void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7886 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7887 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7888 "Expected G_FCONSTANT");
7896bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7897 const MachineInstr &
MI,
unsigned NumBytes)
const {
7898 if (!
MI.mayLoadOrStore())
7901 "Expected load/store to have only one mem op!");
7902 return (*
MI.memoperands_begin())->getSize() == NumBytes;
7905bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
7906 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
7907 if (
MRI.getType(
MI.getOperand(0).getReg()).getSizeInBits() != 32)
7914 switch (
MI.getOpcode()) {
7917 case TargetOpcode::COPY:
7918 case TargetOpcode::G_BITCAST:
7919 case TargetOpcode::G_TRUNC:
7920 case TargetOpcode::G_PHI:
7930 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
7933 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
7944 auto *OpDef =
MRI.getVRegDef(OpReg);
7945 const LLT &Ty =
MRI.getType(OpReg);
7951 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
7955 MRI.setRegBank(Copy.getReg(0), *DstRB);
7956 MO.setReg(Copy.getReg(0));
7961void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
7965 for (
auto &BB : MF) {
7966 for (
auto &
MI : BB) {
7967 if (
MI.getOpcode() == TargetOpcode::G_PHI)
7972 for (
auto *
MI : Phis) {
7994 bool HasGPROp =
false, HasFPROp =
false;
7998 const LLT &Ty =
MRI.getType(MO.getReg());
8003 const RegisterBank *RB =
MRI.getRegBankOrNull(MO.getReg());
8008 if (RB->
getID() == AArch64::GPRRegBankID)
8014 if (HasGPROp && HasFPROp)
8020InstructionSelector *
8024 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()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Undef
Value of the register doesn't matter.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.