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;
489 int OpIdx = -1)
const;
492 int OpIdx = -1)
const;
494 int OpIdx = -1)
const;
496 int OpIdx = -1)
const;
500 int OpIdx = -1)
const;
502 int OpIdx = -1)
const;
504 int OpIdx = -1)
const;
507 int OpIdx = -1)
const;
513 bool tryOptSelect(
GSelect &Sel);
520 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
533 bool ProduceNonFlagSettingCondBr =
false;
542#define GET_GLOBALISEL_PREDICATES_DECL
543#include "AArch64GenGlobalISel.inc"
544#undef GET_GLOBALISEL_PREDICATES_DECL
548#define GET_GLOBALISEL_TEMPORARIES_DECL
549#include "AArch64GenGlobalISel.inc"
550#undef GET_GLOBALISEL_TEMPORARIES_DECL
555#define GET_GLOBALISEL_IMPL
556#include "AArch64GenGlobalISel.inc"
557#undef GET_GLOBALISEL_IMPL
559AArch64InstructionSelector::AArch64InstructionSelector(
562 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
565#include
"AArch64GenGlobalISel.inc"
568#include
"AArch64GenGlobalISel.inc"
580 bool GetAllRegSet =
false) {
581 if (RB.
getID() == AArch64::GPRRegBankID) {
582 if (Ty.getSizeInBits() <= 32)
583 return GetAllRegSet ? &AArch64::GPR32allRegClass
584 : &AArch64::GPR32RegClass;
585 if (Ty.getSizeInBits() == 64)
586 return GetAllRegSet ? &AArch64::GPR64allRegClass
587 : &AArch64::GPR64RegClass;
588 if (Ty.getSizeInBits() == 128)
589 return &AArch64::XSeqPairsClassRegClass;
593 if (RB.
getID() == AArch64::FPRRegBankID) {
594 switch (Ty.getSizeInBits()) {
596 return &AArch64::FPR8RegClass;
598 return &AArch64::FPR16RegClass;
600 return &AArch64::FPR32RegClass;
602 return &AArch64::FPR64RegClass;
604 return &AArch64::FPR128RegClass;
616 bool GetAllRegSet =
false) {
619 "Expected FPR regbank for scalable type size");
620 return &AArch64::ZPRRegClass;
623 unsigned RegBankID = RB.
getID();
625 if (RegBankID == AArch64::GPRRegBankID) {
627 if (SizeInBits <= 32)
628 return GetAllRegSet ? &AArch64::GPR32allRegClass
629 : &AArch64::GPR32RegClass;
630 if (SizeInBits == 64)
631 return GetAllRegSet ? &AArch64::GPR64allRegClass
632 : &AArch64::GPR64RegClass;
633 if (SizeInBits == 128)
634 return &AArch64::XSeqPairsClassRegClass;
637 if (RegBankID == AArch64::FPRRegBankID) {
640 "Unexpected scalable register size");
641 return &AArch64::ZPRRegClass;
644 switch (SizeInBits) {
648 return &AArch64::FPR8RegClass;
650 return &AArch64::FPR16RegClass;
652 return &AArch64::FPR32RegClass;
654 return &AArch64::FPR64RegClass;
656 return &AArch64::FPR128RegClass;
666 switch (
TRI.getRegSizeInBits(*RC)) {
668 SubReg = AArch64::bsub;
671 SubReg = AArch64::hsub;
674 if (RC != &AArch64::FPR32RegClass)
675 SubReg = AArch64::sub_32;
677 SubReg = AArch64::ssub;
680 SubReg = AArch64::dsub;
684 dbgs() <<
"Couldn't find appropriate subregister for register class.");
693 switch (RB.
getID()) {
694 case AArch64::GPRRegBankID:
696 case AArch64::FPRRegBankID:
719 const unsigned RegClassIDs[],
721 unsigned NumRegs = Regs.
size();
724 assert(NumRegs >= 2 && NumRegs <= 4 &&
725 "Only support between two and 4 registers in a tuple!");
727 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
729 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
730 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
731 RegSequence.addUse(Regs[
I]);
732 RegSequence.addImm(SubRegs[
I]);
734 return RegSequence.getReg(0);
739 static const unsigned RegClassIDs[] = {
740 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
741 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
742 AArch64::dsub2, AArch64::dsub3};
743 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
748 static const unsigned RegClassIDs[] = {
749 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
750 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
751 AArch64::qsub2, AArch64::qsub3};
752 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
757 auto &
MBB = *
MI.getParent();
758 auto &MF = *
MBB.getParent();
759 auto &MRI = MF.getRegInfo();
765 else if (Root.
isReg()) {
770 Immed = ValAndVReg->Value.getSExtValue();
793 for (
auto &MO :
I.operands()) {
796 LLVM_DEBUG(
dbgs() <<
"Generic inst non-reg operands are unsupported\n");
804 if (!MO.getReg().isVirtual()) {
805 LLVM_DEBUG(
dbgs() <<
"Generic inst has physical register operand\n");
815 if (PrevOpBank && OpBank != PrevOpBank) {
816 LLVM_DEBUG(
dbgs() <<
"Generic inst operands have different banks\n");
831 case AArch64::GPRRegBankID:
833 switch (GenericOpc) {
834 case TargetOpcode::G_SHL:
835 return AArch64::LSLVWr;
836 case TargetOpcode::G_LSHR:
837 return AArch64::LSRVWr;
838 case TargetOpcode::G_ASHR:
839 return AArch64::ASRVWr;
843 }
else if (OpSize == 64) {
844 switch (GenericOpc) {
845 case TargetOpcode::G_PTR_ADD:
846 return AArch64::ADDXrr;
847 case TargetOpcode::G_SHL:
848 return AArch64::LSLVXr;
849 case TargetOpcode::G_LSHR:
850 return AArch64::LSRVXr;
851 case TargetOpcode::G_ASHR:
852 return AArch64::ASRVXr;
858 case AArch64::FPRRegBankID:
861 switch (GenericOpc) {
862 case TargetOpcode::G_FADD:
863 return AArch64::FADDSrr;
864 case TargetOpcode::G_FSUB:
865 return AArch64::FSUBSrr;
866 case TargetOpcode::G_FMUL:
867 return AArch64::FMULSrr;
868 case TargetOpcode::G_FDIV:
869 return AArch64::FDIVSrr;
874 switch (GenericOpc) {
875 case TargetOpcode::G_FADD:
876 return AArch64::FADDDrr;
877 case TargetOpcode::G_FSUB:
878 return AArch64::FSUBDrr;
879 case TargetOpcode::G_FMUL:
880 return AArch64::FMULDrr;
881 case TargetOpcode::G_FDIV:
882 return AArch64::FDIVDrr;
883 case TargetOpcode::G_OR:
884 return AArch64::ORRv8i8;
901 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
903 case AArch64::GPRRegBankID:
906 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
908 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
910 return isStore ? AArch64::STRWui : AArch64::LDRWui;
912 return isStore ? AArch64::STRXui : AArch64::LDRXui;
915 case AArch64::FPRRegBankID:
918 return isStore ? AArch64::STRBui : AArch64::LDRBui;
920 return isStore ? AArch64::STRHui : AArch64::LDRHui;
922 return isStore ? AArch64::STRSui : AArch64::LDRSui;
924 return isStore ? AArch64::STRDui : AArch64::LDRDui;
926 return isStore ? AArch64::STRQui : AArch64::LDRQui;
940 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
941 assert(To &&
"Destination register class cannot be null");
942 assert(SubReg &&
"Expected a valid subregister");
946 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
948 RegOp.
setReg(SubRegCopy.getReg(0));
952 if (!
I.getOperand(0).getReg().isPhysical())
962static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
966 Register DstReg =
I.getOperand(0).getReg();
967 Register SrcReg =
I.getOperand(1).getReg();
982 if (SrcRegBank != DstRegBank &&
1001 if (
Reg.isPhysical())
1009 RC = getRegClassForTypeOnBank(Ty, RB);
1012 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
1025 Register DstReg =
I.getOperand(0).getReg();
1026 Register SrcReg =
I.getOperand(1).getReg();
1045 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1049 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1050 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1061 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1062 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
1063 }
else if (SrcSize > DstSize) {
1070 }
else if (DstSize > SrcSize) {
1079 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1083 RegOp.
setReg(PromoteReg);
1102 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1103 I.setDesc(
TII.get(AArch64::COPY));
1104 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1108 I.setDesc(
TII.get(AArch64::COPY));
1116 MachineRegisterInfo &MRI = *MIB.
getMRI();
1119 "Expected both select operands to have the same regbank?");
1125 "Expected 32 bit or 64 bit select only?");
1126 const bool Is32Bit =
Size == 32;
1128 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1129 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1135 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1137 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1152 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1169 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1188 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1204 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1210 if (!TrueCst && !FalseCst)
1213 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1214 if (TrueCst && FalseCst) {
1215 int64_t
T = TrueCst->Value.getSExtValue();
1216 int64_t
F = FalseCst->Value.getSExtValue();
1218 if (
T == 0 &&
F == 1) {
1220 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1226 if (
T == 0 &&
F == -1) {
1228 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1236 int64_t
T = TrueCst->Value.getSExtValue();
1239 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1248 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1257 int64_t
F = FalseCst->Value.getSExtValue();
1260 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1267 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1275 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1276 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1278 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1280 return &*SelectInst;
1285 MachineRegisterInfo *MRI =
nullptr) {
1298 if (ValAndVReg && ValAndVReg->Value == 0)
1305 if (ValAndVReg && ValAndVReg->Value == 0)
1409 assert(
Reg.isValid() &&
"Expected valid register!");
1410 bool HasZext =
false;
1412 unsigned Opc =
MI->getOpcode();
1414 if (!
MI->getOperand(0).isReg() ||
1423 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1424 Opc == TargetOpcode::G_TRUNC) {
1425 if (
Opc == TargetOpcode::G_ZEXT)
1428 Register NextReg =
MI->getOperand(1).getReg();
1442 std::optional<uint64_t>
C;
1447 case TargetOpcode::G_AND:
1448 case TargetOpcode::G_XOR: {
1449 TestReg =
MI->getOperand(1).getReg();
1450 Register ConstantReg =
MI->getOperand(2).getReg();
1461 C = VRegAndVal->Value.getZExtValue();
1463 C = VRegAndVal->Value.getSExtValue();
1467 case TargetOpcode::G_ASHR:
1468 case TargetOpcode::G_LSHR:
1469 case TargetOpcode::G_SHL: {
1470 TestReg =
MI->getOperand(1).getReg();
1474 C = VRegAndVal->Value.getSExtValue();
1490 case TargetOpcode::G_AND:
1492 if ((*
C >> Bit) & 1)
1495 case TargetOpcode::G_SHL:
1498 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1503 case TargetOpcode::G_ASHR:
1508 if (Bit >= TestRegSize)
1509 Bit = TestRegSize - 1;
1511 case TargetOpcode::G_LSHR:
1513 if ((Bit + *
C) < TestRegSize) {
1518 case TargetOpcode::G_XOR:
1527 if ((*
C >> Bit) & 1)
1542MachineInstr *AArch64InstructionSelector::emitTestBit(
1543 Register TestReg, uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1544 MachineIRBuilder &MIB)
const {
1546 assert(ProduceNonFlagSettingCondBr &&
1547 "Cannot emit TB(N)Z with speculation tracking!");
1548 MachineRegisterInfo &MRI = *MIB.
getMRI();
1552 LLT Ty = MRI.
getType(TestReg);
1555 assert(Bit < 64 &&
"Bit is too large!");
1559 bool UseWReg =
Bit < 32;
1560 unsigned NecessarySize = UseWReg ? 32 : 64;
1561 if (
Size != NecessarySize)
1562 TestReg = moveScalarRegClass(
1563 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1566 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1567 {AArch64::TBZW, AArch64::TBNZW}};
1568 unsigned Opc = OpcTable[UseWReg][IsNegative];
1575bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1576 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1577 MachineIRBuilder &MIB)
const {
1578 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1605 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1612 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1616MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1618 MachineBasicBlock *DestMBB,
1619 MachineIRBuilder &MIB)
const {
1620 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1621 MachineRegisterInfo &MRI = *MIB.
getMRI();
1623 AArch64::GPRRegBankID &&
1624 "Expected GPRs only?");
1625 auto Ty = MRI.
getType(CompareReg);
1628 assert(Width <= 64 &&
"Expected width to be at most 64?");
1629 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1630 {AArch64::CBNZW, AArch64::CBNZX}};
1631 unsigned Opc = OpcTable[IsNegative][Width == 64];
1632 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1637bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1638 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1640 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1648 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1652 I.eraseFromParent();
1656bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1657 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1659 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1665 if (!ProduceNonFlagSettingCondBr)
1668 MachineRegisterInfo &MRI = *MIB.
getMRI();
1669 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1684 if (VRegAndVal && !AndInst) {
1685 int64_t
C = VRegAndVal->Value.getSExtValue();
1691 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1692 I.eraseFromParent();
1700 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1701 I.eraseFromParent();
1709 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1710 I.eraseFromParent();
1724 if (VRegAndVal && VRegAndVal->Value == 0) {
1732 tryOptAndIntoCompareBranch(
1734 I.eraseFromParent();
1740 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1742 I.eraseFromParent();
1751bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1752 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1754 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1755 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1759 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1766 I.eraseFromParent();
1770bool AArch64InstructionSelector::selectCompareBranch(
1771 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI) {
1772 Register CondReg =
I.getOperand(0).getReg();
1773 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1777 if (CCMIOpc == TargetOpcode::G_FCMP)
1778 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1779 if (CCMIOpc == TargetOpcode::G_ICMP)
1780 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1785 if (ProduceNonFlagSettingCondBr) {
1786 emitTestBit(CondReg, 0,
true,
1787 I.getOperand(1).getMBB(), MIB);
1788 I.eraseFromParent();
1798 .
addMBB(
I.getOperand(1).getMBB());
1799 I.eraseFromParent();
1819 return std::nullopt;
1821 int64_t Imm = *ShiftImm;
1823 return std::nullopt;
1824 switch (SrcTy.getElementType().getSizeInBits()) {
1827 return std::nullopt;
1830 return std::nullopt;
1834 return std::nullopt;
1838 return std::nullopt;
1842 return std::nullopt;
1848bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1849 MachineRegisterInfo &MRI) {
1850 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1851 Register DstReg =
I.getOperand(0).getReg();
1852 const LLT Ty = MRI.
getType(DstReg);
1853 Register Src1Reg =
I.getOperand(1).getReg();
1854 Register Src2Reg =
I.getOperand(2).getReg();
1865 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1867 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1869 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1871 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1873 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1875 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1877 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1889 I.eraseFromParent();
1893bool AArch64InstructionSelector::selectVectorAshrLshr(
1894 MachineInstr &
I, MachineRegisterInfo &MRI) {
1895 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1896 I.getOpcode() == TargetOpcode::G_LSHR);
1897 Register DstReg =
I.getOperand(0).getReg();
1898 const LLT Ty = MRI.
getType(DstReg);
1899 Register Src1Reg =
I.getOperand(1).getReg();
1900 Register Src2Reg =
I.getOperand(2).getReg();
1905 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1915 unsigned NegOpc = 0;
1916 const TargetRegisterClass *RC =
1917 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1919 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1920 NegOpc = AArch64::NEGv2i64;
1922 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1923 NegOpc = AArch64::NEGv4i32;
1925 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1926 NegOpc = AArch64::NEGv2i32;
1928 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1929 NegOpc = AArch64::NEGv4i16;
1931 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1932 NegOpc = AArch64::NEGv8i16;
1934 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1935 NegOpc = AArch64::NEGv16i8;
1937 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1938 NegOpc = AArch64::NEGv8i8;
1944 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1948 I.eraseFromParent();
1952bool AArch64InstructionSelector::selectVaStartAAPCS(
1953 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI)
const {
1962 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1964 const auto *PtrRegClass =
1965 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1967 const MCInstrDesc &MCIDAddAddr =
1969 const MCInstrDesc &MCIDStoreAddr =
1981 const auto VAList =
I.getOperand(0).getReg();
1984 unsigned OffsetBytes = 0;
1988 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1990 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1997 const auto *MMO = *
I.memoperands_begin();
1998 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
2001 .
addImm(OffsetBytes / PtrSize)
2003 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2007 OffsetBytes += PtrSize;
2023 const auto PushIntConstant = [&](
const int32_t
Value) {
2024 constexpr int IntSize = 4;
2027 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
2032 const auto *MMO = *
I.memoperands_begin();
2033 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
2036 .
addImm(OffsetBytes / IntSize)
2038 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2041 OffsetBytes += IntSize;
2045 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2048 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2052 I.eraseFromParent();
2056bool AArch64InstructionSelector::selectVaStartDarwin(
2057 MachineInstr &
I, MachineFunction &MF, MachineRegisterInfo &MRI)
const {
2058 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2059 Register ListReg =
I.getOperand(0).getReg();
2064 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2072 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2080 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2087 I.eraseFromParent();
2091void AArch64InstructionSelector::materializeLargeCMVal(
2092 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2097 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2112 GV, MovZ->getOperand(1).getOffset(), Flags));
2116 MovZ->getOperand(1).getOffset(), Flags));
2122 Register DstReg = BuildMovK(MovZ.getReg(0),
2128bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2133 switch (
I.getOpcode()) {
2134 case TargetOpcode::G_CONSTANT: {
2135 Register DefReg =
I.getOperand(0).getReg();
2136 const LLT DefTy = MRI.
getType(DefReg);
2140 if (PtrSize != 32 && PtrSize != 64)
2146 case TargetOpcode::G_STORE: {
2147 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2148 MachineOperand &SrcOp =
I.getOperand(0);
2161 case TargetOpcode::G_PTR_ADD: {
2165 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2167 return convertPtrAddToAdd(
I, MRI);
2169 case TargetOpcode::G_LOAD: {
2174 Register DstReg =
I.getOperand(0).getReg();
2175 const LLT DstTy = MRI.
getType(DstReg);
2181 case AArch64::G_DUP: {
2183 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2187 MRI.
setType(
I.getOperand(0).getReg(),
2189 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2190 I.getOperand(1).setReg(NewSrc.getReg(0));
2193 case AArch64::G_INSERT_VECTOR_ELT: {
2195 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2196 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2200 MRI.
setType(
I.getOperand(1).getReg(),
2202 MRI.
setType(
I.getOperand(0).getReg(),
2204 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2205 I.getOperand(2).setReg(NewSrc.getReg(0));
2208 case TargetOpcode::G_UITOFP:
2209 case TargetOpcode::G_SITOFP: {
2214 Register SrcReg =
I.getOperand(1).getReg();
2215 LLT SrcTy = MRI.
getType(SrcReg);
2216 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2221 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2222 I.setDesc(
TII.get(AArch64::G_SITOF));
2224 I.setDesc(
TII.get(AArch64::G_UITOF));
2242bool AArch64InstructionSelector::convertPtrAddToAdd(
2243 MachineInstr &
I, MachineRegisterInfo &MRI) {
2244 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2245 Register DstReg =
I.getOperand(0).getReg();
2246 Register AddOp1Reg =
I.getOperand(1).getReg();
2247 const LLT PtrTy = MRI.
getType(DstReg);
2251 const LLT CastPtrTy =
2262 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2263 MRI.
setType(DstReg, CastPtrTy);
2264 I.getOperand(1).setReg(PtrToInt.getReg(0));
2265 if (!select(*PtrToInt)) {
2266 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2275 I.getOperand(2).setReg(NegatedReg);
2276 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2280bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2281 MachineRegisterInfo &MRI) {
2285 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2286 const auto &MO =
I.getOperand(2);
2291 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2295 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2296 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2298 if (!Imm1Fn || !Imm2Fn)
2302 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2303 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2305 for (
auto &RenderFn : *Imm1Fn)
2307 for (
auto &RenderFn : *Imm2Fn)
2310 I.eraseFromParent();
2315bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2316 MachineInstr &
I, MachineRegisterInfo &MRI) {
2317 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2335 LLT DefDstTy = MRI.
getType(DefDstReg);
2336 Register StoreSrcReg =
I.getOperand(0).getReg();
2337 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2353 I.getOperand(0).setReg(DefDstReg);
2357bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2358 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2359 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2365 switch (
I.getOpcode()) {
2366 case AArch64::G_DUP: {
2369 Register Src =
I.getOperand(1).getReg();
2371 Src, MRI,
true,
true);
2375 Register Dst =
I.getOperand(0).getReg();
2381 if (!emitConstantVector(Dst, CV, MIB, MRI))
2383 I.eraseFromParent();
2386 case TargetOpcode::G_SEXT:
2389 if (selectUSMovFromExtend(
I, MRI))
2392 case TargetOpcode::G_BR:
2394 case TargetOpcode::G_SHL:
2395 return earlySelectSHL(
I, MRI);
2396 case TargetOpcode::G_CONSTANT: {
2397 bool IsZero =
false;
2398 if (
I.getOperand(1).isCImm())
2399 IsZero =
I.getOperand(1).getCImm()->isZero();
2400 else if (
I.getOperand(1).isImm())
2401 IsZero =
I.getOperand(1).getImm() == 0;
2406 Register DefReg =
I.getOperand(0).getReg();
2409 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2412 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2417 I.setDesc(
TII.get(TargetOpcode::COPY));
2421 case TargetOpcode::G_ADD: {
2430 Register AddDst =
I.getOperand(0).getReg();
2431 Register AddLHS =
I.getOperand(1).getReg();
2432 Register AddRHS =
I.getOperand(2).getReg();
2442 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2463 MachineInstr *
Cmp = MatchCmp(AddRHS);
2467 Cmp = MatchCmp(AddRHS);
2471 auto &PredOp =
Cmp->getOperand(1);
2473 emitIntegerCompare(
Cmp->getOperand(2),
2474 Cmp->getOperand(3), PredOp, MIB);
2478 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2479 I.eraseFromParent();
2482 case TargetOpcode::G_OR: {
2486 Register Dst =
I.getOperand(0).getReg();
2506 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2509 int64_t Immr =
Size - ShiftImm;
2510 int64_t Imms =
Size - ShiftImm - 1;
2511 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2512 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2513 I.eraseFromParent();
2516 case TargetOpcode::G_FENCE: {
2517 if (
I.getOperand(1).getImm() == 0)
2521 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2522 I.eraseFromParent();
2530bool AArch64InstructionSelector::select(MachineInstr &
I) {
2531 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2532 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2538 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2539 if (Subtarget->requiresStrictAlign()) {
2541 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2547 unsigned Opcode =
I.getOpcode();
2549 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2552 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2557 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2558 const Register DefReg =
I.getOperand(0).getReg();
2559 const LLT DefTy = MRI.
getType(DefReg);
2564 const TargetRegisterClass *DefRC =
2572 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2579 I.setDesc(
TII.get(TargetOpcode::PHI));
2587 if (
I.isDebugInstr())
2594 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2596 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2603 if (preISelLower(
I)) {
2604 Opcode =
I.getOpcode();
2615 if (selectImpl(
I, *CoverageInfo))
2619 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2622 case TargetOpcode::G_SBFX:
2623 case TargetOpcode::G_UBFX: {
2624 static const unsigned OpcTable[2][2] = {
2625 {AArch64::UBFMWri, AArch64::UBFMXri},
2626 {AArch64::SBFMWri, AArch64::SBFMXri}};
2627 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2629 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2632 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2635 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2636 auto LSB = Cst1->Value.getZExtValue();
2637 auto Width = Cst2->Value.getZExtValue();
2641 .
addImm(LSB + Width - 1);
2642 I.eraseFromParent();
2646 case TargetOpcode::G_BRCOND:
2647 return selectCompareBranch(
I, MF, MRI);
2649 case TargetOpcode::G_BRINDIRECT: {
2651 if (std::optional<uint16_t> BADisc =
2653 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2656 MI.addReg(AArch64::XZR);
2657 I.eraseFromParent();
2661 I.setDesc(
TII.get(AArch64::BR));
2666 case TargetOpcode::G_BRJT:
2667 return selectBrJT(
I, MRI);
2669 case AArch64::G_ADD_LOW: {
2674 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2675 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2676 I.setDesc(
TII.get(AArch64::ADDXri));
2682 "Expected small code model");
2684 auto Op2 =
I.getOperand(2);
2685 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2686 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2687 Op1.getTargetFlags())
2689 Op2.getTargetFlags());
2690 I.eraseFromParent();
2695 case TargetOpcode::G_FCONSTANT: {
2696 const Register DefReg =
I.getOperand(0).getReg();
2697 const LLT DefTy = MRI.
getType(DefReg);
2701 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2708 bool OptForSize = shouldOptForSize(&MF);
2712 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2719 auto *FPImm =
I.getOperand(1).getFPImm();
2722 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2725 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2726 I.eraseFromParent();
2731 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2734 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2735 MachineOperand &RegOp =
I.getOperand(0);
2741 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2745 MachineOperand &ImmOp =
I.getOperand(1);
2749 const unsigned MovOpc =
2750 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2751 I.setDesc(
TII.get(MovOpc));
2755 case TargetOpcode::G_EXTRACT: {
2756 Register DstReg =
I.getOperand(0).getReg();
2757 Register SrcReg =
I.getOperand(1).getReg();
2758 LLT SrcTy = MRI.
getType(SrcReg);
2759 LLT DstTy = MRI.
getType(DstReg);
2771 unsigned Offset =
I.getOperand(2).getImm();
2776 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2777 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2780 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2782 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2784 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2786 AArch64::GPR64RegClass, NewI->getOperand(0));
2787 I.eraseFromParent();
2793 unsigned LaneIdx =
Offset / 64;
2794 MachineInstr *Extract = emitExtractVectorElt(
2795 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2798 I.eraseFromParent();
2802 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2803 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2808 "unexpected G_EXTRACT types");
2815 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2816 .addReg(DstReg, {}, AArch64::sub_32);
2818 AArch64::GPR32RegClass, MRI);
2819 I.getOperand(0).setReg(DstReg);
2825 case TargetOpcode::G_INSERT: {
2826 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2827 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2834 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2835 unsigned LSB =
I.getOperand(3).getImm();
2837 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2838 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2842 "unexpected G_INSERT types");
2849 TII.get(AArch64::SUBREG_TO_REG))
2851 .
addUse(
I.getOperand(2).getReg())
2852 .
addImm(AArch64::sub_32);
2854 AArch64::GPR32RegClass, MRI);
2855 I.getOperand(2).setReg(SrcReg);
2860 case TargetOpcode::G_FRAME_INDEX: {
2867 I.setDesc(
TII.get(AArch64::ADDXri));
2877 case TargetOpcode::G_GLOBAL_VALUE: {
2878 const GlobalValue *GV =
nullptr;
2880 if (
I.getOperand(1).isSymbol()) {
2881 OpFlags =
I.getOperand(1).getTargetFlags();
2890 return selectTLSGlobalValue(
I, MRI);
2896 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2897 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2898 I.getOperand(1).setTargetFlags(OpFlags);
2899 I.addImplicitDefUseOperands(MF);
2903 materializeLargeCMVal(
I, GV, OpFlags);
2904 I.eraseFromParent();
2907 I.setDesc(
TII.get(AArch64::ADR));
2908 I.getOperand(1).setTargetFlags(OpFlags);
2910 I.setDesc(
TII.get(AArch64::MOVaddr));
2912 MachineInstrBuilder MIB(MF,
I);
2913 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2920 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2921 return selectPtrAuthGlobalValue(
I, MRI);
2923 case TargetOpcode::G_ZEXTLOAD:
2924 case TargetOpcode::G_LOAD:
2925 case TargetOpcode::G_STORE: {
2927 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2942 assert(MemSizeInBytes <= 8 &&
2943 "128-bit atomics should already be custom-legalized");
2946 static constexpr unsigned LDAPROpcodes[] = {
2947 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2948 static constexpr unsigned LDAROpcodes[] = {
2949 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2950 ArrayRef<unsigned> Opcodes =
2951 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2954 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2956 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2957 AArch64::STLRW, AArch64::STLRX};
2962 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2963 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2964 I.getOperand(0).setReg(NewVal);
2966 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2974 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2977 "Load/Store pointer operand isn't a GPR");
2979 "Load/Store pointer operand isn't a pointer");
2984 LLT ValTy = MRI.
getType(ValReg);
2991 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2997 .addReg(ValReg, {}, SubReg)
3004 if (RB.
getID() == AArch64::FPRRegBankID) {
3007 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3017 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3020 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3029 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3031 const unsigned NewOpc =
3033 if (NewOpc ==
I.getOpcode())
3037 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3040 I.setDesc(
TII.get(NewOpc));
3046 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3047 Register CurValReg =
I.getOperand(0).getReg();
3048 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3049 NewInst.cloneMemRefs(
I);
3050 for (
auto &Fn : *AddrModeFns)
3052 I.eraseFromParent();
3056 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3061 if (Opcode == TargetOpcode::G_STORE) {
3063 LoadStore->getOperand(0).getReg(), MRI);
3064 if (CVal && CVal->Value == 0) {
3066 case AArch64::STRWui:
3067 case AArch64::STRHHui:
3068 case AArch64::STRBBui:
3069 LoadStore->getOperand(0).setReg(AArch64::WZR);
3071 case AArch64::STRXui:
3072 LoadStore->getOperand(0).setReg(AArch64::XZR);
3078 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3079 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3091 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3093 .
addImm(AArch64::sub_32);
3102 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3103 case TargetOpcode::G_INDEXED_SEXTLOAD:
3104 return selectIndexedExtLoad(
I, MRI);
3105 case TargetOpcode::G_INDEXED_LOAD:
3106 return selectIndexedLoad(
I, MRI);
3107 case TargetOpcode::G_INDEXED_STORE:
3110 case TargetOpcode::G_LSHR:
3111 case TargetOpcode::G_ASHR:
3113 return selectVectorAshrLshr(
I, MRI);
3115 case TargetOpcode::G_SHL:
3116 if (Opcode == TargetOpcode::G_SHL &&
3118 return selectVectorSHL(
I, MRI);
3125 Register SrcReg =
I.getOperand(1).getReg();
3126 Register ShiftReg =
I.getOperand(2).getReg();
3127 const LLT ShiftTy = MRI.
getType(ShiftReg);
3128 const LLT SrcTy = MRI.
getType(SrcReg);
3133 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3134 .addReg(ShiftReg, {}, AArch64::sub_32);
3136 I.getOperand(2).setReg(Trunc.getReg(0));
3140 case TargetOpcode::G_OR: {
3147 const Register DefReg =
I.getOperand(0).getReg();
3151 if (NewOpc ==
I.getOpcode())
3154 I.setDesc(
TII.get(NewOpc));
3163 case TargetOpcode::G_PTR_ADD: {
3164 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3165 I.eraseFromParent();
3169 case TargetOpcode::G_SADDE:
3170 case TargetOpcode::G_UADDE:
3171 case TargetOpcode::G_SSUBE:
3172 case TargetOpcode::G_USUBE:
3173 case TargetOpcode::G_SADDO:
3174 case TargetOpcode::G_UADDO:
3175 case TargetOpcode::G_SSUBO:
3176 case TargetOpcode::G_USUBO:
3177 return selectOverflowOp(
I, MRI);
3179 case TargetOpcode::G_PTRMASK: {
3180 Register MaskReg =
I.getOperand(2).getReg();
3186 uint64_t
Mask = *MaskVal;
3187 I.setDesc(
TII.get(AArch64::ANDXri));
3188 I.getOperand(2).ChangeToImmediate(
3194 case TargetOpcode::G_PTRTOINT:
3195 case TargetOpcode::G_TRUNC: {
3196 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3197 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3199 const Register DstReg =
I.getOperand(0).getReg();
3200 const Register SrcReg =
I.getOperand(1).getReg();
3202 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3203 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3207 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3211 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3212 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3216 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3222 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3226 if (DstRC == SrcRC) {
3228 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3232 }
else if (DstRC == &AArch64::GPR32RegClass &&
3233 SrcRC == &AArch64::GPR64RegClass) {
3234 I.getOperand(1).setSubReg(AArch64::sub_32);
3237 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3241 I.setDesc(
TII.get(TargetOpcode::COPY));
3243 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3246 I.setDesc(
TII.get(AArch64::XTNv4i16));
3252 MachineInstr *Extract = emitExtractVectorElt(
3256 I.eraseFromParent();
3261 if (Opcode == TargetOpcode::G_PTRTOINT) {
3262 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3263 I.setDesc(
TII.get(TargetOpcode::COPY));
3271 case TargetOpcode::G_ANYEXT: {
3272 if (selectUSMovFromExtend(
I, MRI))
3275 const Register DstReg =
I.getOperand(0).getReg();
3276 const Register SrcReg =
I.getOperand(1).getReg();
3278 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3279 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3281 <<
", expected: GPR\n");
3285 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3286 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3288 <<
", expected: GPR\n");
3295 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3299 if (DstSize != 64 && DstSize > 32) {
3301 <<
", expected: 32 or 64\n");
3311 .
addImm(AArch64::sub_32);
3312 I.getOperand(1).setReg(ExtSrc);
3317 case TargetOpcode::G_ZEXT:
3318 case TargetOpcode::G_SEXT_INREG:
3319 case TargetOpcode::G_SEXT: {
3320 if (selectUSMovFromExtend(
I, MRI))
3323 unsigned Opcode =
I.getOpcode();
3324 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3325 const Register DefReg =
I.getOperand(0).getReg();
3326 Register SrcReg =
I.getOperand(1).getReg();
3327 const LLT DstTy = MRI.
getType(DefReg);
3328 const LLT SrcTy = MRI.
getType(SrcReg);
3334 if (Opcode == TargetOpcode::G_SEXT_INREG)
3335 SrcSize =
I.getOperand(2).getImm();
3341 AArch64::GPRRegBankID &&
3342 "Unexpected ext regbank");
3353 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3356 if (LoadMI && IsGPR) {
3357 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3358 unsigned BytesLoaded = MemOp->getSize().getValue();
3365 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3368 const Register ZReg = AArch64::WZR;
3369 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3372 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3373 .addUse(SubregToRegSrc)
3374 .
addImm(AArch64::sub_32);
3378 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3388 I.eraseFromParent();
3393 if (DstSize == 64) {
3394 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3402 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3403 {&AArch64::GPR64RegClass}, {})
3409 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3413 }
else if (DstSize <= 32) {
3414 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3423 I.eraseFromParent();
3427 case TargetOpcode::G_FREEZE:
3430 case TargetOpcode::G_INTTOPTR:
3435 case TargetOpcode::G_BITCAST:
3443 case TargetOpcode::G_SELECT: {
3445 const Register CondReg = Sel.getCondReg();
3447 const Register FReg = Sel.getFalseReg();
3449 if (tryOptSelect(Sel))
3455 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3458 if (!emitSelect(Sel.getReg(0), TReg, FReg,
AArch64CC::NE, MIB))
3460 Sel.eraseFromParent();
3463 case TargetOpcode::G_ICMP: {
3473 auto &PredOp =
I.getOperand(1);
3474 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3478 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3479 AArch64::WZR, InvCC, MIB);
3480 I.eraseFromParent();
3484 case TargetOpcode::G_FCMP: {
3487 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3489 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3491 I.eraseFromParent();
3494 case TargetOpcode::G_VASTART:
3496 : selectVaStartAAPCS(
I, MF, MRI);
3497 case TargetOpcode::G_INTRINSIC:
3498 return selectIntrinsic(
I, MRI);
3499 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3500 return selectIntrinsicWithSideEffects(
I, MRI);
3501 case TargetOpcode::G_IMPLICIT_DEF: {
3502 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3503 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3504 const Register DstReg =
I.getOperand(0).getReg();
3505 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3506 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3510 case TargetOpcode::G_BLOCK_ADDR: {
3511 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3512 if (std::optional<uint16_t> BADisc =
3514 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3515 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3524 AArch64::GPR64RegClass, MRI);
3525 I.eraseFromParent();
3529 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3530 I.eraseFromParent();
3533 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3534 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3535 I.getOperand(0).getReg())
3539 I.getOperand(1).getBlockAddress(), 0,
3541 I.eraseFromParent();
3546 case AArch64::G_DUP: {
3553 AArch64::GPRRegBankID)
3555 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3557 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3559 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3561 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3563 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3569 case TargetOpcode::G_BUILD_VECTOR:
3570 return selectBuildVector(
I, MRI);
3571 case TargetOpcode::G_MERGE_VALUES:
3573 case TargetOpcode::G_UNMERGE_VALUES:
3575 case TargetOpcode::G_SHUFFLE_VECTOR:
3576 return selectShuffleVector(
I, MRI);
3577 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3578 return selectExtractElt(
I, MRI);
3579 case TargetOpcode::G_CONCAT_VECTORS:
3580 return selectConcatVectors(
I, MRI);
3581 case TargetOpcode::G_JUMP_TABLE:
3582 return selectJumpTable(
I, MRI);
3583 case TargetOpcode::G_MEMCPY:
3584 case TargetOpcode::G_MEMCPY_INLINE:
3585 case TargetOpcode::G_MEMMOVE:
3586 case TargetOpcode::G_MEMSET:
3587 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3588 return selectMOPS(
I, MRI);
3594bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3595 MachineIRBuilderState OldMIBState = MIB.
getState();
3601bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3602 MachineRegisterInfo &MRI) {
3605 case TargetOpcode::G_MEMCPY:
3606 case TargetOpcode::G_MEMCPY_INLINE:
3607 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3609 case TargetOpcode::G_MEMMOVE:
3610 Mopcode = AArch64::MOPSMemoryMovePseudo;
3612 case TargetOpcode::G_MEMSET:
3614 Mopcode = AArch64::MOPSMemorySetPseudo;
3627 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3628 const auto &SrcValRegClass =
3629 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3647 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3648 {DstPtrCopy, SizeCopy, SrcValCopy});
3651 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3652 {DstPtrCopy, SrcValCopy, SizeCopy});
3659bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3660 MachineRegisterInfo &MRI) {
3661 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3662 Register JTAddr =
I.getOperand(0).getReg();
3663 unsigned JTI =
I.getOperand(1).getIndex();
3666 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3678 "jump table hardening only supported on MachO/ELF");
3686 I.eraseFromParent();
3693 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3694 {TargetReg, ScratchReg}, {JTAddr,
Index})
3695 .addJumpTableIndex(JTI);
3697 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3698 {
static_cast<int64_t
>(JTI)});
3700 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3701 I.eraseFromParent();
3706bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3707 MachineRegisterInfo &MRI) {
3708 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3709 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3711 Register DstReg =
I.getOperand(0).getReg();
3712 unsigned JTI =
I.getOperand(1).getIndex();
3715 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3718 I.eraseFromParent();
3723bool AArch64InstructionSelector::selectTLSGlobalValue(
3724 MachineInstr &
I, MachineRegisterInfo &MRI) {
3727 MachineFunction &MF = *
I.getParent()->getParent();
3730 const auto &GlobalOp =
I.getOperand(1);
3731 assert(GlobalOp.getOffset() == 0 &&
3732 "Shouldn't have an offset on TLS globals!");
3733 const GlobalValue &GV = *GlobalOp.getGlobal();
3736 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3739 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3740 {LoadGOT.getReg(0)})
3751 assert(Opcode == AArch64::BLR);
3752 Opcode = AArch64::BLRAAZ;
3756 .addUse(AArch64::X0, RegState::Implicit)
3757 .
addDef(AArch64::X0, RegState::Implicit)
3763 I.eraseFromParent();
3767MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3768 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3769 MachineIRBuilder &MIRBuilder)
const {
3770 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3772 auto BuildFn = [&](
unsigned SubregIndex) {
3776 .addImm(SubregIndex);
3784 return BuildFn(AArch64::bsub);
3786 return BuildFn(AArch64::hsub);
3788 return BuildFn(AArch64::ssub);
3790 return BuildFn(AArch64::dsub);
3797AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3798 MachineIRBuilder &MIB,
3799 MachineRegisterInfo &MRI)
const {
3800 LLT DstTy = MRI.
getType(DstReg);
3801 const TargetRegisterClass *RC =
3802 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3803 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3807 unsigned SubReg = 0;
3810 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3816 .addReg(SrcReg, {}, SubReg);
3821bool AArch64InstructionSelector::selectMergeValues(
3822 MachineInstr &
I, MachineRegisterInfo &MRI) {
3823 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3824 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3825 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3827 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3829 if (
I.getNumOperands() != 3)
3836 Register DstReg =
I.getOperand(0).getReg();
3837 Register Src1Reg =
I.getOperand(1).getReg();
3838 Register Src2Reg =
I.getOperand(2).getReg();
3839 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3840 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3844 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3845 Src2Reg, 1, RB, MIB);
3850 I.eraseFromParent();
3854 if (RB.
getID() != AArch64::GPRRegBankID)
3860 auto *DstRC = &AArch64::GPR64RegClass;
3862 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3863 TII.get(TargetOpcode::SUBREG_TO_REG))
3865 .
addUse(
I.getOperand(1).getReg())
3866 .
addImm(AArch64::sub_32);
3869 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3870 TII.get(TargetOpcode::SUBREG_TO_REG))
3872 .
addUse(
I.getOperand(2).getReg())
3873 .
addImm(AArch64::sub_32);
3875 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3876 .
addDef(
I.getOperand(0).getReg())
3884 I.eraseFromParent();
3889 const unsigned EltSize) {
3894 CopyOpc = AArch64::DUPi8;
3895 ExtractSubReg = AArch64::bsub;
3898 CopyOpc = AArch64::DUPi16;
3899 ExtractSubReg = AArch64::hsub;
3902 CopyOpc = AArch64::DUPi32;
3903 ExtractSubReg = AArch64::ssub;
3906 CopyOpc = AArch64::DUPi64;
3907 ExtractSubReg = AArch64::dsub;
3911 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3917MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3918 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3919 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3920 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3921 unsigned CopyOpc = 0;
3922 unsigned ExtractSubReg = 0;
3925 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3929 const TargetRegisterClass *DstRC =
3930 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3932 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3936 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3937 const LLT &VecTy = MRI.
getType(VecReg);
3938 const TargetRegisterClass *VecRC =
3939 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3941 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3951 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3952 .addReg(VecReg, {}, ExtractSubReg);
3961 MachineInstr *ScalarToVector = emitScalarToVector(
3962 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3963 if (!ScalarToVector)
3968 MachineInstr *LaneCopyMI =
3969 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3977bool AArch64InstructionSelector::selectExtractElt(
3978 MachineInstr &
I, MachineRegisterInfo &MRI) {
3979 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3980 "unexpected opcode!");
3981 Register DstReg =
I.getOperand(0).getReg();
3982 const LLT NarrowTy = MRI.
getType(DstReg);
3983 const Register SrcReg =
I.getOperand(1).getReg();
3984 const LLT WideTy = MRI.
getType(SrcReg);
3987 "source register size too small!");
3988 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
3991 MachineOperand &LaneIdxOp =
I.getOperand(2);
3992 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4003 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4006 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4007 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4012 I.eraseFromParent();
4016bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4017 MachineInstr &
I, MachineRegisterInfo &MRI) {
4018 unsigned NumElts =
I.getNumOperands() - 1;
4019 Register SrcReg =
I.getOperand(NumElts).getReg();
4020 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4021 const LLT SrcTy = MRI.
getType(SrcReg);
4023 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4025 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4031 const RegisterBank &DstRB =
4035 MachineInstr *Extract =
4036 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4040 I.eraseFromParent();
4044bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4045 MachineRegisterInfo &MRI) {
4046 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4047 "unexpected opcode");
4051 AArch64::FPRRegBankID ||
4053 AArch64::FPRRegBankID) {
4054 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4055 "currently unsupported.\n");
4061 unsigned NumElts =
I.getNumOperands() - 1;
4062 Register SrcReg =
I.getOperand(NumElts).getReg();
4063 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4064 const LLT WideTy = MRI.
getType(SrcReg);
4067 "source register size too small!");
4070 return selectSplitVectorUnmerge(
I, MRI);
4074 unsigned CopyOpc = 0;
4075 unsigned ExtractSubReg = 0;
4086 unsigned NumInsertRegs = NumElts - 1;
4099 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4101 unsigned SubReg = 0;
4104 assert(Found &&
"expected to find last operand's subeg idx");
4105 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4107 MachineInstr &ImpDefMI =
4108 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4113 MachineInstr &InsMI =
4115 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4132 Register CopyTo =
I.getOperand(0).getReg();
4133 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4134 .addReg(InsertRegs[0], {}, ExtractSubReg);
4138 unsigned LaneIdx = 1;
4139 for (
Register InsReg : InsertRegs) {
4140 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4141 MachineInstr &CopyInst =
4152 const TargetRegisterClass *RC =
4160 I.eraseFromParent();
4164bool AArch64InstructionSelector::selectConcatVectors(
4165 MachineInstr &
I, MachineRegisterInfo &MRI) {
4166 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4167 "Unexpected opcode");
4168 Register Dst =
I.getOperand(0).getReg();
4169 Register Op1 =
I.getOperand(1).getReg();
4170 Register Op2 =
I.getOperand(2).getReg();
4171 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4174 I.eraseFromParent();
4179AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4180 MachineFunction &MF)
const {
4188MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4189 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4190 const TargetRegisterClass *RC;
4196 RC = &AArch64::FPR128RegClass;
4197 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4200 RC = &AArch64::FPR64RegClass;
4201 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4204 RC = &AArch64::FPR32RegClass;
4205 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4208 RC = &AArch64::FPR16RegClass;
4209 Opc = AArch64::LDRHui;
4212 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4217 MachineInstr *LoadMI =
nullptr;
4218 auto &MF = MIRBuilder.
getMF();
4219 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4220 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4222 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4225 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4229 .addConstantPoolIndex(
4245static std::pair<unsigned, unsigned>
4247 unsigned Opc, SubregIdx;
4248 if (RB.
getID() == AArch64::GPRRegBankID) {
4250 Opc = AArch64::INSvi8gpr;
4251 SubregIdx = AArch64::bsub;
4252 }
else if (EltSize == 16) {
4253 Opc = AArch64::INSvi16gpr;
4254 SubregIdx = AArch64::ssub;
4255 }
else if (EltSize == 32) {
4256 Opc = AArch64::INSvi32gpr;
4257 SubregIdx = AArch64::ssub;
4258 }
else if (EltSize == 64) {
4259 Opc = AArch64::INSvi64gpr;
4260 SubregIdx = AArch64::dsub;
4266 Opc = AArch64::INSvi8lane;
4267 SubregIdx = AArch64::bsub;
4268 }
else if (EltSize == 16) {
4269 Opc = AArch64::INSvi16lane;
4270 SubregIdx = AArch64::hsub;
4271 }
else if (EltSize == 32) {
4272 Opc = AArch64::INSvi32lane;
4273 SubregIdx = AArch64::ssub;
4274 }
else if (EltSize == 64) {
4275 Opc = AArch64::INSvi64lane;
4276 SubregIdx = AArch64::dsub;
4281 return std::make_pair(
Opc, SubregIdx);
4284MachineInstr *AArch64InstructionSelector::emitInstr(
4285 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4286 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4287 const ComplexRendererFns &RenderFns)
const {
4288 assert(Opcode &&
"Expected an opcode?");
4290 "Function should only be used to produce selected instructions!");
4291 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4293 for (
auto &Fn : *RenderFns)
4299MachineInstr *AArch64InstructionSelector::emitAddSub(
4300 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4302 MachineIRBuilder &MIRBuilder)
const {
4304 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4308 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4309 bool Is32Bit =
Size == 32;
4312 if (
auto Fns = selectArithImmed(
RHS))
4313 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4317 if (
auto Fns = selectNegArithImmed(
RHS))
4318 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4322 if (
auto Fns = selectArithExtendedRegister(
RHS))
4323 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4327 if (
auto Fns = selectShiftedRegister(
RHS))
4328 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4330 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4335AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4336 MachineOperand &
RHS,
4337 MachineIRBuilder &MIRBuilder)
const {
4338 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4339 {{AArch64::ADDXri, AArch64::ADDWri},
4340 {AArch64::ADDXrs, AArch64::ADDWrs},
4341 {AArch64::ADDXrr, AArch64::ADDWrr},
4342 {AArch64::SUBXri, AArch64::SUBWri},
4343 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4344 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4348AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4349 MachineOperand &
RHS,
4350 MachineIRBuilder &MIRBuilder)
const {
4351 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4352 {{AArch64::ADDSXri, AArch64::ADDSWri},
4353 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4354 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4355 {AArch64::SUBSXri, AArch64::SUBSWri},
4356 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4357 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4361AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4362 MachineOperand &
RHS,
4363 MachineIRBuilder &MIRBuilder)
const {
4364 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4365 {{AArch64::SUBSXri, AArch64::SUBSWri},
4366 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4367 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4368 {AArch64::ADDSXri, AArch64::ADDSWri},
4369 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4370 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4374AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4375 MachineOperand &
RHS,
4376 MachineIRBuilder &MIRBuilder)
const {
4377 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4378 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4380 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4381 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4385AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4386 MachineOperand &
RHS,
4387 MachineIRBuilder &MIRBuilder)
const {
4388 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4389 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4391 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4392 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4396AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4397 MachineIRBuilder &MIRBuilder)
const {
4400 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4405AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4406 MachineIRBuilder &MIRBuilder)
const {
4409 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4414AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4415 MachineIRBuilder &MIRBuilder)
const {
4416 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4420 bool Is32Bit = (
RegSize == 32);
4421 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4422 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4423 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4427 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4430 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4437 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4438 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4439 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4442MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4443 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4444 MachineIRBuilder &MIRBuilder)
const {
4445 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4452 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4454 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4456 return emitCMP(
LHS,
RHS, MIRBuilder);
4459MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4461 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4465 "Expected a 32-bit scalar register?");
4467 const Register ZReg = AArch64::WZR;
4472 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4474 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4478 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4479 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4480 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4485MachineInstr *AArch64InstructionSelector::emitFPCompare(
4487 std::optional<CmpInst::Predicate> Pred)
const {
4488 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4493 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4504 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4508 ShouldUseImm =
true;
4512 unsigned CmpOpcTbl[2][3] = {
4513 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4514 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4516 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4528MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4530 MachineIRBuilder &MIRBuilder)
const {
4537 const LLT Op1Ty = MRI.
getType(Op1);
4538 const LLT Op2Ty = MRI.
getType(Op2);
4540 if (Op1Ty != Op2Ty) {
4541 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4544 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4547 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4558 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4559 const TargetRegisterClass *DstRC =
4562 MachineInstr *WidenedOp1 =
4563 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4564 MachineInstr *WidenedOp2 =
4565 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4566 if (!WidenedOp1 || !WidenedOp2) {
4567 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4572 unsigned InsertOpc, InsSubRegIdx;
4573 std::tie(InsertOpc, InsSubRegIdx) =
4591 MachineIRBuilder &MIRBuilder)
const {
4592 auto &MRI = *MIRBuilder.
getMRI();
4598 Size =
TRI.getRegSizeInBits(*RC);
4602 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4603 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4604 unsigned Opc = OpcTable[
Size == 64];
4605 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4610MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4612 MachineRegisterInfo *MRI = MIB.
getMRI();
4613 unsigned Opcode =
I.getOpcode();
4617 bool NeedsNegatedCarry =
4618 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4627 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4628 if (SrcMI ==
I.getPrevNode()) {
4630 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4631 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4632 CarrySrcMI->isUnsigned() &&
4633 CarrySrcMI->getCarryOutReg() == CarryReg &&
4634 selectAndRestoreState(*SrcMI))
4641 if (NeedsNegatedCarry) {
4644 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4648 auto Fns = select12BitValueWithLeftShift(1);
4649 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4652bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4653 MachineRegisterInfo &MRI) {
4658 emitCarryIn(
I, CarryInMI->getCarryInReg());
4662 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4663 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4665 Register CarryOutReg = CarryMI.getCarryOutReg();
4674 emitCSINC(CarryOutReg, ZReg, ZReg,
4675 getInvertedCondCode(OpAndCC.second), MIB);
4678 I.eraseFromParent();
4682std::pair<MachineInstr *, AArch64CC::CondCode>
4683AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4684 MachineOperand &
LHS,
4685 MachineOperand &
RHS,
4686 MachineIRBuilder &MIRBuilder)
const {
4690 case TargetOpcode::G_SADDO:
4692 case TargetOpcode::G_UADDO:
4694 case TargetOpcode::G_SSUBO:
4696 case TargetOpcode::G_USUBO:
4698 case TargetOpcode::G_SADDE:
4700 case TargetOpcode::G_UADDE:
4702 case TargetOpcode::G_SSUBE:
4704 case TargetOpcode::G_USUBE:
4725 unsigned Depth = 0) {
4732 MustBeFirst =
false;
4738 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4739 bool IsOR = Opcode == TargetOpcode::G_OR;
4751 if (MustBeFirstL && MustBeFirstR)
4757 if (!CanNegateL && !CanNegateR)
4761 CanNegate = WillNegate && CanNegateL && CanNegateR;
4764 MustBeFirst = !CanNegate;
4766 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4769 MustBeFirst = MustBeFirstL || MustBeFirstR;
4776MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4779 MachineIRBuilder &MIB)
const {
4780 auto &MRI = *MIB.
getMRI();
4783 std::optional<ValueAndVReg>
C;
4787 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4788 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4789 else if (
C->Value.ule(31))
4790 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4792 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4798 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4799 CCmpOpc = AArch64::FCCMPHrr;
4802 CCmpOpc = AArch64::FCCMPSrr;
4805 CCmpOpc = AArch64::FCCMPDrr;
4815 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4816 CCmp.
addImm(
C->Value.getZExtValue());
4817 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4818 CCmp.
addImm(
C->Value.abs().getZExtValue());
4826MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4830 auto &MRI = *MIB.
getMRI();
4848 MachineInstr *ExtraCmp;
4850 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4862 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4863 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4864 Cmp->getOperand(3).getReg(), MIB);
4871 bool IsOR = Opcode == TargetOpcode::G_OR;
4877 assert(ValidL &&
"Valid conjunction/disjunction tree");
4884 assert(ValidR &&
"Valid conjunction/disjunction tree");
4889 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4898 bool NegateAfterAll;
4899 if (Opcode == TargetOpcode::G_OR) {
4902 assert(CanNegateR &&
"at least one side must be negatable");
4903 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4907 NegateAfterR =
true;
4910 NegateR = CanNegateR;
4911 NegateAfterR = !CanNegateR;
4914 NegateAfterAll = !Negate;
4916 assert(Opcode == TargetOpcode::G_AND &&
4917 "Valid conjunction/disjunction tree");
4918 assert(!Negate &&
"Valid conjunction/disjunction tree");
4922 NegateAfterR =
false;
4923 NegateAfterAll =
false;
4928 MachineInstr *CmpR =
4939MachineInstr *AArch64InstructionSelector::emitConjunction(
4941 bool DummyCanNegate;
4942 bool DummyMustBeFirst;
4949bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4950 MachineInstr &CondMI) {
4961bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4962 MachineRegisterInfo &MRI = *MIB.
getMRI();
4981 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
4990 if (UI.getOpcode() != TargetOpcode::G_SELECT)
4996 unsigned CondOpc = CondDef->
getOpcode();
4997 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
4998 if (tryOptSelectConjunction(
I, *CondDef))
5004 if (CondOpc == TargetOpcode::G_ICMP) {
5033 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5034 I.getOperand(3).getReg(), CondCode, MIB);
5035 I.eraseFromParent();
5039MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5040 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5041 MachineIRBuilder &MIRBuilder)
const {
5043 "Unexpected MachineOperand");
5044 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5067 if (
isCMN(RHSDef,
P, MRI))
5082 if (
isCMN(LHSDef,
P, MRI)) {
5099 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5102 if (!ValAndVReg || ValAndVReg->Value != 0)
5112bool AArch64InstructionSelector::selectShuffleVector(
5113 MachineInstr &
I, MachineRegisterInfo &MRI) {
5114 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5115 Register Src1Reg =
I.getOperand(1).getReg();
5116 Register Src2Reg =
I.getOperand(2).getReg();
5117 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5126 for (
int Val : Mask) {
5129 Val = Val < 0 ? 0 : Val;
5130 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5148 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5155 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5159 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5164 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5165 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5167 I.eraseFromParent();
5175 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5178 I.eraseFromParent();
5182MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5184 unsigned LaneIdx,
const RegisterBank &RB,
5185 MachineIRBuilder &MIRBuilder)
const {
5186 MachineInstr *InsElt =
nullptr;
5187 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5188 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5197 if (RB.
getID() == AArch64::FPRRegBankID) {
5198 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5201 .
addUse(InsSub->getOperand(0).getReg())
5213bool AArch64InstructionSelector::selectUSMovFromExtend(
5214 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5215 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5216 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5217 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5219 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5220 const Register DefReg =
MI.getOperand(0).getReg();
5221 const LLT DstTy = MRI.
getType(DefReg);
5224 if (DstSize != 32 && DstSize != 64)
5227 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5228 MI.getOperand(1).getReg(), MRI);
5234 const LLT VecTy = MRI.
getType(Src0);
5239 const MachineInstr *ScalarToVector = emitScalarToVector(
5240 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5241 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5247 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5249 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5251 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5253 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5255 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5263 MachineInstr *ExtI =
nullptr;
5264 if (DstSize == 64 && !IsSigned) {
5266 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5267 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5269 .
addImm(AArch64::sub_32);
5272 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5275 MI.eraseFromParent();
5279MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5280 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5282 if (DstSize == 128) {
5283 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5285 Op = AArch64::MOVIv16b_ns;
5287 Op = AArch64::MOVIv8b_ns;
5290 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5294 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5301MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5302 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5306 if (DstSize == 128) {
5307 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5309 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5311 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5314 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5331MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5332 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5336 if (DstSize == 128) {
5337 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5339 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5341 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5344 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5367MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5368 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5371 if (DstSize == 128) {
5372 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5374 Op = AArch64::MOVIv2d_ns;
5376 Op = AArch64::MOVID;
5379 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5382 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5389MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5390 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5394 if (DstSize == 128) {
5395 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5397 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5399 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5402 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5419MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5420 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5423 bool IsWide =
false;
5424 if (DstSize == 128) {
5425 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5427 Op = AArch64::FMOVv4f32_ns;
5430 Op = AArch64::FMOVv2f32_ns;
5433 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5439 Op = AArch64::FMOVv2f64_ns;
5443 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5448bool AArch64InstructionSelector::selectIndexedExtLoad(
5449 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5452 Register WriteBack = ExtLd.getWritebackReg();
5457 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5458 bool IsPre = ExtLd.isPre();
5460 unsigned InsertIntoSubReg = 0;
5466 if ((IsSExt && IsFPR) || Ty.
isVector())
5474 if (MemSizeBits == 8) {
5477 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5479 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5480 NewLdDstTy = IsDst64 ? s64 : s32;
5482 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5483 InsertIntoSubReg = AArch64::bsub;
5486 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5487 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5490 }
else if (MemSizeBits == 16) {
5493 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5495 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5496 NewLdDstTy = IsDst64 ? s64 : s32;
5498 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5499 InsertIntoSubReg = AArch64::hsub;
5502 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5503 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5506 }
else if (MemSizeBits == 32) {
5508 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5511 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5512 InsertIntoSubReg = AArch64::ssub;
5515 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5516 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5528 .addImm(Cst->getSExtValue());
5533 if (InsertIntoSubReg) {
5535 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5536 .addUse(LdMI.getReg(1))
5537 .
addImm(InsertIntoSubReg);
5540 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5547 MI.eraseFromParent();
5552bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5553 MachineRegisterInfo &MRI) {
5556 Register WriteBack = Ld.getWritebackReg();
5560 "Unexpected type for indexed load");
5561 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5564 return selectIndexedExtLoad(
MI, MRI);
5568 static constexpr unsigned GPROpcodes[] = {
5569 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5571 static constexpr unsigned FPROpcodes[] = {
5572 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5575 ? FPROpcodes[
Log2_32(MemSize)]
5576 : GPROpcodes[
Log2_32(MemSize)];
5579 static constexpr unsigned GPROpcodes[] = {
5580 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5582 static constexpr unsigned FPROpcodes[] = {
5583 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5584 AArch64::LDRDpost, AArch64::LDRQpost};
5586 ? FPROpcodes[
Log2_32(MemSize)]
5587 : GPROpcodes[
Log2_32(MemSize)];
5597 MI.eraseFromParent();
5601bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5602 MachineRegisterInfo &MRI) {
5608 "Unexpected type for indexed store");
5610 LocationSize MemSize =
I.getMMO().getSize();
5611 unsigned MemSizeInBytes = MemSize.
getValue();
5613 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5614 "Unexpected indexed store size");
5615 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5619 static constexpr unsigned GPROpcodes[] = {
5620 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5622 static constexpr unsigned FPROpcodes[] = {
5623 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5627 Opc = FPROpcodes[MemSizeLog2];
5629 Opc = GPROpcodes[MemSizeLog2];
5631 static constexpr unsigned GPROpcodes[] = {
5632 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5634 static constexpr unsigned FPROpcodes[] = {
5635 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5636 AArch64::STRDpost, AArch64::STRQpost};
5639 Opc = FPROpcodes[MemSizeLog2];
5641 Opc = GPROpcodes[MemSizeLog2];
5649 Str.cloneMemRefs(
I);
5651 I.eraseFromParent();
5656AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5657 MachineIRBuilder &MIRBuilder,
5658 MachineRegisterInfo &MRI) {
5661 assert((DstSize == 64 || DstSize == 128) &&
5662 "Unexpected vector constant size");
5665 if (DstSize == 128) {
5667 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5672 if (DstSize == 64) {
5675 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5678 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5685 APInt SplatValueAsInt =
5688 : SplatValue->getUniqueInteger();
5691 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5692 MachineInstr *NewOp;
5716 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5720 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5721 unsigned NegOpc) -> MachineInstr * {
5724 APInt NegBits(DstSize, 0);
5725 unsigned NumElts = DstSize / NumBits;
5726 for (
unsigned i = 0; i < NumElts; i++)
5727 NegBits |= Neg << (NumBits * i);
5728 NegBits = DefBits ^ NegBits;
5732 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5734 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5736 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5741 if ((R = TryWithFNeg(DefBits, 32,
5742 DstSize == 64 ? AArch64::FNEGv2f32
5743 : AArch64::FNEGv4f32)) ||
5744 (R = TryWithFNeg(DefBits, 64,
5745 DstSize == 64 ? AArch64::FNEGDr
5746 : AArch64::FNEGv2f64)) ||
5747 (STI.hasFullFP16() &&
5748 (R = TryWithFNeg(DefBits, 16,
5749 DstSize == 64 ? AArch64::FNEGv4f16
5750 : AArch64::FNEGv8f16))))
5756 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5760 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5762 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5766bool AArch64InstructionSelector::tryOptConstantBuildVec(
5767 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5768 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5770 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5776 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5777 Register OpReg =
I.getOperand(Idx).getReg();
5786 std::move(AnyConst->Value)));
5799 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5801 I.eraseFromParent();
5805bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5806 MachineInstr &
I, MachineRegisterInfo &MRI) {
5811 Register Dst =
I.getOperand(0).getReg();
5812 Register EltReg =
I.getOperand(1).getReg();
5813 LLT EltTy = MRI.
getType(EltReg);
5816 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5821 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5825 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5828 const TargetRegisterClass *DstRC =
5829 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5834 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5837 I.eraseFromParent();
5842bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5843 MachineRegisterInfo &MRI) {
5844 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5847 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5848 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5851 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5853 if (tryOptBuildVecToSubregToReg(
I, MRI))
5856 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5858 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5860 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5861 MachineInstr *ScalarToVec =
5863 I.getOperand(1).getReg(), MIB);
5872 MachineInstr *PrevMI = ScalarToVec;
5873 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5876 Register OpReg =
I.getOperand(i).getReg();
5879 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5886 if (DstSize < 128) {
5888 const TargetRegisterClass *RC =
5889 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5892 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5897 unsigned SubReg = 0;
5900 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5901 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5907 Register DstReg =
I.getOperand(0).getReg();
5909 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5910 MachineOperand &RegOp =
I.getOperand(1);
5930 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5931 const TargetRegisterClass *RC =
5932 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5941bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5944 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5946 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5947 auto &MRI = *MIB.
getMRI();
5948 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5951 "Destination must be 64 bits or 128 bits?");
5952 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5953 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5956 Load.cloneMemRefs(
I);
5958 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5959 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5960 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5961 .addReg(SelectedLoadDst, {}, SubReg + Idx);
5970bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5971 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5972 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5974 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5975 auto &MRI = *MIB.
getMRI();
5976 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5979 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5981 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5982 [](
auto MO) { return MO.getReg(); });
5986 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6001 .
addImm(LaneNo->getZExtValue())
6003 Load.cloneMemRefs(
I);
6005 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6006 unsigned SubReg = AArch64::qsub0;
6007 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6008 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6009 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6010 : DstOp(
I.getOperand(Idx).
getReg())},
6012 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6017 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6023void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6026 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6027 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6028 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6031 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6032 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6041bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6042 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6043 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6044 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6048 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6049 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6053 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6063 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6066 .
addImm(LaneNo->getZExtValue())
6073bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6074 MachineInstr &
I, MachineRegisterInfo &MRI) {
6087 case Intrinsic::aarch64_ldxp:
6088 case Intrinsic::aarch64_ldaxp: {
6090 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6091 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6097 case Intrinsic::aarch64_neon_ld1x2: {
6098 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6101 Opc = AArch64::LD1Twov8b;
6103 Opc = AArch64::LD1Twov16b;
6105 Opc = AArch64::LD1Twov4h;
6107 Opc = AArch64::LD1Twov8h;
6109 Opc = AArch64::LD1Twov2s;
6111 Opc = AArch64::LD1Twov4s;
6113 Opc = AArch64::LD1Twov2d;
6114 else if (Ty ==
S64 || Ty == P0)
6115 Opc = AArch64::LD1Twov1d;
6118 selectVectorLoadIntrinsic(
Opc, 2,
I);
6121 case Intrinsic::aarch64_neon_ld1x3: {
6122 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6125 Opc = AArch64::LD1Threev8b;
6127 Opc = AArch64::LD1Threev16b;
6129 Opc = AArch64::LD1Threev4h;
6131 Opc = AArch64::LD1Threev8h;
6133 Opc = AArch64::LD1Threev2s;
6135 Opc = AArch64::LD1Threev4s;
6137 Opc = AArch64::LD1Threev2d;
6138 else if (Ty ==
S64 || Ty == P0)
6139 Opc = AArch64::LD1Threev1d;
6142 selectVectorLoadIntrinsic(
Opc, 3,
I);
6145 case Intrinsic::aarch64_neon_ld1x4: {
6146 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6149 Opc = AArch64::LD1Fourv8b;
6151 Opc = AArch64::LD1Fourv16b;
6153 Opc = AArch64::LD1Fourv4h;
6155 Opc = AArch64::LD1Fourv8h;
6157 Opc = AArch64::LD1Fourv2s;
6159 Opc = AArch64::LD1Fourv4s;
6161 Opc = AArch64::LD1Fourv2d;
6162 else if (Ty ==
S64 || Ty == P0)
6163 Opc = AArch64::LD1Fourv1d;
6166 selectVectorLoadIntrinsic(
Opc, 4,
I);
6169 case Intrinsic::aarch64_neon_ld2: {
6170 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6173 Opc = AArch64::LD2Twov8b;
6175 Opc = AArch64::LD2Twov16b;
6177 Opc = AArch64::LD2Twov4h;
6179 Opc = AArch64::LD2Twov8h;
6181 Opc = AArch64::LD2Twov2s;
6183 Opc = AArch64::LD2Twov4s;
6185 Opc = AArch64::LD2Twov2d;
6186 else if (Ty ==
S64 || Ty == P0)
6187 Opc = AArch64::LD1Twov1d;
6190 selectVectorLoadIntrinsic(
Opc, 2,
I);
6193 case Intrinsic::aarch64_neon_ld2lane: {
6194 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6197 Opc = AArch64::LD2i8;
6199 Opc = AArch64::LD2i16;
6201 Opc = AArch64::LD2i32;
6204 Opc = AArch64::LD2i64;
6207 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6211 case Intrinsic::aarch64_neon_ld2r: {
6212 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6215 Opc = AArch64::LD2Rv8b;
6217 Opc = AArch64::LD2Rv16b;
6219 Opc = AArch64::LD2Rv4h;
6221 Opc = AArch64::LD2Rv8h;
6223 Opc = AArch64::LD2Rv2s;
6225 Opc = AArch64::LD2Rv4s;
6227 Opc = AArch64::LD2Rv2d;
6228 else if (Ty ==
S64 || Ty == P0)
6229 Opc = AArch64::LD2Rv1d;
6232 selectVectorLoadIntrinsic(
Opc, 2,
I);
6235 case Intrinsic::aarch64_neon_ld3: {
6236 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6239 Opc = AArch64::LD3Threev8b;
6241 Opc = AArch64::LD3Threev16b;
6243 Opc = AArch64::LD3Threev4h;
6245 Opc = AArch64::LD3Threev8h;
6247 Opc = AArch64::LD3Threev2s;
6249 Opc = AArch64::LD3Threev4s;
6251 Opc = AArch64::LD3Threev2d;
6252 else if (Ty ==
S64 || Ty == P0)
6253 Opc = AArch64::LD1Threev1d;
6256 selectVectorLoadIntrinsic(
Opc, 3,
I);
6259 case Intrinsic::aarch64_neon_ld3lane: {
6260 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6263 Opc = AArch64::LD3i8;
6265 Opc = AArch64::LD3i16;
6267 Opc = AArch64::LD3i32;
6270 Opc = AArch64::LD3i64;
6273 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6277 case Intrinsic::aarch64_neon_ld3r: {
6278 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6281 Opc = AArch64::LD3Rv8b;
6283 Opc = AArch64::LD3Rv16b;
6285 Opc = AArch64::LD3Rv4h;
6287 Opc = AArch64::LD3Rv8h;
6289 Opc = AArch64::LD3Rv2s;
6291 Opc = AArch64::LD3Rv4s;
6293 Opc = AArch64::LD3Rv2d;
6294 else if (Ty ==
S64 || Ty == P0)
6295 Opc = AArch64::LD3Rv1d;
6298 selectVectorLoadIntrinsic(
Opc, 3,
I);
6301 case Intrinsic::aarch64_neon_ld4: {
6302 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6305 Opc = AArch64::LD4Fourv8b;
6307 Opc = AArch64::LD4Fourv16b;
6309 Opc = AArch64::LD4Fourv4h;
6311 Opc = AArch64::LD4Fourv8h;
6313 Opc = AArch64::LD4Fourv2s;
6315 Opc = AArch64::LD4Fourv4s;
6317 Opc = AArch64::LD4Fourv2d;
6318 else if (Ty ==
S64 || Ty == P0)
6319 Opc = AArch64::LD1Fourv1d;
6322 selectVectorLoadIntrinsic(
Opc, 4,
I);
6325 case Intrinsic::aarch64_neon_ld4lane: {
6326 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6329 Opc = AArch64::LD4i8;
6331 Opc = AArch64::LD4i16;
6333 Opc = AArch64::LD4i32;
6336 Opc = AArch64::LD4i64;
6339 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6343 case Intrinsic::aarch64_neon_ld4r: {
6344 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6347 Opc = AArch64::LD4Rv8b;
6349 Opc = AArch64::LD4Rv16b;
6351 Opc = AArch64::LD4Rv4h;
6353 Opc = AArch64::LD4Rv8h;
6355 Opc = AArch64::LD4Rv2s;
6357 Opc = AArch64::LD4Rv4s;
6359 Opc = AArch64::LD4Rv2d;
6360 else if (Ty ==
S64 || Ty == P0)
6361 Opc = AArch64::LD4Rv1d;
6364 selectVectorLoadIntrinsic(
Opc, 4,
I);
6367 case Intrinsic::aarch64_neon_st1x2: {
6368 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6371 Opc = AArch64::ST1Twov8b;
6373 Opc = AArch64::ST1Twov16b;
6375 Opc = AArch64::ST1Twov4h;
6377 Opc = AArch64::ST1Twov8h;
6379 Opc = AArch64::ST1Twov2s;
6381 Opc = AArch64::ST1Twov4s;
6383 Opc = AArch64::ST1Twov2d;
6384 else if (Ty ==
S64 || Ty == P0)
6385 Opc = AArch64::ST1Twov1d;
6388 selectVectorStoreIntrinsic(
I, 2,
Opc);
6391 case Intrinsic::aarch64_neon_st1x3: {
6392 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6395 Opc = AArch64::ST1Threev8b;
6397 Opc = AArch64::ST1Threev16b;
6399 Opc = AArch64::ST1Threev4h;
6401 Opc = AArch64::ST1Threev8h;
6403 Opc = AArch64::ST1Threev2s;
6405 Opc = AArch64::ST1Threev4s;
6407 Opc = AArch64::ST1Threev2d;
6408 else if (Ty ==
S64 || Ty == P0)
6409 Opc = AArch64::ST1Threev1d;
6412 selectVectorStoreIntrinsic(
I, 3,
Opc);
6415 case Intrinsic::aarch64_neon_st1x4: {
6416 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6419 Opc = AArch64::ST1Fourv8b;
6421 Opc = AArch64::ST1Fourv16b;
6423 Opc = AArch64::ST1Fourv4h;
6425 Opc = AArch64::ST1Fourv8h;
6427 Opc = AArch64::ST1Fourv2s;
6429 Opc = AArch64::ST1Fourv4s;
6431 Opc = AArch64::ST1Fourv2d;
6432 else if (Ty ==
S64 || Ty == P0)
6433 Opc = AArch64::ST1Fourv1d;
6436 selectVectorStoreIntrinsic(
I, 4,
Opc);
6439 case Intrinsic::aarch64_neon_st2: {
6440 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6443 Opc = AArch64::ST2Twov8b;
6445 Opc = AArch64::ST2Twov16b;
6447 Opc = AArch64::ST2Twov4h;
6449 Opc = AArch64::ST2Twov8h;
6451 Opc = AArch64::ST2Twov2s;
6453 Opc = AArch64::ST2Twov4s;
6455 Opc = AArch64::ST2Twov2d;
6456 else if (Ty ==
S64 || Ty == P0)
6457 Opc = AArch64::ST1Twov1d;
6460 selectVectorStoreIntrinsic(
I, 2,
Opc);
6463 case Intrinsic::aarch64_neon_st3: {
6464 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6467 Opc = AArch64::ST3Threev8b;
6469 Opc = AArch64::ST3Threev16b;
6471 Opc = AArch64::ST3Threev4h;
6473 Opc = AArch64::ST3Threev8h;
6475 Opc = AArch64::ST3Threev2s;
6477 Opc = AArch64::ST3Threev4s;
6479 Opc = AArch64::ST3Threev2d;
6480 else if (Ty ==
S64 || Ty == P0)
6481 Opc = AArch64::ST1Threev1d;
6484 selectVectorStoreIntrinsic(
I, 3,
Opc);
6487 case Intrinsic::aarch64_neon_st4: {
6488 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6491 Opc = AArch64::ST4Fourv8b;
6493 Opc = AArch64::ST4Fourv16b;
6495 Opc = AArch64::ST4Fourv4h;
6497 Opc = AArch64::ST4Fourv8h;
6499 Opc = AArch64::ST4Fourv2s;
6501 Opc = AArch64::ST4Fourv4s;
6503 Opc = AArch64::ST4Fourv2d;
6504 else if (Ty ==
S64 || Ty == P0)
6505 Opc = AArch64::ST1Fourv1d;
6508 selectVectorStoreIntrinsic(
I, 4,
Opc);
6511 case Intrinsic::aarch64_neon_st2lane: {
6512 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6515 Opc = AArch64::ST2i8;
6517 Opc = AArch64::ST2i16;
6519 Opc = AArch64::ST2i32;
6522 Opc = AArch64::ST2i64;
6525 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6529 case Intrinsic::aarch64_neon_st3lane: {
6530 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6533 Opc = AArch64::ST3i8;
6535 Opc = AArch64::ST3i16;
6537 Opc = AArch64::ST3i32;
6540 Opc = AArch64::ST3i64;
6543 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6547 case Intrinsic::aarch64_neon_st4lane: {
6548 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6551 Opc = AArch64::ST4i8;
6553 Opc = AArch64::ST4i16;
6555 Opc = AArch64::ST4i32;
6558 Opc = AArch64::ST4i64;
6561 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6565 case Intrinsic::aarch64_mops_memset_tag: {
6578 Register DstDef =
I.getOperand(0).getReg();
6580 Register DstUse =
I.getOperand(2).getReg();
6581 Register ValUse =
I.getOperand(3).getReg();
6582 Register SizeUse =
I.getOperand(4).getReg();
6589 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6590 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6595 case Intrinsic::ptrauth_resign_load_relative: {
6596 Register DstReg =
I.getOperand(0).getReg();
6597 Register ValReg =
I.getOperand(2).getReg();
6598 uint64_t AUTKey =
I.getOperand(3).getImm();
6599 Register AUTDisc =
I.getOperand(4).getReg();
6600 uint64_t PACKey =
I.getOperand(5).getImm();
6601 Register PACDisc =
I.getOperand(6).getReg();
6602 int64_t Addend =
I.getOperand(7).getImm();
6605 uint16_t AUTConstDiscC = 0;
6606 std::tie(AUTConstDiscC, AUTAddrDisc) =
6610 uint16_t PACConstDiscC = 0;
6611 std::tie(PACConstDiscC, PACAddrDisc) =
6614 MIB.
buildCopy({AArch64::X16}, {ValReg});
6628 I.eraseFromParent();
6633 I.eraseFromParent();
6637bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6638 MachineRegisterInfo &MRI) {
6644 case Intrinsic::ptrauth_resign: {
6645 Register DstReg =
I.getOperand(0).getReg();
6646 Register ValReg =
I.getOperand(2).getReg();
6647 uint64_t AUTKey =
I.getOperand(3).getImm();
6648 Register AUTDisc =
I.getOperand(4).getReg();
6649 uint64_t PACKey =
I.getOperand(5).getImm();
6650 Register PACDisc =
I.getOperand(6).getReg();
6653 uint16_t AUTConstDiscC = 0;
6654 std::tie(AUTConstDiscC, AUTAddrDisc) =
6658 uint16_t PACConstDiscC = 0;
6659 std::tie(PACConstDiscC, PACAddrDisc) =
6662 MIB.
buildCopy({AArch64::X16}, {ValReg});
6663 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6675 I.eraseFromParent();
6678 case Intrinsic::ptrauth_auth: {
6679 Register DstReg =
I.getOperand(0).getReg();
6680 Register ValReg =
I.getOperand(2).getReg();
6681 uint64_t AUTKey =
I.getOperand(3).getImm();
6682 Register AUTDisc =
I.getOperand(4).getReg();
6685 uint16_t AUTConstDiscC = 0;
6686 std::tie(AUTConstDiscC, AUTAddrDisc) =
6690 MIB.
buildCopy({AArch64::X16}, {ValReg});
6691 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6712 I.eraseFromParent();
6715 case Intrinsic::frameaddress:
6716 case Intrinsic::returnaddress: {
6717 MachineFunction &MF = *
I.getParent()->getParent();
6720 unsigned Depth =
I.getOperand(2).getImm();
6721 Register DstReg =
I.getOperand(0).getReg();
6724 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6725 if (!MFReturnAddr) {
6730 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6733 if (STI.hasPAuth()) {
6734 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6741 I.eraseFromParent();
6750 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6752 FrameAddr = NextFrame;
6755 if (IntrinID == Intrinsic::frameaddress)
6760 if (STI.hasPAuth()) {
6762 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6763 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6772 I.eraseFromParent();
6775 case Intrinsic::aarch64_neon_tbl2:
6776 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6778 case Intrinsic::aarch64_neon_tbl3:
6779 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6782 case Intrinsic::aarch64_neon_tbl4:
6783 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6785 case Intrinsic::aarch64_neon_tbx2:
6786 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6788 case Intrinsic::aarch64_neon_tbx3:
6789 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6791 case Intrinsic::aarch64_neon_tbx4:
6792 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6794 case Intrinsic::swift_async_context_addr:
6795 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6802 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6803 I.eraseFromParent();
6838bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6839 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6840 Register DefReg =
I.getOperand(0).getReg();
6841 Register Addr =
I.getOperand(1).getReg();
6842 uint64_t
Key =
I.getOperand(2).getImm();
6843 Register AddrDisc =
I.getOperand(3).getReg();
6844 uint64_t Disc =
I.getOperand(4).getImm();
6854 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6870 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6882 const GlobalValue *GV;
6893 MachineIRBuilder MIB(
I);
6899 "unsupported non-GOT op flags on ptrauth global reference");
6901 "unsupported non-GOT reference to weak ptrauth global");
6904 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6911 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6912 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6913 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6916 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6921 I.eraseFromParent();
6933 "unsupported non-zero offset in weak ptrauth global reference");
6938 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6939 .addGlobalAddress(GV,
Offset)
6944 I.eraseFromParent();
6948void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6949 MachineRegisterInfo &MRI,
6950 unsigned NumVec,
unsigned Opc1,
6951 unsigned Opc2,
bool isExt) {
6952 Register DstReg =
I.getOperand(0).getReg();
6957 for (
unsigned i = 0; i < NumVec; i++)
6958 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6961 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6962 MachineInstrBuilder
Instr;
6969 I.eraseFromParent();
6972InstructionSelector::ComplexRendererFns
6973AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6975 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6976 return std::nullopt;
6977 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6978 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6981InstructionSelector::ComplexRendererFns
6982AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6984 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6985 return std::nullopt;
6986 uint64_t Enc = 31 - *MaybeImmed;
6987 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6990InstructionSelector::ComplexRendererFns
6991AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
6993 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6994 return std::nullopt;
6995 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
6996 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6999InstructionSelector::ComplexRendererFns
7000AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7002 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7003 return std::nullopt;
7004 uint64_t Enc = 63 - *MaybeImmed;
7005 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7013InstructionSelector::ComplexRendererFns
7014AArch64InstructionSelector::select12BitValueWithLeftShift(
7015 uint64_t Immed)
const {
7017 if (Immed >> 12 == 0) {
7019 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7021 Immed = Immed >> 12;
7023 return std::nullopt;
7027 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7028 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7035InstructionSelector::ComplexRendererFns
7036AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7043 if (MaybeImmed == std::nullopt)
7044 return std::nullopt;
7045 return select12BitValueWithLeftShift(*MaybeImmed);
7050InstructionSelector::ComplexRendererFns
7051AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7055 return std::nullopt;
7057 if (MaybeImmed == std::nullopt)
7058 return std::nullopt;
7059 uint64_t Immed = *MaybeImmed;
7065 return std::nullopt;
7071 Immed = ~((uint32_t)Immed) + 1;
7073 Immed = ~Immed + 1ULL;
7075 if (Immed & 0xFFFFFFFFFF000000ULL)
7076 return std::nullopt;
7078 Immed &= 0xFFFFFFULL;
7079 return select12BitValueWithLeftShift(Immed);
7096std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7097 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7098 if (
MI.getOpcode() == AArch64::G_SHL) {
7102 MI.getOperand(2).getReg(), MRI)) {
7103 const APInt ShiftVal = ValAndVeg->Value;
7106 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7109 return std::nullopt;
7117bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7118 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7119 bool IsAddrOperand)
const {
7124 MI.getParent()->getParent()->getFunction().hasOptSize())
7127 if (IsAddrOperand) {
7129 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7133 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7134 MachineInstr *OffsetInst =
7140 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7151 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7154InstructionSelector::ComplexRendererFns
7155AArch64InstructionSelector::selectExtendedSHL(
7156 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7157 unsigned SizeInBytes,
bool WantsExt)
const {
7158 assert(
Base.isReg() &&
"Expected base to be a register operand");
7159 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7164 unsigned OffsetOpc = OffsetInst->
getOpcode();
7165 bool LookedThroughZExt =
false;
7166 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7168 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7169 return std::nullopt;
7173 LookedThroughZExt =
true;
7175 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7176 return std::nullopt;
7179 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7180 if (LegalShiftVal == 0)
7181 return std::nullopt;
7182 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7183 return std::nullopt;
7194 if (OffsetOpc == TargetOpcode::G_SHL)
7195 return std::nullopt;
7201 return std::nullopt;
7206 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7210 if (OffsetOpc == TargetOpcode::G_MUL) {
7212 return std::nullopt;
7218 if ((ImmVal & 0x7) != ImmVal)
7219 return std::nullopt;
7223 if (ImmVal != LegalShiftVal)
7224 return std::nullopt;
7226 unsigned SignExtend = 0;
7230 if (!LookedThroughZExt) {
7232 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7234 return std::nullopt;
7239 return std::nullopt;
7245 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7250 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7251 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7252 [=](MachineInstrBuilder &MIB) {
7255 MIB.addImm(SignExtend);
7268InstructionSelector::ComplexRendererFns
7269AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7270 MachineOperand &Root,
unsigned SizeInBytes)
const {
7272 return std::nullopt;
7287 MachineInstr *PtrAdd =
7289 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7290 return std::nullopt;
7294 MachineInstr *OffsetInst =
7296 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7309InstructionSelector::ComplexRendererFns
7310AArch64InstructionSelector::selectAddrModeRegisterOffset(
7311 MachineOperand &Root)
const {
7316 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7317 return std::nullopt;
7323 return std::nullopt;
7326 return {{[=](MachineInstrBuilder &MIB) {
7329 [=](MachineInstrBuilder &MIB) {
7332 [=](MachineInstrBuilder &MIB) {
7342InstructionSelector::ComplexRendererFns
7343AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7344 unsigned SizeInBytes)
const {
7347 return std::nullopt;
7348 MachineInstr *PtrAdd =
7351 return std::nullopt;
7369 unsigned Scale =
Log2_32(SizeInBytes);
7370 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7374 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7375 ImmOff < (0x1000 << Scale))
7376 return std::nullopt;
7381 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7385 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7391 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7392 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7397 return std::nullopt;
7401 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7407 return selectAddrModeRegisterOffset(Root);
7416InstructionSelector::ComplexRendererFns
7417AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7418 unsigned SizeInBytes)
const {
7421 MachineInstr *PtrAdd =
7423 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7424 return std::nullopt;
7445 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7454 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7455 return std::nullopt;
7459 getExtendTypeForInst(*OffsetInst, MRI,
true);
7461 return std::nullopt;
7464 MachineIRBuilder MIB(*PtrAdd);
7466 AArch64::GPR32RegClass, MIB);
7470 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7471 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7472 [=](MachineInstrBuilder &MIB) {
7473 MIB.addImm(SignExtend);
7483InstructionSelector::ComplexRendererFns
7484AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7485 unsigned Size)
const {
7486 MachineRegisterInfo &MRI =
7490 return std::nullopt;
7492 if (!isBaseWithConstantOffset(Root, MRI))
7493 return std::nullopt;
7497 MachineOperand &OffImm = RootDef->
getOperand(2);
7498 if (!OffImm.
isReg())
7499 return std::nullopt;
7501 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7502 return std::nullopt;
7504 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7506 return std::nullopt;
7509 if (RHSC >= -256 && RHSC < 256) {
7512 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7513 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7516 return std::nullopt;
7519InstructionSelector::ComplexRendererFns
7520AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7522 MachineRegisterInfo &MRI)
const {
7523 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7524 return std::nullopt;
7527 return std::nullopt;
7532 return std::nullopt;
7536 return std::nullopt;
7540 return std::nullopt;
7543 MachineIRBuilder MIRBuilder(RootDef);
7545 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7546 [=](MachineInstrBuilder &MIB) {
7547 MIB.addGlobalAddress(GV,
Offset,
7556InstructionSelector::ComplexRendererFns
7557AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7558 unsigned Size)
const {
7563 return std::nullopt;
7566 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7568 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7569 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7577 MachineInstr *RootParent = Root.
getParent();
7579 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7581 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7586 if (isBaseWithConstantOffset(Root, MRI)) {
7594 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7595 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7597 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7598 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7602 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7603 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7610 if (selectAddrModeUnscaled(Root,
Size))
7611 return std::nullopt;
7614 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7615 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7622 switch (
MI.getOpcode()) {
7625 case TargetOpcode::G_SHL:
7627 case TargetOpcode::G_LSHR:
7629 case TargetOpcode::G_ASHR:
7631 case TargetOpcode::G_ROTR:
7638InstructionSelector::ComplexRendererFns
7639AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7640 bool AllowROR)
const {
7642 return std::nullopt;
7643 MachineRegisterInfo &MRI =
7651 return std::nullopt;
7653 return std::nullopt;
7654 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7655 return std::nullopt;
7658 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7661 return std::nullopt;
7665 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7669 unsigned Val = *Immed & (NumBits - 1);
7672 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7673 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7677 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7678 unsigned Opc =
MI.getOpcode();
7681 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7683 if (
Opc == TargetOpcode::G_SEXT)
7686 Size =
MI.getOperand(2).getImm();
7687 assert(
Size != 64 &&
"Extend from 64 bits?");
7700 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7702 assert(
Size != 64 &&
"Extend from 64 bits?");
7717 if (
Opc != TargetOpcode::G_AND)
7723 uint64_t AndMask = *MaybeAndMask;
7736Register AArch64InstructionSelector::moveScalarRegClass(
7737 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7738 MachineRegisterInfo &MRI = *MIB.
getMRI();
7748 return Copy.getReg(0);
7753InstructionSelector::ComplexRendererFns
7754AArch64InstructionSelector::selectArithExtendedRegister(
7755 MachineOperand &Root)
const {
7757 return std::nullopt;
7758 MachineRegisterInfo &MRI =
7761 uint64_t ShiftVal = 0;
7766 return std::nullopt;
7768 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7769 return std::nullopt;
7772 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7777 return std::nullopt;
7778 ShiftVal = *MaybeShiftVal;
7780 return std::nullopt;
7785 return std::nullopt;
7786 Ext = getExtendTypeForInst(*ExtDef, MRI);
7788 return std::nullopt;
7792 Ext = getExtendTypeForInst(*RootDef, MRI);
7794 return std::nullopt;
7802 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7803 if (isDef32(*ExtInst))
7804 return std::nullopt;
7810 MachineIRBuilder MIB(*RootDef);
7811 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7813 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7814 [=](MachineInstrBuilder &MIB) {
7815 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7819InstructionSelector::ComplexRendererFns
7820AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7822 return std::nullopt;
7823 MachineRegisterInfo &MRI =
7827 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7832 return std::nullopt;
7834 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7837 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7840 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7845 LaneIdx->Value.getSExtValue() == 1) {
7847 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7851 return std::nullopt;
7854InstructionSelector::ComplexRendererFns
7855AArch64InstructionSelector::selectCVTFixedPointVecBase(
7856 const MachineOperand &Root)
const {
7858 return std::nullopt;
7859 const MachineRegisterInfo &MRI =
7864 return std::nullopt;
7865 std::optional<ValueAndVReg> CstVal =
7868 return std::nullopt;
7874 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7877 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7880 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7883 return std::nullopt;
7887 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7889 return std::nullopt;
7892InstructionSelector::ComplexRendererFns
7893AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
7894 return selectCVTFixedPointVecBase(Root);
7897void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
7898 const MachineInstr &
MI,
7903 InstructionSelector::ComplexRendererFns Renderer =
7904 selectCVTFixedPointVecBase(
MI.getOperand(2));
7905 assert((Renderer && Renderer->size() == 1) &&
7906 "Expected selectCVTFixedPointVec to provide a function\n");
7907 (Renderer->front())(MIB);
7910void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7911 const MachineInstr &
MI,
7913 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
7914 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7915 "Expected G_CONSTANT");
7916 std::optional<int64_t> CstVal =
7918 assert(CstVal &&
"Expected constant value");
7922void AArch64InstructionSelector::renderLogicalImm32(
7923 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7924 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7925 "Expected G_CONSTANT");
7926 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7931void AArch64InstructionSelector::renderLogicalImm64(
7932 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7933 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7934 "Expected G_CONSTANT");
7935 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7940void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7941 const MachineInstr &
MI,
7943 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7944 "Expected G_UBSANTRAP");
7945 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7948void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7949 const MachineInstr &
MI,
7951 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7952 "Expected G_FCONSTANT");
7957void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7958 const MachineInstr &
MI,
7960 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7961 "Expected G_FCONSTANT");
7966void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7967 const MachineInstr &
MI,
7969 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7970 "Expected G_FCONSTANT");
7975void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7976 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7977 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7978 "Expected G_FCONSTANT");
7986bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7987 const MachineInstr &
MI,
unsigned NumBytes)
const {
7988 if (!
MI.mayLoadOrStore())
7991 "Expected load/store to have only one mem op!");
7992 return (*
MI.memoperands_begin())->getSize() == NumBytes;
7995bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
7996 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8004 switch (
MI.getOpcode()) {
8007 case TargetOpcode::COPY:
8008 case TargetOpcode::G_BITCAST:
8009 case TargetOpcode::G_TRUNC:
8010 case TargetOpcode::G_PHI:
8020 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8023 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8041 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8046 MO.setReg(Copy.getReg(0));
8051void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8055 for (
auto &BB : MF) {
8056 for (
auto &
MI : BB) {
8057 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8062 for (
auto *
MI : Phis) {
8084 bool HasGPROp =
false, HasFPROp =
false;
8088 const LLT &Ty = MRI.
getType(MO.getReg());
8098 if (RB->
getID() == AArch64::GPRRegBankID)
8104 if (HasGPROp && HasFPROp)
8110InstructionSelector *
8114 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 StringRef getName(Value *V)
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
LLVM_ABI bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
constexpr LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr bool isPointerVector() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr 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 LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
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.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
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.