45#include "llvm/IR/IntrinsicsAArch64.h"
52#define DEBUG_TYPE "aarch64-isel"
65#define GET_GLOBALISEL_PREDICATE_BITSET
66#include "AArch64GenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATE_BITSET
87 ProduceNonFlagSettingCondBr =
135 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
213 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
215 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
217 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
219 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
233 unsigned Opc1,
unsigned Opc2,
bool isExt);
239 unsigned emitConstantPoolEntry(
const Constant *CPVal,
258 std::optional<CmpInst::Predicate> = std::nullopt)
const;
261 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
262 std::initializer_list<llvm::SrcOp> SrcOps,
264 const ComplexRendererFns &RenderFns = std::nullopt)
const;
299 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
322 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
344 std::pair<MachineInstr *, AArch64CC::CondCode>
379 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
380 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
381 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
382 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
384 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
386 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
389 unsigned Size)
const;
391 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
392 return selectAddrModeUnscaled(Root, 1);
394 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
395 return selectAddrModeUnscaled(Root, 2);
397 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
398 return selectAddrModeUnscaled(Root, 4);
400 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
401 return selectAddrModeUnscaled(Root, 8);
403 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
404 return selectAddrModeUnscaled(Root, 16);
409 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
413 unsigned Size)
const;
415 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
416 return selectAddrModeIndexed(Root, Width / 8);
425 bool IsAddrOperand)
const;
428 unsigned SizeInBytes)
const;
436 bool WantsExt)
const;
437 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
439 unsigned SizeInBytes)
const;
441 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
442 return selectAddrModeXRO(Root, Width / 8);
446 unsigned SizeInBytes)
const;
448 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
449 return selectAddrModeWRO(Root, Width / 8);
453 bool AllowROR =
false)
const;
455 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
456 return selectShiftedRegister(Root);
459 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
460 return selectShiftedRegister(Root,
true);
470 bool IsLoadStore =
false)
const;
481 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
485 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
490 bool isReciprocal =
false)
const;
492 int OpIdx = -1)
const;
497 int OpIdx = -1)
const;
499 int OpIdx = -1)
const;
501 int OpIdx = -1)
const;
505 int OpIdx = -1)
const;
507 int OpIdx = -1)
const;
509 int OpIdx = -1)
const;
512 int OpIdx = -1)
const;
518 bool tryOptSelect(
GSelect &Sel);
525 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
538 bool ProduceNonFlagSettingCondBr =
false;
547#define GET_GLOBALISEL_PREDICATES_DECL
548#include "AArch64GenGlobalISel.inc"
549#undef GET_GLOBALISEL_PREDICATES_DECL
553#define GET_GLOBALISEL_TEMPORARIES_DECL
554#include "AArch64GenGlobalISel.inc"
555#undef GET_GLOBALISEL_TEMPORARIES_DECL
560#define GET_GLOBALISEL_IMPL
561#include "AArch64GenGlobalISel.inc"
562#undef GET_GLOBALISEL_IMPL
564AArch64InstructionSelector::AArch64InstructionSelector(
567 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
570#include
"AArch64GenGlobalISel.inc"
573#include
"AArch64GenGlobalISel.inc"
585 bool GetAllRegSet =
false) {
586 if (RB.
getID() == AArch64::GPRRegBankID) {
587 if (Ty.getSizeInBits() <= 32)
588 return GetAllRegSet ? &AArch64::GPR32allRegClass
589 : &AArch64::GPR32RegClass;
590 if (Ty.getSizeInBits() == 64)
591 return GetAllRegSet ? &AArch64::GPR64allRegClass
592 : &AArch64::GPR64RegClass;
593 if (Ty.getSizeInBits() == 128)
594 return &AArch64::XSeqPairsClassRegClass;
598 if (RB.
getID() == AArch64::FPRRegBankID) {
599 switch (Ty.getSizeInBits()) {
601 return &AArch64::FPR8RegClass;
603 return &AArch64::FPR16RegClass;
605 return &AArch64::FPR32RegClass;
607 return &AArch64::FPR64RegClass;
609 return &AArch64::FPR128RegClass;
621 bool GetAllRegSet =
false) {
624 "Expected FPR regbank for scalable type size");
625 return &AArch64::ZPRRegClass;
628 unsigned RegBankID = RB.
getID();
630 if (RegBankID == AArch64::GPRRegBankID) {
632 if (SizeInBits <= 32)
633 return GetAllRegSet ? &AArch64::GPR32allRegClass
634 : &AArch64::GPR32RegClass;
635 if (SizeInBits == 64)
636 return GetAllRegSet ? &AArch64::GPR64allRegClass
637 : &AArch64::GPR64RegClass;
638 if (SizeInBits == 128)
639 return &AArch64::XSeqPairsClassRegClass;
642 if (RegBankID == AArch64::FPRRegBankID) {
645 "Unexpected scalable register size");
646 return &AArch64::ZPRRegClass;
649 switch (SizeInBits) {
653 return &AArch64::FPR8RegClass;
655 return &AArch64::FPR16RegClass;
657 return &AArch64::FPR32RegClass;
659 return &AArch64::FPR64RegClass;
661 return &AArch64::FPR128RegClass;
671 switch (
TRI.getRegSizeInBits(*RC)) {
673 SubReg = AArch64::bsub;
676 SubReg = AArch64::hsub;
679 if (RC != &AArch64::FPR32RegClass)
680 SubReg = AArch64::sub_32;
682 SubReg = AArch64::ssub;
685 SubReg = AArch64::dsub;
689 dbgs() <<
"Couldn't find appropriate subregister for register class.");
698 switch (RB.
getID()) {
699 case AArch64::GPRRegBankID:
701 case AArch64::FPRRegBankID:
724 const unsigned RegClassIDs[],
726 unsigned NumRegs = Regs.
size();
729 assert(NumRegs >= 2 && NumRegs <= 4 &&
730 "Only support between two and 4 registers in a tuple!");
732 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
734 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
735 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
736 RegSequence.addUse(Regs[
I]);
737 RegSequence.addImm(SubRegs[
I]);
739 return RegSequence.getReg(0);
744 static const unsigned RegClassIDs[] = {
745 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
746 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
747 AArch64::dsub2, AArch64::dsub3};
748 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
753 static const unsigned RegClassIDs[] = {
754 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
755 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
756 AArch64::qsub2, AArch64::qsub3};
757 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
762 auto &
MBB = *
MI.getParent();
763 auto &MF = *
MBB.getParent();
764 auto &MRI = MF.getRegInfo();
770 else if (Root.
isReg()) {
775 Immed = ValAndVReg->Value.getSExtValue();
798 for (
auto &MO :
I.operands()) {
801 LLVM_DEBUG(
dbgs() <<
"Generic inst non-reg operands are unsupported\n");
809 if (!MO.getReg().isVirtual()) {
810 LLVM_DEBUG(
dbgs() <<
"Generic inst has physical register operand\n");
820 if (PrevOpBank && OpBank != PrevOpBank) {
821 LLVM_DEBUG(
dbgs() <<
"Generic inst operands have different banks\n");
836 case AArch64::GPRRegBankID:
838 switch (GenericOpc) {
839 case TargetOpcode::G_SHL:
840 return AArch64::LSLVWr;
841 case TargetOpcode::G_LSHR:
842 return AArch64::LSRVWr;
843 case TargetOpcode::G_ASHR:
844 return AArch64::ASRVWr;
848 }
else if (OpSize == 64) {
849 switch (GenericOpc) {
850 case TargetOpcode::G_PTR_ADD:
851 return AArch64::ADDXrr;
852 case TargetOpcode::G_SHL:
853 return AArch64::LSLVXr;
854 case TargetOpcode::G_LSHR:
855 return AArch64::LSRVXr;
856 case TargetOpcode::G_ASHR:
857 return AArch64::ASRVXr;
863 case AArch64::FPRRegBankID:
866 switch (GenericOpc) {
867 case TargetOpcode::G_FADD:
868 return AArch64::FADDSrr;
869 case TargetOpcode::G_FSUB:
870 return AArch64::FSUBSrr;
871 case TargetOpcode::G_FMUL:
872 return AArch64::FMULSrr;
873 case TargetOpcode::G_FDIV:
874 return AArch64::FDIVSrr;
879 switch (GenericOpc) {
880 case TargetOpcode::G_FADD:
881 return AArch64::FADDDrr;
882 case TargetOpcode::G_FSUB:
883 return AArch64::FSUBDrr;
884 case TargetOpcode::G_FMUL:
885 return AArch64::FMULDrr;
886 case TargetOpcode::G_FDIV:
887 return AArch64::FDIVDrr;
888 case TargetOpcode::G_OR:
889 return AArch64::ORRv8i8;
906 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
908 case AArch64::GPRRegBankID:
911 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
913 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
915 return isStore ? AArch64::STRWui : AArch64::LDRWui;
917 return isStore ? AArch64::STRXui : AArch64::LDRXui;
920 case AArch64::FPRRegBankID:
923 return isStore ? AArch64::STRBui : AArch64::LDRBui;
925 return isStore ? AArch64::STRHui : AArch64::LDRHui;
927 return isStore ? AArch64::STRSui : AArch64::LDRSui;
929 return isStore ? AArch64::STRDui : AArch64::LDRDui;
931 return isStore ? AArch64::STRQui : AArch64::LDRQui;
945 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
946 assert(To &&
"Destination register class cannot be null");
947 assert(SubReg &&
"Expected a valid subregister");
951 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
953 RegOp.
setReg(SubRegCopy.getReg(0));
957 if (!
I.getOperand(0).getReg().isPhysical())
967static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
971 Register DstReg =
I.getOperand(0).getReg();
972 Register SrcReg =
I.getOperand(1).getReg();
987 if (SrcRegBank != DstRegBank &&
1006 if (
Reg.isPhysical())
1014 RC = getRegClassForTypeOnBank(Ty, RB);
1017 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
1030 Register DstReg =
I.getOperand(0).getReg();
1031 Register SrcReg =
I.getOperand(1).getReg();
1050 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1054 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1055 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1066 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1067 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
1068 }
else if (SrcSize > DstSize) {
1075 }
else if (DstSize > SrcSize) {
1084 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1088 RegOp.
setReg(PromoteReg);
1107 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1108 I.setDesc(
TII.get(AArch64::COPY));
1109 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1113 I.setDesc(
TII.get(AArch64::COPY));
1121 MachineRegisterInfo &MRI = *MIB.
getMRI();
1124 "Expected both select operands to have the same regbank?");
1130 "Expected 32 bit or 64 bit select only?");
1131 const bool Is32Bit =
Size == 32;
1133 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1134 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1140 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1142 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1157 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1174 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1193 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1209 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1215 if (!TrueCst && !FalseCst)
1218 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1219 if (TrueCst && FalseCst) {
1220 int64_t
T = TrueCst->Value.getSExtValue();
1221 int64_t
F = FalseCst->Value.getSExtValue();
1223 if (
T == 0 &&
F == 1) {
1225 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1231 if (
T == 0 &&
F == -1) {
1233 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1241 int64_t
T = TrueCst->Value.getSExtValue();
1244 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1253 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1262 int64_t
F = FalseCst->Value.getSExtValue();
1265 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1272 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1280 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1281 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1283 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1285 return &*SelectInst;
1290 MachineRegisterInfo *MRI =
nullptr) {
1303 if (ValAndVReg && ValAndVReg->Value == 0)
1310 if (ValAndVReg && ValAndVReg->Value == 0)
1414 assert(
Reg.isValid() &&
"Expected valid register!");
1415 bool HasZext =
false;
1417 unsigned Opc =
MI->getOpcode();
1419 if (!
MI->getOperand(0).isReg() ||
1428 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1429 Opc == TargetOpcode::G_TRUNC) {
1430 if (
Opc == TargetOpcode::G_ZEXT)
1433 Register NextReg =
MI->getOperand(1).getReg();
1447 std::optional<uint64_t>
C;
1452 case TargetOpcode::G_AND:
1453 case TargetOpcode::G_XOR: {
1454 TestReg =
MI->getOperand(1).getReg();
1455 Register ConstantReg =
MI->getOperand(2).getReg();
1466 C = VRegAndVal->Value.getZExtValue();
1468 C = VRegAndVal->Value.getSExtValue();
1472 case TargetOpcode::G_ASHR:
1473 case TargetOpcode::G_LSHR:
1474 case TargetOpcode::G_SHL: {
1475 TestReg =
MI->getOperand(1).getReg();
1479 C = VRegAndVal->Value.getSExtValue();
1495 case TargetOpcode::G_AND:
1497 if ((*
C >> Bit) & 1)
1500 case TargetOpcode::G_SHL:
1503 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1508 case TargetOpcode::G_ASHR:
1513 if (Bit >= TestRegSize)
1514 Bit = TestRegSize - 1;
1516 case TargetOpcode::G_LSHR:
1518 if ((Bit + *
C) < TestRegSize) {
1523 case TargetOpcode::G_XOR:
1532 if ((*
C >> Bit) & 1)
1547MachineInstr *AArch64InstructionSelector::emitTestBit(
1548 Register TestReg, uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1549 MachineIRBuilder &MIB)
const {
1551 assert(ProduceNonFlagSettingCondBr &&
1552 "Cannot emit TB(N)Z with speculation tracking!");
1553 MachineRegisterInfo &MRI = *MIB.
getMRI();
1557 LLT Ty = MRI.
getType(TestReg);
1560 assert(Bit < 64 &&
"Bit is too large!");
1564 bool UseWReg =
Bit < 32;
1565 unsigned NecessarySize = UseWReg ? 32 : 64;
1566 if (
Size != NecessarySize)
1567 TestReg = moveScalarRegClass(
1568 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1571 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1572 {AArch64::TBZW, AArch64::TBNZW}};
1573 unsigned Opc = OpcTable[UseWReg][IsNegative];
1580bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1581 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1582 MachineIRBuilder &MIB)
const {
1583 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1610 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1617 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1621MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1623 MachineBasicBlock *DestMBB,
1624 MachineIRBuilder &MIB)
const {
1625 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1626 MachineRegisterInfo &MRI = *MIB.
getMRI();
1628 AArch64::GPRRegBankID &&
1629 "Expected GPRs only?");
1630 auto Ty = MRI.
getType(CompareReg);
1633 assert(Width <= 64 &&
"Expected width to be at most 64?");
1634 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1635 {AArch64::CBNZW, AArch64::CBNZX}};
1636 unsigned Opc = OpcTable[IsNegative][Width == 64];
1637 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1642bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1643 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1645 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1653 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1657 I.eraseFromParent();
1661bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1662 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1664 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1670 if (!ProduceNonFlagSettingCondBr)
1673 MachineRegisterInfo &MRI = *MIB.
getMRI();
1674 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1689 if (VRegAndVal && !AndInst) {
1690 int64_t
C = VRegAndVal->Value.getSExtValue();
1696 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1697 I.eraseFromParent();
1705 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1706 I.eraseFromParent();
1714 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1715 I.eraseFromParent();
1729 if (VRegAndVal && VRegAndVal->Value == 0) {
1737 tryOptAndIntoCompareBranch(
1739 I.eraseFromParent();
1745 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1747 I.eraseFromParent();
1756bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1757 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1759 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1760 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1764 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1771 I.eraseFromParent();
1775bool AArch64InstructionSelector::selectCompareBranch(
1776 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI) {
1777 Register CondReg =
I.getOperand(0).getReg();
1778 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1782 if (CCMIOpc == TargetOpcode::G_FCMP)
1783 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1784 if (CCMIOpc == TargetOpcode::G_ICMP)
1785 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1790 if (ProduceNonFlagSettingCondBr) {
1791 emitTestBit(CondReg, 0,
true,
1792 I.getOperand(1).getMBB(), MIB);
1793 I.eraseFromParent();
1803 .
addMBB(
I.getOperand(1).getMBB());
1804 I.eraseFromParent();
1824 return std::nullopt;
1826 int64_t Imm = *ShiftImm;
1828 return std::nullopt;
1829 switch (SrcTy.getElementType().getSizeInBits()) {
1832 return std::nullopt;
1835 return std::nullopt;
1839 return std::nullopt;
1843 return std::nullopt;
1847 return std::nullopt;
1853bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1854 MachineRegisterInfo &MRI) {
1855 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1856 Register DstReg =
I.getOperand(0).getReg();
1857 const LLT Ty = MRI.
getType(DstReg);
1858 Register Src1Reg =
I.getOperand(1).getReg();
1859 Register Src2Reg =
I.getOperand(2).getReg();
1870 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1872 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1874 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1876 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1878 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1880 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1882 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1894 I.eraseFromParent();
1898bool AArch64InstructionSelector::selectVectorAshrLshr(
1899 MachineInstr &
I, MachineRegisterInfo &MRI) {
1900 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1901 I.getOpcode() == TargetOpcode::G_LSHR);
1902 Register DstReg =
I.getOperand(0).getReg();
1903 const LLT Ty = MRI.
getType(DstReg);
1904 Register Src1Reg =
I.getOperand(1).getReg();
1905 Register Src2Reg =
I.getOperand(2).getReg();
1910 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1920 unsigned NegOpc = 0;
1921 const TargetRegisterClass *RC =
1922 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1924 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1925 NegOpc = AArch64::NEGv2i64;
1927 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1928 NegOpc = AArch64::NEGv4i32;
1930 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1931 NegOpc = AArch64::NEGv2i32;
1933 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1934 NegOpc = AArch64::NEGv4i16;
1936 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1937 NegOpc = AArch64::NEGv8i16;
1939 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1940 NegOpc = AArch64::NEGv16i8;
1942 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1943 NegOpc = AArch64::NEGv8i8;
1949 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1953 I.eraseFromParent();
1957bool AArch64InstructionSelector::selectVaStartAAPCS(
1958 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI)
const {
1967 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1969 const auto *PtrRegClass =
1970 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1972 const MCInstrDesc &MCIDAddAddr =
1974 const MCInstrDesc &MCIDStoreAddr =
1986 const auto VAList =
I.getOperand(0).getReg();
1989 unsigned OffsetBytes = 0;
1993 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1995 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
2002 const auto *MMO = *
I.memoperands_begin();
2003 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
2006 .
addImm(OffsetBytes / PtrSize)
2008 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2012 OffsetBytes += PtrSize;
2028 const auto PushIntConstant = [&](
const int32_t
Value) {
2029 constexpr int IntSize = 4;
2032 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
2037 const auto *MMO = *
I.memoperands_begin();
2038 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
2041 .
addImm(OffsetBytes / IntSize)
2043 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2046 OffsetBytes += IntSize;
2050 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2053 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2057 I.eraseFromParent();
2061bool AArch64InstructionSelector::selectVaStartDarwin(
2062 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI)
const {
2063 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2064 Register ListReg =
I.getOperand(0).getReg();
2069 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2077 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2085 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2092 I.eraseFromParent();
2096void AArch64InstructionSelector::materializeLargeCMVal(
2097 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2102 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2117 GV, MovZ->getOperand(1).getOffset(), Flags));
2121 MovZ->getOperand(1).getOffset(), Flags));
2127 Register DstReg = BuildMovK(MovZ.getReg(0),
2133bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2138 switch (
I.getOpcode()) {
2139 case TargetOpcode::G_CONSTANT: {
2140 Register DefReg =
I.getOperand(0).getReg();
2141 const LLT DefTy = MRI.
getType(DefReg);
2145 if (PtrSize != 32 && PtrSize != 64)
2151 case TargetOpcode::G_STORE: {
2152 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2153 MachineOperand &SrcOp =
I.getOperand(0);
2166 case TargetOpcode::G_PTR_ADD: {
2170 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2172 return convertPtrAddToAdd(
I, MRI);
2174 case TargetOpcode::G_LOAD: {
2179 Register DstReg =
I.getOperand(0).getReg();
2180 const LLT DstTy = MRI.
getType(DstReg);
2186 case AArch64::G_DUP: {
2188 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2192 MRI.
setType(
I.getOperand(0).getReg(),
2194 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2195 I.getOperand(1).setReg(NewSrc.getReg(0));
2198 case AArch64::G_INSERT_VECTOR_ELT: {
2200 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2201 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2205 MRI.
setType(
I.getOperand(1).getReg(),
2207 MRI.
setType(
I.getOperand(0).getReg(),
2209 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2210 I.getOperand(2).setReg(NewSrc.getReg(0));
2213 case TargetOpcode::G_UITOFP:
2214 case TargetOpcode::G_SITOFP: {
2219 Register SrcReg =
I.getOperand(1).getReg();
2220 LLT SrcTy = MRI.
getType(SrcReg);
2221 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2230 I.getOperand(1).setReg(
Copy.getReg(0));
2232 getRegClassForTypeOnBank(
2233 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2235 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2236 I.setDesc(
TII.get(AArch64::G_SITOF));
2238 I.setDesc(
TII.get(AArch64::G_UITOF));
2256bool AArch64InstructionSelector::convertPtrAddToAdd(
2257 MachineInstr &
I, MachineRegisterInfo &MRI) {
2258 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2259 Register DstReg =
I.getOperand(0).getReg();
2260 Register AddOp1Reg =
I.getOperand(1).getReg();
2261 const LLT PtrTy = MRI.
getType(DstReg);
2265 const LLT CastPtrTy = PtrTy.
isVector()
2277 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2278 MRI.
setType(DstReg, CastPtrTy);
2279 I.getOperand(1).setReg(PtrToInt.getReg(0));
2280 if (!select(*PtrToInt)) {
2281 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2290 I.getOperand(2).setReg(NegatedReg);
2291 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2295bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2296 MachineRegisterInfo &MRI) {
2300 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2301 const auto &MO =
I.getOperand(2);
2306 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2310 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2311 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2313 if (!Imm1Fn || !Imm2Fn)
2317 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2318 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2320 for (
auto &RenderFn : *Imm1Fn)
2322 for (
auto &RenderFn : *Imm2Fn)
2325 I.eraseFromParent();
2330bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2331 MachineInstr &
I, MachineRegisterInfo &MRI) {
2332 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2350 LLT DefDstTy = MRI.
getType(DefDstReg);
2351 Register StoreSrcReg =
I.getOperand(0).getReg();
2352 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2368 I.getOperand(0).setReg(DefDstReg);
2372bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2373 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2374 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2380 switch (
I.getOpcode()) {
2381 case AArch64::G_DUP: {
2384 Register Src =
I.getOperand(1).getReg();
2386 Src, MRI,
true,
true);
2390 Register Dst =
I.getOperand(0).getReg();
2396 if (!emitConstantVector(Dst, CV, MIB, MRI))
2398 I.eraseFromParent();
2401 case TargetOpcode::G_SEXT:
2404 if (selectUSMovFromExtend(
I, MRI))
2407 case TargetOpcode::G_BR:
2409 case TargetOpcode::G_SHL:
2410 return earlySelectSHL(
I, MRI);
2411 case TargetOpcode::G_CONSTANT: {
2412 bool IsZero =
false;
2413 if (
I.getOperand(1).isCImm())
2414 IsZero =
I.getOperand(1).getCImm()->isZero();
2415 else if (
I.getOperand(1).isImm())
2416 IsZero =
I.getOperand(1).getImm() == 0;
2421 Register DefReg =
I.getOperand(0).getReg();
2424 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2427 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2432 I.setDesc(
TII.get(TargetOpcode::COPY));
2436 case TargetOpcode::G_ADD: {
2445 Register AddDst =
I.getOperand(0).getReg();
2446 Register AddLHS =
I.getOperand(1).getReg();
2447 Register AddRHS =
I.getOperand(2).getReg();
2457 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2478 MachineInstr *
Cmp = MatchCmp(AddRHS);
2482 Cmp = MatchCmp(AddRHS);
2486 auto &PredOp =
Cmp->getOperand(1);
2488 emitIntegerCompare(
Cmp->getOperand(2),
2489 Cmp->getOperand(3), PredOp, MIB);
2493 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2494 I.eraseFromParent();
2497 case TargetOpcode::G_OR: {
2501 Register Dst =
I.getOperand(0).getReg();
2521 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2524 int64_t Immr =
Size - ShiftImm;
2525 int64_t Imms =
Size - ShiftImm - 1;
2526 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2527 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2528 I.eraseFromParent();
2531 case TargetOpcode::G_FENCE: {
2532 if (
I.getOperand(1).getImm() == 0)
2536 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2537 I.eraseFromParent();
2545bool AArch64InstructionSelector::select(MachineInstr &
I) {
2546 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2547 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2553 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2554 if (Subtarget->requiresStrictAlign()) {
2556 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2562 unsigned Opcode =
I.getOpcode();
2564 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2567 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2572 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2573 const Register DefReg =
I.getOperand(0).getReg();
2574 const LLT DefTy = MRI.
getType(DefReg);
2579 const TargetRegisterClass *DefRC =
2587 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2594 I.setDesc(
TII.get(TargetOpcode::PHI));
2602 if (
I.isDebugInstr())
2609 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2611 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2618 if (preISelLower(
I)) {
2619 Opcode =
I.getOpcode();
2630 if (selectImpl(
I, *CoverageInfo))
2634 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2637 case TargetOpcode::G_SBFX:
2638 case TargetOpcode::G_UBFX: {
2639 static const unsigned OpcTable[2][2] = {
2640 {AArch64::UBFMWri, AArch64::UBFMXri},
2641 {AArch64::SBFMWri, AArch64::SBFMXri}};
2642 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2644 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2647 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2650 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2651 auto LSB = Cst1->Value.getZExtValue();
2652 auto Width = Cst2->Value.getZExtValue();
2656 .
addImm(LSB + Width - 1);
2657 I.eraseFromParent();
2661 case TargetOpcode::G_BRCOND:
2662 return selectCompareBranch(
I, MF, MRI);
2664 case TargetOpcode::G_BRINDIRECT: {
2666 if (std::optional<uint16_t> BADisc =
2668 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2671 MI.addReg(AArch64::XZR);
2672 I.eraseFromParent();
2676 I.setDesc(
TII.get(AArch64::BR));
2681 case TargetOpcode::G_BRJT:
2682 return selectBrJT(
I, MRI);
2684 case AArch64::G_ADD_LOW: {
2689 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2690 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2691 I.setDesc(
TII.get(AArch64::ADDXri));
2697 "Expected small code model");
2699 auto Op2 =
I.getOperand(2);
2700 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2701 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2702 Op1.getTargetFlags())
2704 Op2.getTargetFlags());
2705 I.eraseFromParent();
2710 case TargetOpcode::G_FCONSTANT: {
2711 const Register DefReg =
I.getOperand(0).getReg();
2712 const LLT DefTy = MRI.
getType(DefReg);
2716 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2723 bool OptForSize = shouldOptForSize(&MF);
2727 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2734 auto *FPImm =
I.getOperand(1).getFPImm();
2737 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2740 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2741 I.eraseFromParent();
2746 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2749 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2750 MachineOperand &RegOp =
I.getOperand(0);
2756 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2760 MachineOperand &ImmOp =
I.getOperand(1);
2764 const unsigned MovOpc =
2765 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2766 I.setDesc(
TII.get(MovOpc));
2770 case TargetOpcode::G_EXTRACT: {
2771 Register DstReg =
I.getOperand(0).getReg();
2772 Register SrcReg =
I.getOperand(1).getReg();
2773 LLT SrcTy = MRI.
getType(SrcReg);
2774 LLT DstTy = MRI.
getType(DstReg);
2786 unsigned Offset =
I.getOperand(2).getImm();
2791 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2792 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2795 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2797 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2799 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2801 AArch64::GPR64RegClass, NewI->getOperand(0));
2802 I.eraseFromParent();
2808 unsigned LaneIdx =
Offset / 64;
2809 MachineInstr *Extract = emitExtractVectorElt(
2810 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2813 I.eraseFromParent();
2817 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2818 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2823 "unexpected G_EXTRACT types");
2830 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2831 .addReg(DstReg, {}, AArch64::sub_32);
2833 AArch64::GPR32RegClass, MRI);
2834 I.getOperand(0).setReg(DstReg);
2840 case TargetOpcode::G_INSERT: {
2841 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2842 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2849 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2850 unsigned LSB =
I.getOperand(3).getImm();
2852 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2853 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2857 "unexpected G_INSERT types");
2864 TII.get(AArch64::SUBREG_TO_REG))
2866 .
addUse(
I.getOperand(2).getReg())
2867 .
addImm(AArch64::sub_32);
2869 AArch64::GPR32RegClass, MRI);
2870 I.getOperand(2).setReg(SrcReg);
2875 case TargetOpcode::G_FRAME_INDEX: {
2882 I.setDesc(
TII.get(AArch64::ADDXri));
2892 case TargetOpcode::G_GLOBAL_VALUE: {
2893 const GlobalValue *GV =
nullptr;
2895 if (
I.getOperand(1).isSymbol()) {
2896 OpFlags =
I.getOperand(1).getTargetFlags();
2905 return selectTLSGlobalValue(
I, MRI);
2911 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2912 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2913 I.getOperand(1).setTargetFlags(OpFlags);
2914 I.addImplicitDefUseOperands(MF);
2918 materializeLargeCMVal(
I, GV, OpFlags);
2919 I.eraseFromParent();
2922 I.setDesc(
TII.get(AArch64::ADR));
2923 I.getOperand(1).setTargetFlags(OpFlags);
2925 I.setDesc(
TII.get(AArch64::MOVaddr));
2927 MachineInstrBuilder MIB(MF,
I);
2928 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2935 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2936 return selectPtrAuthGlobalValue(
I, MRI);
2938 case TargetOpcode::G_ZEXTLOAD:
2939 case TargetOpcode::G_LOAD:
2940 case TargetOpcode::G_STORE: {
2942 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2957 assert(MemSizeInBytes <= 8 &&
2958 "128-bit atomics should already be custom-legalized");
2961 static constexpr unsigned LDAPROpcodes[] = {
2962 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2963 static constexpr unsigned LDAROpcodes[] = {
2964 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2965 ArrayRef<unsigned> Opcodes =
2966 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2969 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2971 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2972 AArch64::STLRW, AArch64::STLRX};
2977 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2978 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2979 I.getOperand(0).setReg(NewVal);
2981 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2989 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2992 "Load/Store pointer operand isn't a GPR");
2994 "Load/Store pointer operand isn't a pointer");
2999 LLT ValTy = MRI.
getType(ValReg);
3006 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3012 .addReg(ValReg, {}, SubReg)
3019 if (RB.
getID() == AArch64::FPRRegBankID) {
3022 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3032 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3035 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3044 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3046 const unsigned NewOpc =
3048 if (NewOpc ==
I.getOpcode())
3052 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3055 I.setDesc(
TII.get(NewOpc));
3061 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3062 Register CurValReg =
I.getOperand(0).getReg();
3063 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3064 NewInst.cloneMemRefs(
I);
3065 for (
auto &Fn : *AddrModeFns)
3067 I.eraseFromParent();
3071 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3076 if (Opcode == TargetOpcode::G_STORE) {
3078 LoadStore->getOperand(0).getReg(), MRI);
3079 if (CVal && CVal->Value == 0) {
3081 case AArch64::STRWui:
3082 case AArch64::STRHHui:
3083 case AArch64::STRBBui:
3084 LoadStore->getOperand(0).setReg(AArch64::WZR);
3086 case AArch64::STRXui:
3087 LoadStore->getOperand(0).setReg(AArch64::XZR);
3093 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3094 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3106 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3108 .
addImm(AArch64::sub_32);
3117 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3118 case TargetOpcode::G_INDEXED_SEXTLOAD:
3119 return selectIndexedExtLoad(
I, MRI);
3120 case TargetOpcode::G_INDEXED_LOAD:
3121 return selectIndexedLoad(
I, MRI);
3122 case TargetOpcode::G_INDEXED_STORE:
3125 case TargetOpcode::G_LSHR:
3126 case TargetOpcode::G_ASHR:
3128 return selectVectorAshrLshr(
I, MRI);
3130 case TargetOpcode::G_SHL:
3131 if (Opcode == TargetOpcode::G_SHL &&
3133 return selectVectorSHL(
I, MRI);
3140 Register SrcReg =
I.getOperand(1).getReg();
3141 Register ShiftReg =
I.getOperand(2).getReg();
3142 const LLT ShiftTy = MRI.
getType(ShiftReg);
3143 const LLT SrcTy = MRI.
getType(SrcReg);
3148 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3149 .addReg(ShiftReg, {}, AArch64::sub_32);
3151 I.getOperand(2).setReg(Trunc.getReg(0));
3155 case TargetOpcode::G_OR: {
3162 const Register DefReg =
I.getOperand(0).getReg();
3166 if (NewOpc ==
I.getOpcode())
3169 I.setDesc(
TII.get(NewOpc));
3178 case TargetOpcode::G_PTR_ADD: {
3179 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3180 I.eraseFromParent();
3184 case TargetOpcode::G_SADDE:
3185 case TargetOpcode::G_UADDE:
3186 case TargetOpcode::G_SSUBE:
3187 case TargetOpcode::G_USUBE:
3188 case TargetOpcode::G_SADDO:
3189 case TargetOpcode::G_UADDO:
3190 case TargetOpcode::G_SSUBO:
3191 case TargetOpcode::G_USUBO:
3192 return selectOverflowOp(
I, MRI);
3194 case TargetOpcode::G_PTRMASK: {
3195 Register MaskReg =
I.getOperand(2).getReg();
3201 uint64_t
Mask = *MaskVal;
3202 I.setDesc(
TII.get(AArch64::ANDXri));
3203 I.getOperand(2).ChangeToImmediate(
3209 case TargetOpcode::G_PTRTOINT:
3210 case TargetOpcode::G_TRUNC: {
3211 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3212 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3214 const Register DstReg =
I.getOperand(0).getReg();
3215 const Register SrcReg =
I.getOperand(1).getReg();
3217 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3218 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3222 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3226 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3227 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3231 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3237 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3241 if (DstRC == SrcRC) {
3243 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3247 }
else if (DstRC == &AArch64::GPR32RegClass &&
3248 SrcRC == &AArch64::GPR64RegClass) {
3249 I.getOperand(1).setSubReg(AArch64::sub_32);
3252 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3256 I.setDesc(
TII.get(TargetOpcode::COPY));
3258 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3261 I.setDesc(
TII.get(AArch64::XTNv4i16));
3267 MachineInstr *Extract = emitExtractVectorElt(
3271 I.eraseFromParent();
3276 if (Opcode == TargetOpcode::G_PTRTOINT) {
3277 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3278 I.setDesc(
TII.get(TargetOpcode::COPY));
3286 case TargetOpcode::G_ANYEXT: {
3287 if (selectUSMovFromExtend(
I, MRI))
3290 const Register DstReg =
I.getOperand(0).getReg();
3291 const Register SrcReg =
I.getOperand(1).getReg();
3293 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3294 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3296 <<
", expected: GPR\n");
3300 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3301 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3303 <<
", expected: GPR\n");
3310 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3314 if (DstSize != 64 && DstSize > 32) {
3316 <<
", expected: 32 or 64\n");
3326 .
addImm(AArch64::sub_32);
3327 I.getOperand(1).setReg(ExtSrc);
3332 case TargetOpcode::G_ZEXT:
3333 case TargetOpcode::G_SEXT_INREG:
3334 case TargetOpcode::G_SEXT: {
3335 if (selectUSMovFromExtend(
I, MRI))
3338 unsigned Opcode =
I.getOpcode();
3339 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3340 const Register DefReg =
I.getOperand(0).getReg();
3341 Register SrcReg =
I.getOperand(1).getReg();
3342 const LLT DstTy = MRI.
getType(DefReg);
3343 const LLT SrcTy = MRI.
getType(SrcReg);
3349 if (Opcode == TargetOpcode::G_SEXT_INREG)
3350 SrcSize =
I.getOperand(2).getImm();
3356 AArch64::GPRRegBankID &&
3357 "Unexpected ext regbank");
3368 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3371 if (LoadMI && IsGPR) {
3372 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3373 unsigned BytesLoaded = MemOp->getSize().getValue();
3380 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3383 const Register ZReg = AArch64::WZR;
3384 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3387 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3388 .addUse(SubregToRegSrc)
3389 .
addImm(AArch64::sub_32);
3393 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3403 I.eraseFromParent();
3408 if (DstSize == 64) {
3409 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3417 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3418 {&AArch64::GPR64RegClass}, {})
3424 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3428 }
else if (DstSize <= 32) {
3429 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3438 I.eraseFromParent();
3442 case TargetOpcode::G_FREEZE:
3445 case TargetOpcode::G_INTTOPTR:
3450 case TargetOpcode::G_BITCAST:
3458 case TargetOpcode::G_SELECT: {
3460 const Register CondReg = Sel.getCondReg();
3462 const Register FReg = Sel.getFalseReg();
3464 if (tryOptSelect(Sel))
3470 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3475 Sel.eraseFromParent();
3478 case TargetOpcode::G_ICMP: {
3488 auto &PredOp =
I.getOperand(1);
3489 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3493 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3494 AArch64::WZR, InvCC, MIB);
3495 I.eraseFromParent();
3499 case TargetOpcode::G_FCMP: {
3502 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3504 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3506 I.eraseFromParent();
3509 case TargetOpcode::G_VASTART:
3511 : selectVaStartAAPCS(
I, MF, MRI);
3512 case TargetOpcode::G_INTRINSIC:
3513 return selectIntrinsic(
I, MRI);
3514 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3515 return selectIntrinsicWithSideEffects(
I, MRI);
3516 case TargetOpcode::G_IMPLICIT_DEF: {
3517 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3518 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3519 const Register DstReg =
I.getOperand(0).getReg();
3520 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3521 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3525 case TargetOpcode::G_BLOCK_ADDR: {
3526 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3527 if (std::optional<uint16_t> BADisc =
3529 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3530 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3539 AArch64::GPR64RegClass, MRI);
3540 I.eraseFromParent();
3544 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3545 I.eraseFromParent();
3548 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3549 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3550 I.getOperand(0).getReg())
3554 I.getOperand(1).getBlockAddress(), 0,
3556 I.eraseFromParent();
3561 case AArch64::G_DUP: {
3568 AArch64::GPRRegBankID)
3570 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3572 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3574 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3576 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3578 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3584 case TargetOpcode::G_BUILD_VECTOR:
3585 return selectBuildVector(
I, MRI);
3586 case TargetOpcode::G_MERGE_VALUES:
3588 case TargetOpcode::G_UNMERGE_VALUES:
3590 case TargetOpcode::G_SHUFFLE_VECTOR:
3591 return selectShuffleVector(
I, MRI);
3592 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3593 return selectExtractElt(
I, MRI);
3594 case TargetOpcode::G_CONCAT_VECTORS:
3595 return selectConcatVectors(
I, MRI);
3596 case TargetOpcode::G_JUMP_TABLE:
3597 return selectJumpTable(
I, MRI);
3598 case TargetOpcode::G_MEMCPY:
3599 case TargetOpcode::G_MEMCPY_INLINE:
3600 case TargetOpcode::G_MEMMOVE:
3601 case TargetOpcode::G_MEMSET:
3602 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3603 return selectMOPS(
I, MRI);
3609bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3610 MachineIRBuilderState OldMIBState = MIB.
getState();
3616bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3617 MachineRegisterInfo &MRI) {
3620 case TargetOpcode::G_MEMCPY:
3621 case TargetOpcode::G_MEMCPY_INLINE:
3622 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3624 case TargetOpcode::G_MEMMOVE:
3625 Mopcode = AArch64::MOPSMemoryMovePseudo;
3627 case TargetOpcode::G_MEMSET:
3629 Mopcode = AArch64::MOPSMemorySetPseudo;
3642 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3643 const auto &SrcValRegClass =
3644 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3662 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3663 {DstPtrCopy, SizeCopy, SrcValCopy});
3666 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3667 {DstPtrCopy, SrcValCopy, SizeCopy});
3674bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3675 MachineRegisterInfo &MRI) {
3676 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3677 Register JTAddr =
I.getOperand(0).getReg();
3678 unsigned JTI =
I.getOperand(1).getIndex();
3681 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3693 "jump table hardening only supported on MachO/ELF");
3701 I.eraseFromParent();
3708 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3709 {TargetReg, ScratchReg}, {JTAddr,
Index})
3710 .addJumpTableIndex(JTI);
3712 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3713 {
static_cast<int64_t
>(JTI)});
3715 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3716 I.eraseFromParent();
3721bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3722 MachineRegisterInfo &MRI) {
3723 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3724 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3726 Register DstReg =
I.getOperand(0).getReg();
3727 unsigned JTI =
I.getOperand(1).getIndex();
3730 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3733 I.eraseFromParent();
3738bool AArch64InstructionSelector::selectTLSGlobalValue(
3739 MachineInstr &
I, MachineRegisterInfo &MRI) {
3742 MachineFunction &MF = *
I.getParent()->getParent();
3745 const auto &GlobalOp =
I.getOperand(1);
3746 assert(GlobalOp.getOffset() == 0 &&
3747 "Shouldn't have an offset on TLS globals!");
3748 const GlobalValue &GV = *GlobalOp.getGlobal();
3751 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3754 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3755 {LoadGOT.getReg(0)})
3766 assert(Opcode == AArch64::BLR);
3767 Opcode = AArch64::BLRAAZ;
3771 .addUse(AArch64::X0, RegState::Implicit)
3772 .
addDef(AArch64::X0, RegState::Implicit)
3778 I.eraseFromParent();
3782MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3783 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3784 MachineIRBuilder &MIRBuilder)
const {
3785 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3787 auto BuildFn = [&](
unsigned SubregIndex) {
3791 .addImm(SubregIndex);
3799 return BuildFn(AArch64::bsub);
3801 return BuildFn(AArch64::hsub);
3803 return BuildFn(AArch64::ssub);
3805 return BuildFn(AArch64::dsub);
3812AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3813 MachineIRBuilder &MIB,
3814 MachineRegisterInfo &MRI)
const {
3815 LLT DstTy = MRI.
getType(DstReg);
3816 const TargetRegisterClass *RC =
3817 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3818 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3822 unsigned SubReg = 0;
3825 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3831 .addReg(SrcReg, {}, SubReg);
3836bool AArch64InstructionSelector::selectMergeValues(
3837 MachineInstr &
I, MachineRegisterInfo &MRI) {
3838 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3839 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3840 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3842 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3844 if (
I.getNumOperands() != 3)
3851 Register DstReg =
I.getOperand(0).getReg();
3852 Register Src1Reg =
I.getOperand(1).getReg();
3853 Register Src2Reg =
I.getOperand(2).getReg();
3854 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3855 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3859 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3860 Src2Reg, 1, RB, MIB);
3865 I.eraseFromParent();
3869 if (RB.
getID() != AArch64::GPRRegBankID)
3875 auto *DstRC = &AArch64::GPR64RegClass;
3877 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3878 TII.get(TargetOpcode::SUBREG_TO_REG))
3880 .
addUse(
I.getOperand(1).getReg())
3881 .
addImm(AArch64::sub_32);
3884 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3885 TII.get(TargetOpcode::SUBREG_TO_REG))
3887 .
addUse(
I.getOperand(2).getReg())
3888 .
addImm(AArch64::sub_32);
3890 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3891 .
addDef(
I.getOperand(0).getReg())
3899 I.eraseFromParent();
3904 const unsigned EltSize) {
3909 CopyOpc = AArch64::DUPi8;
3910 ExtractSubReg = AArch64::bsub;
3913 CopyOpc = AArch64::DUPi16;
3914 ExtractSubReg = AArch64::hsub;
3917 CopyOpc = AArch64::DUPi32;
3918 ExtractSubReg = AArch64::ssub;
3921 CopyOpc = AArch64::DUPi64;
3922 ExtractSubReg = AArch64::dsub;
3926 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3932MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3933 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3934 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3935 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3936 unsigned CopyOpc = 0;
3937 unsigned ExtractSubReg = 0;
3940 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3944 const TargetRegisterClass *DstRC =
3945 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3947 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3951 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3952 const LLT &VecTy = MRI.
getType(VecReg);
3953 const TargetRegisterClass *VecRC =
3954 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3956 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3966 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3967 .addReg(VecReg, {}, ExtractSubReg);
3976 MachineInstr *ScalarToVector = emitScalarToVector(
3977 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3978 if (!ScalarToVector)
3983 MachineInstr *LaneCopyMI =
3984 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3992bool AArch64InstructionSelector::selectExtractElt(
3993 MachineInstr &
I, MachineRegisterInfo &MRI) {
3994 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3995 "unexpected opcode!");
3996 Register DstReg =
I.getOperand(0).getReg();
3997 const LLT NarrowTy = MRI.
getType(DstReg);
3998 const Register SrcReg =
I.getOperand(1).getReg();
3999 const LLT WideTy = MRI.
getType(SrcReg);
4002 "source register size too small!");
4003 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4006 MachineOperand &LaneIdxOp =
I.getOperand(2);
4007 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4018 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4021 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4022 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4027 I.eraseFromParent();
4031bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4032 MachineInstr &
I, MachineRegisterInfo &MRI) {
4033 unsigned NumElts =
I.getNumOperands() - 1;
4034 Register SrcReg =
I.getOperand(NumElts).getReg();
4035 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4036 const LLT SrcTy = MRI.
getType(SrcReg);
4038 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4040 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4046 const RegisterBank &DstRB =
4050 MachineInstr *Extract =
4051 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4055 I.eraseFromParent();
4059bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4060 MachineRegisterInfo &MRI) {
4061 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4062 "unexpected opcode");
4066 AArch64::FPRRegBankID ||
4068 AArch64::FPRRegBankID) {
4069 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4070 "currently unsupported.\n");
4076 unsigned NumElts =
I.getNumOperands() - 1;
4077 Register SrcReg =
I.getOperand(NumElts).getReg();
4078 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4079 const LLT WideTy = MRI.
getType(SrcReg);
4082 "source register size too small!");
4085 return selectSplitVectorUnmerge(
I, MRI);
4089 unsigned CopyOpc = 0;
4090 unsigned ExtractSubReg = 0;
4101 unsigned NumInsertRegs = NumElts - 1;
4114 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4116 unsigned SubReg = 0;
4119 assert(Found &&
"expected to find last operand's subeg idx");
4120 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4122 MachineInstr &ImpDefMI =
4123 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4128 MachineInstr &InsMI =
4130 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4147 Register CopyTo =
I.getOperand(0).getReg();
4148 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4149 .addReg(InsertRegs[0], {}, ExtractSubReg);
4153 unsigned LaneIdx = 1;
4154 for (
Register InsReg : InsertRegs) {
4155 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4156 MachineInstr &CopyInst =
4167 const TargetRegisterClass *RC =
4175 I.eraseFromParent();
4179bool AArch64InstructionSelector::selectConcatVectors(
4180 MachineInstr &
I, MachineRegisterInfo &MRI) {
4181 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4182 "Unexpected opcode");
4183 Register Dst =
I.getOperand(0).getReg();
4184 Register Op1 =
I.getOperand(1).getReg();
4185 Register Op2 =
I.getOperand(2).getReg();
4186 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4189 I.eraseFromParent();
4194AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4195 MachineFunction &MF)
const {
4203MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4204 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4205 const TargetRegisterClass *RC;
4211 RC = &AArch64::FPR128RegClass;
4212 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4215 RC = &AArch64::FPR64RegClass;
4216 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4219 RC = &AArch64::FPR32RegClass;
4220 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4223 RC = &AArch64::FPR16RegClass;
4224 Opc = AArch64::LDRHui;
4227 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4232 MachineInstr *LoadMI =
nullptr;
4233 auto &MF = MIRBuilder.
getMF();
4234 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4235 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4237 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4240 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4244 .addConstantPoolIndex(
4260static std::pair<unsigned, unsigned>
4262 unsigned Opc, SubregIdx;
4263 if (RB.
getID() == AArch64::GPRRegBankID) {
4265 Opc = AArch64::INSvi8gpr;
4266 SubregIdx = AArch64::bsub;
4267 }
else if (EltSize == 16) {
4268 Opc = AArch64::INSvi16gpr;
4269 SubregIdx = AArch64::ssub;
4270 }
else if (EltSize == 32) {
4271 Opc = AArch64::INSvi32gpr;
4272 SubregIdx = AArch64::ssub;
4273 }
else if (EltSize == 64) {
4274 Opc = AArch64::INSvi64gpr;
4275 SubregIdx = AArch64::dsub;
4281 Opc = AArch64::INSvi8lane;
4282 SubregIdx = AArch64::bsub;
4283 }
else if (EltSize == 16) {
4284 Opc = AArch64::INSvi16lane;
4285 SubregIdx = AArch64::hsub;
4286 }
else if (EltSize == 32) {
4287 Opc = AArch64::INSvi32lane;
4288 SubregIdx = AArch64::ssub;
4289 }
else if (EltSize == 64) {
4290 Opc = AArch64::INSvi64lane;
4291 SubregIdx = AArch64::dsub;
4296 return std::make_pair(
Opc, SubregIdx);
4299MachineInstr *AArch64InstructionSelector::emitInstr(
4300 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4301 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4302 const ComplexRendererFns &RenderFns)
const {
4303 assert(Opcode &&
"Expected an opcode?");
4305 "Function should only be used to produce selected instructions!");
4306 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4308 for (
auto &Fn : *RenderFns)
4314MachineInstr *AArch64InstructionSelector::emitAddSub(
4315 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4317 MachineIRBuilder &MIRBuilder)
const {
4319 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4323 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4324 bool Is32Bit =
Size == 32;
4327 if (
auto Fns = selectArithImmed(
RHS))
4328 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4332 if (
auto Fns = selectNegArithImmed(
RHS))
4333 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4337 if (
auto Fns = selectArithExtendedRegister(
RHS))
4338 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4342 if (
auto Fns = selectShiftedRegister(
RHS))
4343 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4345 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4350AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4351 MachineOperand &
RHS,
4352 MachineIRBuilder &MIRBuilder)
const {
4353 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4354 {{AArch64::ADDXri, AArch64::ADDWri},
4355 {AArch64::ADDXrs, AArch64::ADDWrs},
4356 {AArch64::ADDXrr, AArch64::ADDWrr},
4357 {AArch64::SUBXri, AArch64::SUBWri},
4358 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4359 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4363AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4364 MachineOperand &
RHS,
4365 MachineIRBuilder &MIRBuilder)
const {
4366 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4367 {{AArch64::ADDSXri, AArch64::ADDSWri},
4368 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4369 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4370 {AArch64::SUBSXri, AArch64::SUBSWri},
4371 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4372 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4376AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4377 MachineOperand &
RHS,
4378 MachineIRBuilder &MIRBuilder)
const {
4379 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4380 {{AArch64::SUBSXri, AArch64::SUBSWri},
4381 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4382 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4383 {AArch64::ADDSXri, AArch64::ADDSWri},
4384 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4385 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4389AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4390 MachineOperand &
RHS,
4391 MachineIRBuilder &MIRBuilder)
const {
4392 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4393 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4395 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4396 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4400AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4401 MachineOperand &
RHS,
4402 MachineIRBuilder &MIRBuilder)
const {
4403 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4404 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4406 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4407 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4411AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4412 MachineIRBuilder &MIRBuilder)
const {
4415 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4420AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4421 MachineIRBuilder &MIRBuilder)
const {
4424 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4429AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4430 MachineIRBuilder &MIRBuilder)
const {
4431 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4435 bool Is32Bit = (
RegSize == 32);
4436 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4437 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4438 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4442 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4445 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4452 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4453 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4454 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4457MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4458 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4459 MachineIRBuilder &MIRBuilder)
const {
4460 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4467 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4469 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4471 return emitCMP(
LHS,
RHS, MIRBuilder);
4474MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4476 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4480 "Expected a 32-bit scalar register?");
4482 const Register ZReg = AArch64::WZR;
4487 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4489 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4493 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4494 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4495 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4500MachineInstr *AArch64InstructionSelector::emitFPCompare(
4502 std::optional<CmpInst::Predicate> Pred)
const {
4503 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4508 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4519 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4523 ShouldUseImm =
true;
4527 unsigned CmpOpcTbl[2][3] = {
4528 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4529 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4531 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4543MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4545 MachineIRBuilder &MIRBuilder)
const {
4552 const LLT Op1Ty = MRI.
getType(Op1);
4553 const LLT Op2Ty = MRI.
getType(Op2);
4555 if (Op1Ty != Op2Ty) {
4556 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4559 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4562 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4573 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4574 const TargetRegisterClass *DstRC =
4577 MachineInstr *WidenedOp1 =
4578 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4579 MachineInstr *WidenedOp2 =
4580 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4581 if (!WidenedOp1 || !WidenedOp2) {
4582 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4587 unsigned InsertOpc, InsSubRegIdx;
4588 std::tie(InsertOpc, InsSubRegIdx) =
4606 MachineIRBuilder &MIRBuilder)
const {
4607 auto &MRI = *MIRBuilder.
getMRI();
4613 Size =
TRI.getRegSizeInBits(*RC);
4617 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4618 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4619 unsigned Opc = OpcTable[
Size == 64];
4620 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4625MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4627 MachineRegisterInfo *MRI = MIB.
getMRI();
4628 unsigned Opcode =
I.getOpcode();
4632 bool NeedsNegatedCarry =
4633 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4642 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4643 if (SrcMI ==
I.getPrevNode()) {
4645 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4646 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4647 CarrySrcMI->isUnsigned() &&
4648 CarrySrcMI->getCarryOutReg() == CarryReg &&
4649 selectAndRestoreState(*SrcMI))
4656 if (NeedsNegatedCarry) {
4659 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4663 auto Fns = select12BitValueWithLeftShift(1);
4664 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4667bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4668 MachineRegisterInfo &MRI) {
4673 emitCarryIn(
I, CarryInMI->getCarryInReg());
4677 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4678 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4680 Register CarryOutReg = CarryMI.getCarryOutReg();
4689 emitCSINC(CarryOutReg, ZReg, ZReg,
4690 getInvertedCondCode(OpAndCC.second), MIB);
4693 I.eraseFromParent();
4697std::pair<MachineInstr *, AArch64CC::CondCode>
4698AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4699 MachineOperand &
LHS,
4700 MachineOperand &
RHS,
4701 MachineIRBuilder &MIRBuilder)
const {
4705 case TargetOpcode::G_SADDO:
4707 case TargetOpcode::G_UADDO:
4709 case TargetOpcode::G_SSUBO:
4711 case TargetOpcode::G_USUBO:
4713 case TargetOpcode::G_SADDE:
4715 case TargetOpcode::G_UADDE:
4717 case TargetOpcode::G_SSUBE:
4719 case TargetOpcode::G_USUBE:
4740 unsigned Depth = 0) {
4747 MustBeFirst =
false;
4753 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4754 bool IsOR = Opcode == TargetOpcode::G_OR;
4766 if (MustBeFirstL && MustBeFirstR)
4772 if (!CanNegateL && !CanNegateR)
4776 CanNegate = WillNegate && CanNegateL && CanNegateR;
4779 MustBeFirst = !CanNegate;
4781 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4784 MustBeFirst = MustBeFirstL || MustBeFirstR;
4791MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4794 MachineIRBuilder &MIB)
const {
4795 auto &MRI = *MIB.
getMRI();
4798 std::optional<ValueAndVReg>
C;
4802 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4803 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4804 else if (
C->Value.ule(31))
4805 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4807 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4813 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4814 CCmpOpc = AArch64::FCCMPHrr;
4817 CCmpOpc = AArch64::FCCMPSrr;
4820 CCmpOpc = AArch64::FCCMPDrr;
4830 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4831 CCmp.
addImm(
C->Value.getZExtValue());
4832 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4833 CCmp.
addImm(
C->Value.abs().getZExtValue());
4841MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4845 auto &MRI = *MIB.
getMRI();
4863 MachineInstr *ExtraCmp;
4865 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4877 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4878 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4879 Cmp->getOperand(3).getReg(), MIB);
4886 bool IsOR = Opcode == TargetOpcode::G_OR;
4892 assert(ValidL &&
"Valid conjunction/disjunction tree");
4899 assert(ValidR &&
"Valid conjunction/disjunction tree");
4904 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4913 bool NegateAfterAll;
4914 if (Opcode == TargetOpcode::G_OR) {
4917 assert(CanNegateR &&
"at least one side must be negatable");
4918 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4922 NegateAfterR =
true;
4925 NegateR = CanNegateR;
4926 NegateAfterR = !CanNegateR;
4929 NegateAfterAll = !Negate;
4931 assert(Opcode == TargetOpcode::G_AND &&
4932 "Valid conjunction/disjunction tree");
4933 assert(!Negate &&
"Valid conjunction/disjunction tree");
4937 NegateAfterR =
false;
4938 NegateAfterAll =
false;
4943 MachineInstr *CmpR =
4954MachineInstr *AArch64InstructionSelector::emitConjunction(
4956 bool DummyCanNegate;
4957 bool DummyMustBeFirst;
4964bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4965 MachineInstr &CondMI) {
4976bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4977 MachineRegisterInfo &MRI = *MIB.
getMRI();
4996 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5005 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5011 unsigned CondOpc = CondDef->
getOpcode();
5012 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5013 if (tryOptSelectConjunction(
I, *CondDef))
5019 if (CondOpc == TargetOpcode::G_ICMP) {
5048 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5049 I.getOperand(3).getReg(), CondCode, MIB);
5050 I.eraseFromParent();
5054MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5055 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5056 MachineIRBuilder &MIRBuilder)
const {
5058 "Unexpected MachineOperand");
5059 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5082 if (
isCMN(RHSDef,
P, MRI))
5097 if (
isCMN(LHSDef,
P, MRI)) {
5114 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5117 if (!ValAndVReg || ValAndVReg->Value != 0)
5127bool AArch64InstructionSelector::selectShuffleVector(
5128 MachineInstr &
I, MachineRegisterInfo &MRI) {
5129 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5130 Register Src1Reg =
I.getOperand(1).getReg();
5131 Register Src2Reg =
I.getOperand(2).getReg();
5132 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5141 for (
int Val : Mask) {
5144 Val = Val < 0 ? 0 : Val;
5145 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5163 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5170 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5174 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5179 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5180 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5182 I.eraseFromParent();
5190 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5193 I.eraseFromParent();
5197MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5199 unsigned LaneIdx,
const RegisterBank &RB,
5200 MachineIRBuilder &MIRBuilder)
const {
5201 MachineInstr *InsElt =
nullptr;
5202 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5203 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5212 if (RB.
getID() == AArch64::FPRRegBankID) {
5213 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5216 .
addUse(InsSub->getOperand(0).getReg())
5228bool AArch64InstructionSelector::selectUSMovFromExtend(
5229 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5230 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5231 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5232 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5234 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5235 const Register DefReg =
MI.getOperand(0).getReg();
5236 const LLT DstTy = MRI.
getType(DefReg);
5239 if (DstSize != 32 && DstSize != 64)
5242 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5243 MI.getOperand(1).getReg(), MRI);
5249 const LLT VecTy = MRI.
getType(Src0);
5254 const MachineInstr *ScalarToVector = emitScalarToVector(
5255 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5256 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5262 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5264 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5266 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5268 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5270 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5278 MachineInstr *ExtI =
nullptr;
5279 if (DstSize == 64 && !IsSigned) {
5281 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5282 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5284 .
addImm(AArch64::sub_32);
5287 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5290 MI.eraseFromParent();
5294MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5295 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5297 if (DstSize == 128) {
5298 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5300 Op = AArch64::MOVIv16b_ns;
5302 Op = AArch64::MOVIv8b_ns;
5305 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5309 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5316MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5317 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5321 if (DstSize == 128) {
5322 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5324 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5326 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5329 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5346MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5347 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5351 if (DstSize == 128) {
5352 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5354 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5356 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5359 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5382MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5383 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5386 if (DstSize == 128) {
5387 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5389 Op = AArch64::MOVIv2d_ns;
5391 Op = AArch64::MOVID;
5394 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5397 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5404MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5405 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5409 if (DstSize == 128) {
5410 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5412 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5414 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5417 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5434MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5435 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5438 bool IsWide =
false;
5439 if (DstSize == 128) {
5440 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5442 Op = AArch64::FMOVv4f32_ns;
5445 Op = AArch64::FMOVv2f32_ns;
5448 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5454 Op = AArch64::FMOVv2f64_ns;
5458 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5463bool AArch64InstructionSelector::selectIndexedExtLoad(
5464 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5467 Register WriteBack = ExtLd.getWritebackReg();
5472 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5473 bool IsPre = ExtLd.isPre();
5475 unsigned InsertIntoSubReg = 0;
5481 if ((IsSExt && IsFPR) || Ty.
isVector())
5489 if (MemSizeBits == 8) {
5492 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5494 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5495 NewLdDstTy = IsDst64 ? s64 : s32;
5497 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5498 InsertIntoSubReg = AArch64::bsub;
5501 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5502 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5505 }
else if (MemSizeBits == 16) {
5508 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5510 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5511 NewLdDstTy = IsDst64 ? s64 : s32;
5513 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5514 InsertIntoSubReg = AArch64::hsub;
5517 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5518 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5521 }
else if (MemSizeBits == 32) {
5523 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5526 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5527 InsertIntoSubReg = AArch64::ssub;
5530 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5531 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5543 .addImm(Cst->getSExtValue());
5548 if (InsertIntoSubReg) {
5550 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5551 .addUse(LdMI.getReg(1))
5552 .
addImm(InsertIntoSubReg);
5555 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5562 MI.eraseFromParent();
5567bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5568 MachineRegisterInfo &MRI) {
5571 Register WriteBack = Ld.getWritebackReg();
5575 "Unexpected type for indexed load");
5576 unsigned MemSize = Ld.getMMO().getMemoryType().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,
5590 ? FPROpcodes[
Log2_32(MemSize)]
5591 : GPROpcodes[
Log2_32(MemSize)];
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};
5601 ? FPROpcodes[
Log2_32(MemSize)]
5602 : GPROpcodes[
Log2_32(MemSize)];
5612 MI.eraseFromParent();
5616bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5617 MachineRegisterInfo &MRI) {
5623 "Unexpected type for indexed store");
5625 LocationSize MemSize =
I.getMMO().getSize();
5626 unsigned MemSizeInBytes = MemSize.
getValue();
5628 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5629 "Unexpected indexed store size");
5630 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5634 static constexpr unsigned GPROpcodes[] = {
5635 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5637 static constexpr unsigned FPROpcodes[] = {
5638 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5642 Opc = FPROpcodes[MemSizeLog2];
5644 Opc = GPROpcodes[MemSizeLog2];
5646 static constexpr unsigned GPROpcodes[] = {
5647 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5649 static constexpr unsigned FPROpcodes[] = {
5650 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5651 AArch64::STRDpost, AArch64::STRQpost};
5654 Opc = FPROpcodes[MemSizeLog2];
5656 Opc = GPROpcodes[MemSizeLog2];
5664 Str.cloneMemRefs(
I);
5666 I.eraseFromParent();
5671AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5672 MachineIRBuilder &MIRBuilder,
5673 MachineRegisterInfo &MRI) {
5676 assert((DstSize == 64 || DstSize == 128) &&
5677 "Unexpected vector constant size");
5680 if (DstSize == 128) {
5682 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5687 if (DstSize == 64) {
5690 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5693 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5700 APInt SplatValueAsInt =
5703 : SplatValue->getUniqueInteger();
5706 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5707 MachineInstr *NewOp;
5731 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5735 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5736 unsigned NegOpc) -> MachineInstr * {
5739 APInt NegBits(DstSize, 0);
5740 unsigned NumElts = DstSize / NumBits;
5741 for (
unsigned i = 0; i < NumElts; i++)
5742 NegBits |= Neg << (NumBits * i);
5743 NegBits = DefBits ^ NegBits;
5747 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5749 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5751 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5756 if ((R = TryWithFNeg(DefBits, 32,
5757 DstSize == 64 ? AArch64::FNEGv2f32
5758 : AArch64::FNEGv4f32)) ||
5759 (R = TryWithFNeg(DefBits, 64,
5760 DstSize == 64 ? AArch64::FNEGDr
5761 : AArch64::FNEGv2f64)) ||
5762 (STI.hasFullFP16() &&
5763 (R = TryWithFNeg(DefBits, 16,
5764 DstSize == 64 ? AArch64::FNEGv4f16
5765 : AArch64::FNEGv8f16))))
5771 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5775 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5777 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5781bool AArch64InstructionSelector::tryOptConstantBuildVec(
5782 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5783 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5785 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5791 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5792 Register OpReg =
I.getOperand(Idx).getReg();
5801 std::move(AnyConst->Value)));
5814 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5816 I.eraseFromParent();
5820bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5821 MachineInstr &
I, MachineRegisterInfo &MRI) {
5826 Register Dst =
I.getOperand(0).getReg();
5827 Register EltReg =
I.getOperand(1).getReg();
5828 LLT EltTy = MRI.
getType(EltReg);
5831 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5836 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5840 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5843 const TargetRegisterClass *DstRC =
5844 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5849 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5852 I.eraseFromParent();
5857bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5858 MachineRegisterInfo &MRI) {
5859 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5862 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5863 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5866 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5868 if (tryOptBuildVecToSubregToReg(
I, MRI))
5871 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5873 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5875 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5876 MachineInstr *ScalarToVec =
5878 I.getOperand(1).getReg(), MIB);
5887 MachineInstr *PrevMI = ScalarToVec;
5888 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5891 Register OpReg =
I.getOperand(i).getReg();
5894 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5901 if (DstSize < 128) {
5903 const TargetRegisterClass *RC =
5904 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5907 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5912 unsigned SubReg = 0;
5915 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5916 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5922 Register DstReg =
I.getOperand(0).getReg();
5924 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5925 MachineOperand &RegOp =
I.getOperand(1);
5945 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5946 const TargetRegisterClass *RC =
5947 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5956bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5959 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5961 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5962 auto &MRI = *MIB.
getMRI();
5963 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5966 "Destination must be 64 bits or 128 bits?");
5967 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5968 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5971 Load.cloneMemRefs(
I);
5973 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5974 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5975 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5976 .addReg(SelectedLoadDst, {}, SubReg + Idx);
5985bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5986 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5987 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5989 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5990 auto &MRI = *MIB.
getMRI();
5991 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5994 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5996 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5997 [](
auto MO) { return MO.getReg(); });
6001 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6016 .
addImm(LaneNo->getZExtValue())
6018 Load.cloneMemRefs(
I);
6020 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6021 unsigned SubReg = AArch64::qsub0;
6022 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6023 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6024 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6025 : DstOp(
I.getOperand(Idx).
getReg())},
6027 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6032 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6038void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6041 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6042 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6043 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6046 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6047 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6056bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6057 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6058 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6059 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6063 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6064 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6068 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6078 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6081 .
addImm(LaneNo->getZExtValue())
6088bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6089 MachineInstr &
I, MachineRegisterInfo &MRI) {
6102 case Intrinsic::aarch64_ldxp:
6103 case Intrinsic::aarch64_ldaxp: {
6105 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6106 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6112 case Intrinsic::aarch64_neon_ld1x2: {
6113 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6116 Opc = AArch64::LD1Twov8b;
6118 Opc = AArch64::LD1Twov16b;
6120 Opc = AArch64::LD1Twov4h;
6122 Opc = AArch64::LD1Twov8h;
6124 Opc = AArch64::LD1Twov2s;
6126 Opc = AArch64::LD1Twov4s;
6128 Opc = AArch64::LD1Twov2d;
6129 else if (Ty ==
S64 || Ty == P0)
6130 Opc = AArch64::LD1Twov1d;
6133 selectVectorLoadIntrinsic(
Opc, 2,
I);
6136 case Intrinsic::aarch64_neon_ld1x3: {
6137 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6140 Opc = AArch64::LD1Threev8b;
6142 Opc = AArch64::LD1Threev16b;
6144 Opc = AArch64::LD1Threev4h;
6146 Opc = AArch64::LD1Threev8h;
6148 Opc = AArch64::LD1Threev2s;
6150 Opc = AArch64::LD1Threev4s;
6152 Opc = AArch64::LD1Threev2d;
6153 else if (Ty ==
S64 || Ty == P0)
6154 Opc = AArch64::LD1Threev1d;
6157 selectVectorLoadIntrinsic(
Opc, 3,
I);
6160 case Intrinsic::aarch64_neon_ld1x4: {
6161 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6164 Opc = AArch64::LD1Fourv8b;
6166 Opc = AArch64::LD1Fourv16b;
6168 Opc = AArch64::LD1Fourv4h;
6170 Opc = AArch64::LD1Fourv8h;
6172 Opc = AArch64::LD1Fourv2s;
6174 Opc = AArch64::LD1Fourv4s;
6176 Opc = AArch64::LD1Fourv2d;
6177 else if (Ty ==
S64 || Ty == P0)
6178 Opc = AArch64::LD1Fourv1d;
6181 selectVectorLoadIntrinsic(
Opc, 4,
I);
6184 case Intrinsic::aarch64_neon_ld2: {
6185 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6188 Opc = AArch64::LD2Twov8b;
6190 Opc = AArch64::LD2Twov16b;
6192 Opc = AArch64::LD2Twov4h;
6194 Opc = AArch64::LD2Twov8h;
6196 Opc = AArch64::LD2Twov2s;
6198 Opc = AArch64::LD2Twov4s;
6200 Opc = AArch64::LD2Twov2d;
6201 else if (Ty ==
S64 || Ty == P0)
6202 Opc = AArch64::LD1Twov1d;
6205 selectVectorLoadIntrinsic(
Opc, 2,
I);
6208 case Intrinsic::aarch64_neon_ld2lane: {
6209 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6212 Opc = AArch64::LD2i8;
6214 Opc = AArch64::LD2i16;
6216 Opc = AArch64::LD2i32;
6219 Opc = AArch64::LD2i64;
6222 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6226 case Intrinsic::aarch64_neon_ld2r: {
6227 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6230 Opc = AArch64::LD2Rv8b;
6232 Opc = AArch64::LD2Rv16b;
6234 Opc = AArch64::LD2Rv4h;
6236 Opc = AArch64::LD2Rv8h;
6238 Opc = AArch64::LD2Rv2s;
6240 Opc = AArch64::LD2Rv4s;
6242 Opc = AArch64::LD2Rv2d;
6243 else if (Ty ==
S64 || Ty == P0)
6244 Opc = AArch64::LD2Rv1d;
6247 selectVectorLoadIntrinsic(
Opc, 2,
I);
6250 case Intrinsic::aarch64_neon_ld3: {
6251 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6254 Opc = AArch64::LD3Threev8b;
6256 Opc = AArch64::LD3Threev16b;
6258 Opc = AArch64::LD3Threev4h;
6260 Opc = AArch64::LD3Threev8h;
6262 Opc = AArch64::LD3Threev2s;
6264 Opc = AArch64::LD3Threev4s;
6266 Opc = AArch64::LD3Threev2d;
6267 else if (Ty ==
S64 || Ty == P0)
6268 Opc = AArch64::LD1Threev1d;
6271 selectVectorLoadIntrinsic(
Opc, 3,
I);
6274 case Intrinsic::aarch64_neon_ld3lane: {
6275 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6278 Opc = AArch64::LD3i8;
6280 Opc = AArch64::LD3i16;
6282 Opc = AArch64::LD3i32;
6285 Opc = AArch64::LD3i64;
6288 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6292 case Intrinsic::aarch64_neon_ld3r: {
6293 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6296 Opc = AArch64::LD3Rv8b;
6298 Opc = AArch64::LD3Rv16b;
6300 Opc = AArch64::LD3Rv4h;
6302 Opc = AArch64::LD3Rv8h;
6304 Opc = AArch64::LD3Rv2s;
6306 Opc = AArch64::LD3Rv4s;
6308 Opc = AArch64::LD3Rv2d;
6309 else if (Ty ==
S64 || Ty == P0)
6310 Opc = AArch64::LD3Rv1d;
6313 selectVectorLoadIntrinsic(
Opc, 3,
I);
6316 case Intrinsic::aarch64_neon_ld4: {
6317 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6320 Opc = AArch64::LD4Fourv8b;
6322 Opc = AArch64::LD4Fourv16b;
6324 Opc = AArch64::LD4Fourv4h;
6326 Opc = AArch64::LD4Fourv8h;
6328 Opc = AArch64::LD4Fourv2s;
6330 Opc = AArch64::LD4Fourv4s;
6332 Opc = AArch64::LD4Fourv2d;
6333 else if (Ty ==
S64 || Ty == P0)
6334 Opc = AArch64::LD1Fourv1d;
6337 selectVectorLoadIntrinsic(
Opc, 4,
I);
6340 case Intrinsic::aarch64_neon_ld4lane: {
6341 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6344 Opc = AArch64::LD4i8;
6346 Opc = AArch64::LD4i16;
6348 Opc = AArch64::LD4i32;
6351 Opc = AArch64::LD4i64;
6354 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6358 case Intrinsic::aarch64_neon_ld4r: {
6359 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6362 Opc = AArch64::LD4Rv8b;
6364 Opc = AArch64::LD4Rv16b;
6366 Opc = AArch64::LD4Rv4h;
6368 Opc = AArch64::LD4Rv8h;
6370 Opc = AArch64::LD4Rv2s;
6372 Opc = AArch64::LD4Rv4s;
6374 Opc = AArch64::LD4Rv2d;
6375 else if (Ty ==
S64 || Ty == P0)
6376 Opc = AArch64::LD4Rv1d;
6379 selectVectorLoadIntrinsic(
Opc, 4,
I);
6382 case Intrinsic::aarch64_neon_st1x2: {
6383 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6386 Opc = AArch64::ST1Twov8b;
6388 Opc = AArch64::ST1Twov16b;
6390 Opc = AArch64::ST1Twov4h;
6392 Opc = AArch64::ST1Twov8h;
6394 Opc = AArch64::ST1Twov2s;
6396 Opc = AArch64::ST1Twov4s;
6398 Opc = AArch64::ST1Twov2d;
6399 else if (Ty ==
S64 || Ty == P0)
6400 Opc = AArch64::ST1Twov1d;
6403 selectVectorStoreIntrinsic(
I, 2,
Opc);
6406 case Intrinsic::aarch64_neon_st1x3: {
6407 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6410 Opc = AArch64::ST1Threev8b;
6412 Opc = AArch64::ST1Threev16b;
6414 Opc = AArch64::ST1Threev4h;
6416 Opc = AArch64::ST1Threev8h;
6418 Opc = AArch64::ST1Threev2s;
6420 Opc = AArch64::ST1Threev4s;
6422 Opc = AArch64::ST1Threev2d;
6423 else if (Ty ==
S64 || Ty == P0)
6424 Opc = AArch64::ST1Threev1d;
6427 selectVectorStoreIntrinsic(
I, 3,
Opc);
6430 case Intrinsic::aarch64_neon_st1x4: {
6431 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6434 Opc = AArch64::ST1Fourv8b;
6436 Opc = AArch64::ST1Fourv16b;
6438 Opc = AArch64::ST1Fourv4h;
6440 Opc = AArch64::ST1Fourv8h;
6442 Opc = AArch64::ST1Fourv2s;
6444 Opc = AArch64::ST1Fourv4s;
6446 Opc = AArch64::ST1Fourv2d;
6447 else if (Ty ==
S64 || Ty == P0)
6448 Opc = AArch64::ST1Fourv1d;
6451 selectVectorStoreIntrinsic(
I, 4,
Opc);
6454 case Intrinsic::aarch64_neon_st2: {
6455 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6458 Opc = AArch64::ST2Twov8b;
6460 Opc = AArch64::ST2Twov16b;
6462 Opc = AArch64::ST2Twov4h;
6464 Opc = AArch64::ST2Twov8h;
6466 Opc = AArch64::ST2Twov2s;
6468 Opc = AArch64::ST2Twov4s;
6470 Opc = AArch64::ST2Twov2d;
6471 else if (Ty ==
S64 || Ty == P0)
6472 Opc = AArch64::ST1Twov1d;
6475 selectVectorStoreIntrinsic(
I, 2,
Opc);
6478 case Intrinsic::aarch64_neon_st3: {
6479 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6482 Opc = AArch64::ST3Threev8b;
6484 Opc = AArch64::ST3Threev16b;
6486 Opc = AArch64::ST3Threev4h;
6488 Opc = AArch64::ST3Threev8h;
6490 Opc = AArch64::ST3Threev2s;
6492 Opc = AArch64::ST3Threev4s;
6494 Opc = AArch64::ST3Threev2d;
6495 else if (Ty ==
S64 || Ty == P0)
6496 Opc = AArch64::ST1Threev1d;
6499 selectVectorStoreIntrinsic(
I, 3,
Opc);
6502 case Intrinsic::aarch64_neon_st4: {
6503 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6506 Opc = AArch64::ST4Fourv8b;
6508 Opc = AArch64::ST4Fourv16b;
6510 Opc = AArch64::ST4Fourv4h;
6512 Opc = AArch64::ST4Fourv8h;
6514 Opc = AArch64::ST4Fourv2s;
6516 Opc = AArch64::ST4Fourv4s;
6518 Opc = AArch64::ST4Fourv2d;
6519 else if (Ty ==
S64 || Ty == P0)
6520 Opc = AArch64::ST1Fourv1d;
6523 selectVectorStoreIntrinsic(
I, 4,
Opc);
6526 case Intrinsic::aarch64_neon_st2lane: {
6527 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6530 Opc = AArch64::ST2i8;
6532 Opc = AArch64::ST2i16;
6534 Opc = AArch64::ST2i32;
6537 Opc = AArch64::ST2i64;
6540 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6544 case Intrinsic::aarch64_neon_st3lane: {
6545 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6548 Opc = AArch64::ST3i8;
6550 Opc = AArch64::ST3i16;
6552 Opc = AArch64::ST3i32;
6555 Opc = AArch64::ST3i64;
6558 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6562 case Intrinsic::aarch64_neon_st4lane: {
6563 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6566 Opc = AArch64::ST4i8;
6568 Opc = AArch64::ST4i16;
6570 Opc = AArch64::ST4i32;
6573 Opc = AArch64::ST4i64;
6576 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6580 case Intrinsic::aarch64_mops_memset_tag: {
6593 Register DstDef =
I.getOperand(0).getReg();
6595 Register DstUse =
I.getOperand(2).getReg();
6596 Register ValUse =
I.getOperand(3).getReg();
6597 Register SizeUse =
I.getOperand(4).getReg();
6604 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6605 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6610 case Intrinsic::ptrauth_resign_load_relative: {
6611 Register DstReg =
I.getOperand(0).getReg();
6612 Register ValReg =
I.getOperand(2).getReg();
6613 uint64_t AUTKey =
I.getOperand(3).getImm();
6614 Register AUTDisc =
I.getOperand(4).getReg();
6615 uint64_t PACKey =
I.getOperand(5).getImm();
6616 Register PACDisc =
I.getOperand(6).getReg();
6617 int64_t Addend =
I.getOperand(7).getImm();
6620 uint16_t AUTConstDiscC = 0;
6621 std::tie(AUTConstDiscC, AUTAddrDisc) =
6625 uint16_t PACConstDiscC = 0;
6626 std::tie(PACConstDiscC, PACAddrDisc) =
6629 MIB.
buildCopy({AArch64::X16}, {ValReg});
6643 I.eraseFromParent();
6648 I.eraseFromParent();
6652bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6653 MachineRegisterInfo &MRI) {
6659 case Intrinsic::ptrauth_resign: {
6660 Register DstReg =
I.getOperand(0).getReg();
6661 Register ValReg =
I.getOperand(2).getReg();
6662 uint64_t AUTKey =
I.getOperand(3).getImm();
6663 Register AUTDisc =
I.getOperand(4).getReg();
6664 uint64_t PACKey =
I.getOperand(5).getImm();
6665 Register PACDisc =
I.getOperand(6).getReg();
6668 uint16_t AUTConstDiscC = 0;
6669 std::tie(AUTConstDiscC, AUTAddrDisc) =
6673 uint16_t PACConstDiscC = 0;
6674 std::tie(PACConstDiscC, PACAddrDisc) =
6677 MIB.
buildCopy({AArch64::X16}, {ValReg});
6678 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6690 I.eraseFromParent();
6693 case Intrinsic::ptrauth_auth: {
6694 Register DstReg =
I.getOperand(0).getReg();
6695 Register ValReg =
I.getOperand(2).getReg();
6696 uint64_t AUTKey =
I.getOperand(3).getImm();
6697 Register AUTDisc =
I.getOperand(4).getReg();
6700 uint16_t AUTConstDiscC = 0;
6701 std::tie(AUTConstDiscC, AUTAddrDisc) =
6705 MIB.
buildCopy({AArch64::X16}, {ValReg});
6706 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6727 I.eraseFromParent();
6730 case Intrinsic::frameaddress:
6731 case Intrinsic::returnaddress: {
6732 MachineFunction &MF = *
I.getParent()->getParent();
6735 unsigned Depth =
I.getOperand(2).getImm();
6736 Register DstReg =
I.getOperand(0).getReg();
6739 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6740 if (!MFReturnAddr) {
6745 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6748 if (STI.hasPAuth()) {
6749 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6756 I.eraseFromParent();
6765 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6767 FrameAddr = NextFrame;
6770 if (IntrinID == Intrinsic::frameaddress)
6775 if (STI.hasPAuth()) {
6777 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6778 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6787 I.eraseFromParent();
6790 case Intrinsic::aarch64_neon_tbl2:
6791 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6793 case Intrinsic::aarch64_neon_tbl3:
6794 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6797 case Intrinsic::aarch64_neon_tbl4:
6798 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6800 case Intrinsic::aarch64_neon_tbx2:
6801 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6803 case Intrinsic::aarch64_neon_tbx3:
6804 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6806 case Intrinsic::aarch64_neon_tbx4:
6807 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6809 case Intrinsic::swift_async_context_addr:
6810 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6817 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6818 I.eraseFromParent();
6853bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6854 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6855 Register DefReg =
I.getOperand(0).getReg();
6856 Register Addr =
I.getOperand(1).getReg();
6857 uint64_t
Key =
I.getOperand(2).getImm();
6858 Register AddrDisc =
I.getOperand(3).getReg();
6859 uint64_t Disc =
I.getOperand(4).getImm();
6869 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6885 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6897 const GlobalValue *GV;
6908 MachineIRBuilder MIB(
I);
6914 "unsupported non-GOT op flags on ptrauth global reference");
6916 "unsupported non-GOT reference to weak ptrauth global");
6919 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6926 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6927 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6928 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6931 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6936 I.eraseFromParent();
6948 "unsupported non-zero offset in weak ptrauth global reference");
6953 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6954 .addGlobalAddress(GV,
Offset)
6959 I.eraseFromParent();
6963void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6964 MachineRegisterInfo &MRI,
6965 unsigned NumVec,
unsigned Opc1,
6966 unsigned Opc2,
bool isExt) {
6967 Register DstReg =
I.getOperand(0).getReg();
6972 for (
unsigned i = 0; i < NumVec; i++)
6973 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6976 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6977 MachineInstrBuilder
Instr;
6984 I.eraseFromParent();
6987InstructionSelector::ComplexRendererFns
6988AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6990 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6991 return std::nullopt;
6992 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6993 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6996InstructionSelector::ComplexRendererFns
6997AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6999 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7000 return std::nullopt;
7001 uint64_t Enc = 31 - *MaybeImmed;
7002 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7005InstructionSelector::ComplexRendererFns
7006AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7008 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7009 return std::nullopt;
7010 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7011 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7014InstructionSelector::ComplexRendererFns
7015AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7017 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7018 return std::nullopt;
7019 uint64_t Enc = 63 - *MaybeImmed;
7020 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7028InstructionSelector::ComplexRendererFns
7029AArch64InstructionSelector::select12BitValueWithLeftShift(
7030 uint64_t Immed)
const {
7032 if (Immed >> 12 == 0) {
7034 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7036 Immed = Immed >> 12;
7038 return std::nullopt;
7042 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7043 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7050InstructionSelector::ComplexRendererFns
7051AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7058 if (MaybeImmed == std::nullopt)
7059 return std::nullopt;
7060 return select12BitValueWithLeftShift(*MaybeImmed);
7065InstructionSelector::ComplexRendererFns
7066AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7070 return std::nullopt;
7072 if (MaybeImmed == std::nullopt)
7073 return std::nullopt;
7074 uint64_t Immed = *MaybeImmed;
7080 return std::nullopt;
7086 Immed = ~((uint32_t)Immed) + 1;
7088 Immed = ~Immed + 1ULL;
7090 if (Immed & 0xFFFFFFFFFF000000ULL)
7091 return std::nullopt;
7093 Immed &= 0xFFFFFFULL;
7094 return select12BitValueWithLeftShift(Immed);
7111std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7112 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7113 if (
MI.getOpcode() == AArch64::G_SHL) {
7117 MI.getOperand(2).getReg(), MRI)) {
7118 const APInt ShiftVal = ValAndVeg->Value;
7121 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7124 return std::nullopt;
7132bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7133 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7134 bool IsAddrOperand)
const {
7139 MI.getParent()->getParent()->getFunction().hasOptSize())
7142 if (IsAddrOperand) {
7144 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7148 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7149 MachineInstr *OffsetInst =
7155 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7166 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7169InstructionSelector::ComplexRendererFns
7170AArch64InstructionSelector::selectExtendedSHL(
7171 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7172 unsigned SizeInBytes,
bool WantsExt)
const {
7173 assert(
Base.isReg() &&
"Expected base to be a register operand");
7174 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7179 unsigned OffsetOpc = OffsetInst->
getOpcode();
7180 bool LookedThroughZExt =
false;
7181 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7183 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7184 return std::nullopt;
7188 LookedThroughZExt =
true;
7190 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7191 return std::nullopt;
7194 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7195 if (LegalShiftVal == 0)
7196 return std::nullopt;
7197 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7198 return std::nullopt;
7209 if (OffsetOpc == TargetOpcode::G_SHL)
7210 return std::nullopt;
7216 return std::nullopt;
7221 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7225 if (OffsetOpc == TargetOpcode::G_MUL) {
7227 return std::nullopt;
7233 if ((ImmVal & 0x7) != ImmVal)
7234 return std::nullopt;
7238 if (ImmVal != LegalShiftVal)
7239 return std::nullopt;
7241 unsigned SignExtend = 0;
7245 if (!LookedThroughZExt) {
7247 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7249 return std::nullopt;
7254 return std::nullopt;
7260 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7265 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7266 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7267 [=](MachineInstrBuilder &MIB) {
7270 MIB.addImm(SignExtend);
7283InstructionSelector::ComplexRendererFns
7284AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7285 MachineOperand &Root,
unsigned SizeInBytes)
const {
7287 return std::nullopt;
7302 MachineInstr *PtrAdd =
7304 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7305 return std::nullopt;
7309 MachineInstr *OffsetInst =
7311 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7324InstructionSelector::ComplexRendererFns
7325AArch64InstructionSelector::selectAddrModeRegisterOffset(
7326 MachineOperand &Root)
const {
7331 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7332 return std::nullopt;
7338 return std::nullopt;
7341 return {{[=](MachineInstrBuilder &MIB) {
7344 [=](MachineInstrBuilder &MIB) {
7347 [=](MachineInstrBuilder &MIB) {
7357InstructionSelector::ComplexRendererFns
7358AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7359 unsigned SizeInBytes)
const {
7362 return std::nullopt;
7363 MachineInstr *PtrAdd =
7366 return std::nullopt;
7384 unsigned Scale =
Log2_32(SizeInBytes);
7385 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7389 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7390 ImmOff < (0x1000 << Scale))
7391 return std::nullopt;
7396 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7400 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7406 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7407 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7412 return std::nullopt;
7416 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7422 return selectAddrModeRegisterOffset(Root);
7431InstructionSelector::ComplexRendererFns
7432AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7433 unsigned SizeInBytes)
const {
7436 MachineInstr *PtrAdd =
7438 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7439 return std::nullopt;
7460 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7469 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7470 return std::nullopt;
7474 getExtendTypeForInst(*OffsetInst, MRI,
true);
7476 return std::nullopt;
7479 MachineIRBuilder MIB(*PtrAdd);
7481 AArch64::GPR32RegClass, MIB);
7485 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7486 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7487 [=](MachineInstrBuilder &MIB) {
7488 MIB.addImm(SignExtend);
7498InstructionSelector::ComplexRendererFns
7499AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7500 unsigned Size)
const {
7501 MachineRegisterInfo &MRI =
7505 return std::nullopt;
7507 if (!isBaseWithConstantOffset(Root, MRI))
7508 return std::nullopt;
7512 MachineOperand &OffImm = RootDef->
getOperand(2);
7513 if (!OffImm.
isReg())
7514 return std::nullopt;
7516 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7517 return std::nullopt;
7519 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7521 return std::nullopt;
7524 if (RHSC >= -256 && RHSC < 256) {
7527 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7528 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7531 return std::nullopt;
7534InstructionSelector::ComplexRendererFns
7535AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7537 MachineRegisterInfo &MRI)
const {
7538 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7539 return std::nullopt;
7542 return std::nullopt;
7547 return std::nullopt;
7551 return std::nullopt;
7555 return std::nullopt;
7558 MachineIRBuilder MIRBuilder(RootDef);
7560 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7561 [=](MachineInstrBuilder &MIB) {
7562 MIB.addGlobalAddress(GV,
Offset,
7571InstructionSelector::ComplexRendererFns
7572AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7573 unsigned Size)
const {
7578 return std::nullopt;
7581 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7583 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7584 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7592 MachineInstr *RootParent = Root.
getParent();
7594 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7596 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7601 if (isBaseWithConstantOffset(Root, MRI)) {
7609 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7610 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7612 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7613 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7617 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7618 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7625 if (selectAddrModeUnscaled(Root,
Size))
7626 return std::nullopt;
7629 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7630 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7637 switch (
MI.getOpcode()) {
7640 case TargetOpcode::G_SHL:
7642 case TargetOpcode::G_LSHR:
7644 case TargetOpcode::G_ASHR:
7646 case TargetOpcode::G_ROTR:
7653InstructionSelector::ComplexRendererFns
7654AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7655 bool AllowROR)
const {
7657 return std::nullopt;
7658 MachineRegisterInfo &MRI =
7666 return std::nullopt;
7668 return std::nullopt;
7669 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7670 return std::nullopt;
7673 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7676 return std::nullopt;
7680 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7684 unsigned Val = *Immed & (NumBits - 1);
7687 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7688 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7692 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7693 unsigned Opc =
MI.getOpcode();
7696 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7698 if (
Opc == TargetOpcode::G_SEXT)
7701 Size =
MI.getOperand(2).getImm();
7702 assert(
Size != 64 &&
"Extend from 64 bits?");
7715 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7717 assert(
Size != 64 &&
"Extend from 64 bits?");
7732 if (
Opc != TargetOpcode::G_AND)
7738 uint64_t AndMask = *MaybeAndMask;
7751Register AArch64InstructionSelector::moveScalarRegClass(
7752 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7753 MachineRegisterInfo &MRI = *MIB.
getMRI();
7763 return Copy.getReg(0);
7768InstructionSelector::ComplexRendererFns
7769AArch64InstructionSelector::selectArithExtendedRegister(
7770 MachineOperand &Root)
const {
7772 return std::nullopt;
7773 MachineRegisterInfo &MRI =
7776 uint64_t ShiftVal = 0;
7781 return std::nullopt;
7783 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7784 return std::nullopt;
7787 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7792 return std::nullopt;
7793 ShiftVal = *MaybeShiftVal;
7795 return std::nullopt;
7800 return std::nullopt;
7801 Ext = getExtendTypeForInst(*ExtDef, MRI);
7803 return std::nullopt;
7807 Ext = getExtendTypeForInst(*RootDef, MRI);
7809 return std::nullopt;
7817 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7818 if (isDef32(*ExtInst))
7819 return std::nullopt;
7825 MachineIRBuilder MIB(*RootDef);
7826 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7828 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7829 [=](MachineInstrBuilder &MIB) {
7830 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7834InstructionSelector::ComplexRendererFns
7835AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7837 return std::nullopt;
7838 MachineRegisterInfo &MRI =
7842 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7847 return std::nullopt;
7850 if (Unmerge->getNumDefs() == 2 &&
7852 Register ExtReg = Unmerge->getSourceReg();
7853 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7857 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7861 LaneIdx->Value.getSExtValue() == 1) {
7862 Register ExtReg = ExtElt->getVectorReg();
7863 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7867 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7868 auto LaneIdx = Subvec->getIndexImm();
7870 Register ExtReg = Subvec->getSrcVec();
7871 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7875 return std::nullopt;
7878InstructionSelector::ComplexRendererFns
7879AArch64InstructionSelector::selectCVTFixedPointVecBase(
7880 const MachineOperand &Root,
bool isReciprocal)
const {
7882 return std::nullopt;
7883 const MachineRegisterInfo &MRI =
7888 return std::nullopt;
7889 std::optional<ValueAndVReg> CstVal =
7892 return std::nullopt;
7898 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7901 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7904 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7907 return std::nullopt;
7909 if (
unsigned FBits =
7911 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7913 return std::nullopt;
7916InstructionSelector::ComplexRendererFns
7917AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
7918 return selectCVTFixedPointVecBase(Root,
false);
7921InstructionSelector::ComplexRendererFns
7922AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
7923 MachineOperand &Root)
const {
7924 return selectCVTFixedPointVecBase(Root,
true);
7927void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
7928 const MachineInstr &
MI,
7933 InstructionSelector::ComplexRendererFns Renderer =
7934 selectCVTFixedPointVecBase(
MI.getOperand(2),
false);
7935 assert((Renderer && Renderer->size() == 1) &&
7936 "Expected selectCVTFixedPointVec to provide a function\n");
7937 (Renderer->front())(MIB);
7940void AArch64InstructionSelector::renderFixedPointRecipXForm(
7941 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7942 InstructionSelector::ComplexRendererFns Renderer =
7943 selectCVTFixedPointVecBase(
MI.getOperand(2),
true);
7944 assert((Renderer && Renderer->size() == 1) &&
7945 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
7946 (Renderer->front())(MIB);
7949void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7950 const MachineInstr &
MI,
7952 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
7953 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7954 "Expected G_CONSTANT");
7955 std::optional<int64_t> CstVal =
7957 assert(CstVal &&
"Expected constant value");
7961void AArch64InstructionSelector::renderLogicalImm32(
7962 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7963 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7964 "Expected G_CONSTANT");
7965 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7970void AArch64InstructionSelector::renderLogicalImm64(
7971 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7972 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7973 "Expected G_CONSTANT");
7974 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7979void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7980 const MachineInstr &
MI,
7982 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7983 "Expected G_UBSANTRAP");
7984 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7987void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7988 const MachineInstr &
MI,
7990 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7991 "Expected G_FCONSTANT");
7996void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7997 const MachineInstr &
MI,
7999 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8000 "Expected G_FCONSTANT");
8005void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8006 const MachineInstr &
MI,
8008 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8009 "Expected G_FCONSTANT");
8014void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8015 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8016 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
8017 "Expected G_FCONSTANT");
8025bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8026 const MachineInstr &
MI,
unsigned NumBytes)
const {
8027 if (!
MI.mayLoadOrStore())
8030 "Expected load/store to have only one mem op!");
8031 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8034bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8035 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8043 switch (
MI.getOpcode()) {
8046 case TargetOpcode::COPY:
8047 case TargetOpcode::G_BITCAST:
8048 case TargetOpcode::G_TRUNC:
8049 case TargetOpcode::G_PHI:
8059 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8062 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8080 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8085 MO.setReg(Copy.getReg(0));
8090void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8094 for (
auto &BB : MF) {
8095 for (
auto &
MI : BB) {
8096 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8101 for (
auto *
MI : Phis) {
8123 bool HasGPROp =
false, HasFPROp =
false;
8127 const LLT &Ty = MRI.
getType(MO.getReg());
8137 if (RB->
getID() == AArch64::GPRRegBankID)
8143 if (HasGPROp && HasFPROp)
8149InstructionSelector *
8153 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
static std::pair< const TargetRegisterClass *, const TargetRegisterClass * > getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Helper function to get the source and destination register classes for a copy.
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc (such as G_OR or G_SDIV),...
static bool getSubRegForClass(const TargetRegisterClass *RC, const TargetRegisterInfo &TRI, unsigned &SubReg)
Returns the correct subregister to use for a given register class.
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI, Register SrcReg, const TargetRegisterClass *To, unsigned SubReg)
Helper function for selectCopy.
static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P, Register RHS={}, MachineRegisterInfo *MRI=nullptr)
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, const AArch64RegisterBankInfo &RBI)
static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool unsupportedBinOp(const MachineInstr &I, const AArch64RegisterBankInfo &RBI, const MachineRegisterInfo &MRI, const AArch64RegisterInfo &TRI)
Check whether I is a currently unsupported binary operation:
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineInstr unsigned OpIdx
static MachineBasicBlock * emitSelect(MachineInstr &MI, MachineBasicBlock *BB, const TargetInstrInfo *TII, const PPCSubtarget &Subtarget)
Emit SELECT instruction, using ISEL if available, otherwise use branch-based control flow.
static StringRef getName(Value *V)
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
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
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
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.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
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.