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());
2225 I.getOperand(1).setReg(
Copy.getReg(0));
2227 getRegClassForTypeOnBank(
2228 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2230 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2231 I.setDesc(
TII.get(AArch64::G_SITOF));
2233 I.setDesc(
TII.get(AArch64::G_UITOF));
2251bool AArch64InstructionSelector::convertPtrAddToAdd(
2252 MachineInstr &
I, MachineRegisterInfo &MRI) {
2253 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2254 Register DstReg =
I.getOperand(0).getReg();
2255 Register AddOp1Reg =
I.getOperand(1).getReg();
2256 const LLT PtrTy = MRI.
getType(DstReg);
2260 const LLT CastPtrTy = PtrTy.
isVector()
2272 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2273 MRI.
setType(DstReg, CastPtrTy);
2274 I.getOperand(1).setReg(PtrToInt.getReg(0));
2275 if (!select(*PtrToInt)) {
2276 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2285 I.getOperand(2).setReg(NegatedReg);
2286 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2290bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2291 MachineRegisterInfo &MRI) {
2295 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2296 const auto &MO =
I.getOperand(2);
2301 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2305 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2306 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2308 if (!Imm1Fn || !Imm2Fn)
2312 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2313 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2315 for (
auto &RenderFn : *Imm1Fn)
2317 for (
auto &RenderFn : *Imm2Fn)
2320 I.eraseFromParent();
2325bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2326 MachineInstr &
I, MachineRegisterInfo &MRI) {
2327 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2345 LLT DefDstTy = MRI.
getType(DefDstReg);
2346 Register StoreSrcReg =
I.getOperand(0).getReg();
2347 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2363 I.getOperand(0).setReg(DefDstReg);
2367bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2368 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2369 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2375 switch (
I.getOpcode()) {
2376 case AArch64::G_DUP: {
2379 Register Src =
I.getOperand(1).getReg();
2381 Src, MRI,
true,
true);
2385 Register Dst =
I.getOperand(0).getReg();
2391 if (!emitConstantVector(Dst, CV, MIB, MRI))
2393 I.eraseFromParent();
2396 case TargetOpcode::G_SEXT:
2399 if (selectUSMovFromExtend(
I, MRI))
2402 case TargetOpcode::G_BR:
2404 case TargetOpcode::G_SHL:
2405 return earlySelectSHL(
I, MRI);
2406 case TargetOpcode::G_CONSTANT: {
2407 bool IsZero =
false;
2408 if (
I.getOperand(1).isCImm())
2409 IsZero =
I.getOperand(1).getCImm()->isZero();
2410 else if (
I.getOperand(1).isImm())
2411 IsZero =
I.getOperand(1).getImm() == 0;
2416 Register DefReg =
I.getOperand(0).getReg();
2419 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2422 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2427 I.setDesc(
TII.get(TargetOpcode::COPY));
2431 case TargetOpcode::G_ADD: {
2440 Register AddDst =
I.getOperand(0).getReg();
2441 Register AddLHS =
I.getOperand(1).getReg();
2442 Register AddRHS =
I.getOperand(2).getReg();
2452 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2473 MachineInstr *
Cmp = MatchCmp(AddRHS);
2477 Cmp = MatchCmp(AddRHS);
2481 auto &PredOp =
Cmp->getOperand(1);
2483 emitIntegerCompare(
Cmp->getOperand(2),
2484 Cmp->getOperand(3), PredOp, MIB);
2488 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2489 I.eraseFromParent();
2492 case TargetOpcode::G_OR: {
2496 Register Dst =
I.getOperand(0).getReg();
2516 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2519 int64_t Immr =
Size - ShiftImm;
2520 int64_t Imms =
Size - ShiftImm - 1;
2521 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2522 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2523 I.eraseFromParent();
2526 case TargetOpcode::G_FENCE: {
2527 if (
I.getOperand(1).getImm() == 0)
2531 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2532 I.eraseFromParent();
2540bool AArch64InstructionSelector::select(MachineInstr &
I) {
2541 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2542 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2548 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2549 if (Subtarget->requiresStrictAlign()) {
2551 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2557 unsigned Opcode =
I.getOpcode();
2559 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2562 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2567 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2568 const Register DefReg =
I.getOperand(0).getReg();
2569 const LLT DefTy = MRI.
getType(DefReg);
2574 const TargetRegisterClass *DefRC =
2582 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2589 I.setDesc(
TII.get(TargetOpcode::PHI));
2597 if (
I.isDebugInstr())
2604 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2606 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2613 if (preISelLower(
I)) {
2614 Opcode =
I.getOpcode();
2625 if (selectImpl(
I, *CoverageInfo))
2629 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2632 case TargetOpcode::G_SBFX:
2633 case TargetOpcode::G_UBFX: {
2634 static const unsigned OpcTable[2][2] = {
2635 {AArch64::UBFMWri, AArch64::UBFMXri},
2636 {AArch64::SBFMWri, AArch64::SBFMXri}};
2637 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2639 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2642 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2645 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2646 auto LSB = Cst1->Value.getZExtValue();
2647 auto Width = Cst2->Value.getZExtValue();
2651 .
addImm(LSB + Width - 1);
2652 I.eraseFromParent();
2656 case TargetOpcode::G_BRCOND:
2657 return selectCompareBranch(
I, MF, MRI);
2659 case TargetOpcode::G_BRINDIRECT: {
2661 if (std::optional<uint16_t> BADisc =
2663 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2666 MI.addReg(AArch64::XZR);
2667 I.eraseFromParent();
2671 I.setDesc(
TII.get(AArch64::BR));
2676 case TargetOpcode::G_BRJT:
2677 return selectBrJT(
I, MRI);
2679 case AArch64::G_ADD_LOW: {
2684 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2685 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2686 I.setDesc(
TII.get(AArch64::ADDXri));
2692 "Expected small code model");
2694 auto Op2 =
I.getOperand(2);
2695 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2696 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2697 Op1.getTargetFlags())
2699 Op2.getTargetFlags());
2700 I.eraseFromParent();
2705 case TargetOpcode::G_FCONSTANT: {
2706 const Register DefReg =
I.getOperand(0).getReg();
2707 const LLT DefTy = MRI.
getType(DefReg);
2711 const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2718 bool OptForSize = shouldOptForSize(&MF);
2722 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2729 auto *FPImm =
I.getOperand(1).getFPImm();
2732 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2735 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2736 I.eraseFromParent();
2741 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2744 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2745 MachineOperand &RegOp =
I.getOperand(0);
2751 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2755 MachineOperand &ImmOp =
I.getOperand(1);
2759 const unsigned MovOpc =
2760 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2761 I.setDesc(
TII.get(MovOpc));
2765 case TargetOpcode::G_EXTRACT: {
2766 Register DstReg =
I.getOperand(0).getReg();
2767 Register SrcReg =
I.getOperand(1).getReg();
2768 LLT SrcTy = MRI.
getType(SrcReg);
2769 LLT DstTy = MRI.
getType(DstReg);
2781 unsigned Offset =
I.getOperand(2).getImm();
2786 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2787 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2790 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2792 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2794 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2796 AArch64::GPR64RegClass, NewI->getOperand(0));
2797 I.eraseFromParent();
2803 unsigned LaneIdx =
Offset / 64;
2804 MachineInstr *Extract = emitExtractVectorElt(
2805 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2808 I.eraseFromParent();
2812 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2813 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2818 "unexpected G_EXTRACT types");
2825 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2826 .addReg(DstReg, {}, AArch64::sub_32);
2828 AArch64::GPR32RegClass, MRI);
2829 I.getOperand(0).setReg(DstReg);
2835 case TargetOpcode::G_INSERT: {
2836 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2837 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2844 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2845 unsigned LSB =
I.getOperand(3).getImm();
2847 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2848 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2852 "unexpected G_INSERT types");
2859 TII.get(AArch64::SUBREG_TO_REG))
2861 .
addUse(
I.getOperand(2).getReg())
2862 .
addImm(AArch64::sub_32);
2864 AArch64::GPR32RegClass, MRI);
2865 I.getOperand(2).setReg(SrcReg);
2870 case TargetOpcode::G_FRAME_INDEX: {
2877 I.setDesc(
TII.get(AArch64::ADDXri));
2887 case TargetOpcode::G_GLOBAL_VALUE: {
2888 const GlobalValue *GV =
nullptr;
2890 if (
I.getOperand(1).isSymbol()) {
2891 OpFlags =
I.getOperand(1).getTargetFlags();
2900 return selectTLSGlobalValue(
I, MRI);
2906 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2907 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2908 I.getOperand(1).setTargetFlags(OpFlags);
2909 I.addImplicitDefUseOperands(MF);
2913 materializeLargeCMVal(
I, GV, OpFlags);
2914 I.eraseFromParent();
2917 I.setDesc(
TII.get(AArch64::ADR));
2918 I.getOperand(1).setTargetFlags(OpFlags);
2920 I.setDesc(
TII.get(AArch64::MOVaddr));
2922 MachineInstrBuilder MIB(MF,
I);
2923 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2930 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2931 return selectPtrAuthGlobalValue(
I, MRI);
2933 case TargetOpcode::G_ZEXTLOAD:
2934 case TargetOpcode::G_LOAD:
2935 case TargetOpcode::G_STORE: {
2937 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2952 assert(MemSizeInBytes <= 8 &&
2953 "128-bit atomics should already be custom-legalized");
2956 static constexpr unsigned LDAPROpcodes[] = {
2957 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2958 static constexpr unsigned LDAROpcodes[] = {
2959 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2960 ArrayRef<unsigned> Opcodes =
2961 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2964 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2966 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2967 AArch64::STLRW, AArch64::STLRX};
2972 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2973 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2974 I.getOperand(0).setReg(NewVal);
2976 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2984 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2987 "Load/Store pointer operand isn't a GPR");
2989 "Load/Store pointer operand isn't a pointer");
2994 LLT ValTy = MRI.
getType(ValReg);
3001 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3007 .addReg(ValReg, {}, SubReg)
3014 if (RB.
getID() == AArch64::FPRRegBankID) {
3017 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3027 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3030 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3039 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3041 const unsigned NewOpc =
3043 if (NewOpc ==
I.getOpcode())
3047 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3050 I.setDesc(
TII.get(NewOpc));
3056 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3057 Register CurValReg =
I.getOperand(0).getReg();
3058 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3059 NewInst.cloneMemRefs(
I);
3060 for (
auto &Fn : *AddrModeFns)
3062 I.eraseFromParent();
3066 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3071 if (Opcode == TargetOpcode::G_STORE) {
3073 LoadStore->getOperand(0).getReg(), MRI);
3074 if (CVal && CVal->Value == 0) {
3076 case AArch64::STRWui:
3077 case AArch64::STRHHui:
3078 case AArch64::STRBBui:
3079 LoadStore->getOperand(0).setReg(AArch64::WZR);
3081 case AArch64::STRXui:
3082 LoadStore->getOperand(0).setReg(AArch64::XZR);
3088 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3089 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3101 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3103 .
addImm(AArch64::sub_32);
3112 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3113 case TargetOpcode::G_INDEXED_SEXTLOAD:
3114 return selectIndexedExtLoad(
I, MRI);
3115 case TargetOpcode::G_INDEXED_LOAD:
3116 return selectIndexedLoad(
I, MRI);
3117 case TargetOpcode::G_INDEXED_STORE:
3120 case TargetOpcode::G_LSHR:
3121 case TargetOpcode::G_ASHR:
3123 return selectVectorAshrLshr(
I, MRI);
3125 case TargetOpcode::G_SHL:
3126 if (Opcode == TargetOpcode::G_SHL &&
3128 return selectVectorSHL(
I, MRI);
3135 Register SrcReg =
I.getOperand(1).getReg();
3136 Register ShiftReg =
I.getOperand(2).getReg();
3137 const LLT ShiftTy = MRI.
getType(ShiftReg);
3138 const LLT SrcTy = MRI.
getType(SrcReg);
3143 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3144 .addReg(ShiftReg, {}, AArch64::sub_32);
3146 I.getOperand(2).setReg(Trunc.getReg(0));
3150 case TargetOpcode::G_OR: {
3157 const Register DefReg =
I.getOperand(0).getReg();
3161 if (NewOpc ==
I.getOpcode())
3164 I.setDesc(
TII.get(NewOpc));
3173 case TargetOpcode::G_PTR_ADD: {
3174 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3175 I.eraseFromParent();
3179 case TargetOpcode::G_SADDE:
3180 case TargetOpcode::G_UADDE:
3181 case TargetOpcode::G_SSUBE:
3182 case TargetOpcode::G_USUBE:
3183 case TargetOpcode::G_SADDO:
3184 case TargetOpcode::G_UADDO:
3185 case TargetOpcode::G_SSUBO:
3186 case TargetOpcode::G_USUBO:
3187 return selectOverflowOp(
I, MRI);
3189 case TargetOpcode::G_PTRMASK: {
3190 Register MaskReg =
I.getOperand(2).getReg();
3196 uint64_t
Mask = *MaskVal;
3197 I.setDesc(
TII.get(AArch64::ANDXri));
3198 I.getOperand(2).ChangeToImmediate(
3204 case TargetOpcode::G_PTRTOINT:
3205 case TargetOpcode::G_TRUNC: {
3206 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3207 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3209 const Register DstReg =
I.getOperand(0).getReg();
3210 const Register SrcReg =
I.getOperand(1).getReg();
3212 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3213 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3217 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3221 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3222 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3226 const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
3232 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3236 if (DstRC == SrcRC) {
3238 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3242 }
else if (DstRC == &AArch64::GPR32RegClass &&
3243 SrcRC == &AArch64::GPR64RegClass) {
3244 I.getOperand(1).setSubReg(AArch64::sub_32);
3247 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3251 I.setDesc(
TII.get(TargetOpcode::COPY));
3253 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3256 I.setDesc(
TII.get(AArch64::XTNv4i16));
3262 MachineInstr *Extract = emitExtractVectorElt(
3266 I.eraseFromParent();
3271 if (Opcode == TargetOpcode::G_PTRTOINT) {
3272 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3273 I.setDesc(
TII.get(TargetOpcode::COPY));
3281 case TargetOpcode::G_ANYEXT: {
3282 if (selectUSMovFromExtend(
I, MRI))
3285 const Register DstReg =
I.getOperand(0).getReg();
3286 const Register SrcReg =
I.getOperand(1).getReg();
3288 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3289 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3291 <<
", expected: GPR\n");
3295 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3296 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3298 <<
", expected: GPR\n");
3305 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3309 if (DstSize != 64 && DstSize > 32) {
3311 <<
", expected: 32 or 64\n");
3321 .
addImm(AArch64::sub_32);
3322 I.getOperand(1).setReg(ExtSrc);
3327 case TargetOpcode::G_ZEXT:
3328 case TargetOpcode::G_SEXT_INREG:
3329 case TargetOpcode::G_SEXT: {
3330 if (selectUSMovFromExtend(
I, MRI))
3333 unsigned Opcode =
I.getOpcode();
3334 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3335 const Register DefReg =
I.getOperand(0).getReg();
3336 Register SrcReg =
I.getOperand(1).getReg();
3337 const LLT DstTy = MRI.
getType(DefReg);
3338 const LLT SrcTy = MRI.
getType(SrcReg);
3344 if (Opcode == TargetOpcode::G_SEXT_INREG)
3345 SrcSize =
I.getOperand(2).getImm();
3351 AArch64::GPRRegBankID &&
3352 "Unexpected ext regbank");
3363 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3366 if (LoadMI && IsGPR) {
3367 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3368 unsigned BytesLoaded = MemOp->getSize().getValue();
3375 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3378 const Register ZReg = AArch64::WZR;
3379 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3382 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3383 .addUse(SubregToRegSrc)
3384 .
addImm(AArch64::sub_32);
3388 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3398 I.eraseFromParent();
3403 if (DstSize == 64) {
3404 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3412 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3413 {&AArch64::GPR64RegClass}, {})
3419 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3423 }
else if (DstSize <= 32) {
3424 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3433 I.eraseFromParent();
3437 case TargetOpcode::G_FREEZE:
3440 case TargetOpcode::G_INTTOPTR:
3445 case TargetOpcode::G_BITCAST:
3453 case TargetOpcode::G_SELECT: {
3455 const Register CondReg = Sel.getCondReg();
3457 const Register FReg = Sel.getFalseReg();
3459 if (tryOptSelect(Sel))
3465 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3468 if (!emitSelect(Sel.getReg(0), TReg, FReg,
AArch64CC::NE, MIB))
3470 Sel.eraseFromParent();
3473 case TargetOpcode::G_ICMP: {
3483 auto &PredOp =
I.getOperand(1);
3484 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3488 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3489 AArch64::WZR, InvCC, MIB);
3490 I.eraseFromParent();
3494 case TargetOpcode::G_FCMP: {
3497 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3499 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3501 I.eraseFromParent();
3504 case TargetOpcode::G_VASTART:
3506 : selectVaStartAAPCS(
I, MF, MRI);
3507 case TargetOpcode::G_INTRINSIC:
3508 return selectIntrinsic(
I, MRI);
3509 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3510 return selectIntrinsicWithSideEffects(
I, MRI);
3511 case TargetOpcode::G_IMPLICIT_DEF: {
3512 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3513 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3514 const Register DstReg =
I.getOperand(0).getReg();
3515 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3516 const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
3520 case TargetOpcode::G_BLOCK_ADDR: {
3521 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3522 if (std::optional<uint16_t> BADisc =
3524 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3525 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3534 AArch64::GPR64RegClass, MRI);
3535 I.eraseFromParent();
3539 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3540 I.eraseFromParent();
3543 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3544 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3545 I.getOperand(0).getReg())
3549 I.getOperand(1).getBlockAddress(), 0,
3551 I.eraseFromParent();
3556 case AArch64::G_DUP: {
3563 AArch64::GPRRegBankID)
3565 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3567 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3569 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3571 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3573 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3579 case TargetOpcode::G_BUILD_VECTOR:
3580 return selectBuildVector(
I, MRI);
3581 case TargetOpcode::G_MERGE_VALUES:
3583 case TargetOpcode::G_UNMERGE_VALUES:
3585 case TargetOpcode::G_SHUFFLE_VECTOR:
3586 return selectShuffleVector(
I, MRI);
3587 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3588 return selectExtractElt(
I, MRI);
3589 case TargetOpcode::G_CONCAT_VECTORS:
3590 return selectConcatVectors(
I, MRI);
3591 case TargetOpcode::G_JUMP_TABLE:
3592 return selectJumpTable(
I, MRI);
3593 case TargetOpcode::G_MEMCPY:
3594 case TargetOpcode::G_MEMCPY_INLINE:
3595 case TargetOpcode::G_MEMMOVE:
3596 case TargetOpcode::G_MEMSET:
3597 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3598 return selectMOPS(
I, MRI);
3604bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3605 MachineIRBuilderState OldMIBState = MIB.
getState();
3611bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3612 MachineRegisterInfo &MRI) {
3615 case TargetOpcode::G_MEMCPY:
3616 case TargetOpcode::G_MEMCPY_INLINE:
3617 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3619 case TargetOpcode::G_MEMMOVE:
3620 Mopcode = AArch64::MOPSMemoryMovePseudo;
3622 case TargetOpcode::G_MEMSET:
3624 Mopcode = AArch64::MOPSMemorySetPseudo;
3637 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3638 const auto &SrcValRegClass =
3639 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3657 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3658 {DstPtrCopy, SizeCopy, SrcValCopy});
3661 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3662 {DstPtrCopy, SrcValCopy, SizeCopy});
3669bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3670 MachineRegisterInfo &MRI) {
3671 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3672 Register JTAddr =
I.getOperand(0).getReg();
3673 unsigned JTI =
I.getOperand(1).getIndex();
3676 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3688 "jump table hardening only supported on MachO/ELF");
3696 I.eraseFromParent();
3703 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3704 {TargetReg, ScratchReg}, {JTAddr,
Index})
3705 .addJumpTableIndex(JTI);
3707 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3708 {
static_cast<int64_t
>(JTI)});
3710 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3711 I.eraseFromParent();
3716bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3717 MachineRegisterInfo &MRI) {
3718 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3719 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3721 Register DstReg =
I.getOperand(0).getReg();
3722 unsigned JTI =
I.getOperand(1).getIndex();
3725 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3728 I.eraseFromParent();
3733bool AArch64InstructionSelector::selectTLSGlobalValue(
3734 MachineInstr &
I, MachineRegisterInfo &MRI) {
3737 MachineFunction &MF = *
I.getParent()->getParent();
3740 const auto &GlobalOp =
I.getOperand(1);
3741 assert(GlobalOp.getOffset() == 0 &&
3742 "Shouldn't have an offset on TLS globals!");
3743 const GlobalValue &GV = *GlobalOp.getGlobal();
3746 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3749 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3750 {LoadGOT.getReg(0)})
3761 assert(Opcode == AArch64::BLR);
3762 Opcode = AArch64::BLRAAZ;
3766 .addUse(AArch64::X0, RegState::Implicit)
3767 .
addDef(AArch64::X0, RegState::Implicit)
3773 I.eraseFromParent();
3777MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3778 unsigned EltSize,
const TargetRegisterClass *DstRC,
Register Scalar,
3779 MachineIRBuilder &MIRBuilder)
const {
3780 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3782 auto BuildFn = [&](
unsigned SubregIndex) {
3786 .addImm(SubregIndex);
3794 return BuildFn(AArch64::bsub);
3796 return BuildFn(AArch64::hsub);
3798 return BuildFn(AArch64::ssub);
3800 return BuildFn(AArch64::dsub);
3807AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3808 MachineIRBuilder &MIB,
3809 MachineRegisterInfo &MRI)
const {
3810 LLT DstTy = MRI.
getType(DstReg);
3811 const TargetRegisterClass *RC =
3812 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3813 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3817 unsigned SubReg = 0;
3820 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3826 .addReg(SrcReg, {}, SubReg);
3831bool AArch64InstructionSelector::selectMergeValues(
3832 MachineInstr &
I, MachineRegisterInfo &MRI) {
3833 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3834 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3835 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3837 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3839 if (
I.getNumOperands() != 3)
3846 Register DstReg =
I.getOperand(0).getReg();
3847 Register Src1Reg =
I.getOperand(1).getReg();
3848 Register Src2Reg =
I.getOperand(2).getReg();
3849 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3850 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3854 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3855 Src2Reg, 1, RB, MIB);
3860 I.eraseFromParent();
3864 if (RB.
getID() != AArch64::GPRRegBankID)
3870 auto *DstRC = &AArch64::GPR64RegClass;
3872 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3873 TII.get(TargetOpcode::SUBREG_TO_REG))
3875 .
addUse(
I.getOperand(1).getReg())
3876 .
addImm(AArch64::sub_32);
3879 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3880 TII.get(TargetOpcode::SUBREG_TO_REG))
3882 .
addUse(
I.getOperand(2).getReg())
3883 .
addImm(AArch64::sub_32);
3885 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3886 .
addDef(
I.getOperand(0).getReg())
3894 I.eraseFromParent();
3899 const unsigned EltSize) {
3904 CopyOpc = AArch64::DUPi8;
3905 ExtractSubReg = AArch64::bsub;
3908 CopyOpc = AArch64::DUPi16;
3909 ExtractSubReg = AArch64::hsub;
3912 CopyOpc = AArch64::DUPi32;
3913 ExtractSubReg = AArch64::ssub;
3916 CopyOpc = AArch64::DUPi64;
3917 ExtractSubReg = AArch64::dsub;
3921 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3927MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3928 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3929 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3930 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3931 unsigned CopyOpc = 0;
3932 unsigned ExtractSubReg = 0;
3935 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3939 const TargetRegisterClass *DstRC =
3940 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3942 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3946 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3947 const LLT &VecTy = MRI.
getType(VecReg);
3948 const TargetRegisterClass *VecRC =
3949 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3951 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3961 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3962 .addReg(VecReg, {}, ExtractSubReg);
3971 MachineInstr *ScalarToVector = emitScalarToVector(
3972 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3973 if (!ScalarToVector)
3978 MachineInstr *LaneCopyMI =
3979 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3987bool AArch64InstructionSelector::selectExtractElt(
3988 MachineInstr &
I, MachineRegisterInfo &MRI) {
3989 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3990 "unexpected opcode!");
3991 Register DstReg =
I.getOperand(0).getReg();
3992 const LLT NarrowTy = MRI.
getType(DstReg);
3993 const Register SrcReg =
I.getOperand(1).getReg();
3994 const LLT WideTy = MRI.
getType(SrcReg);
3997 "source register size too small!");
3998 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4001 MachineOperand &LaneIdxOp =
I.getOperand(2);
4002 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4013 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4016 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4017 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4022 I.eraseFromParent();
4026bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4027 MachineInstr &
I, MachineRegisterInfo &MRI) {
4028 unsigned NumElts =
I.getNumOperands() - 1;
4029 Register SrcReg =
I.getOperand(NumElts).getReg();
4030 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4031 const LLT SrcTy = MRI.
getType(SrcReg);
4033 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4035 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4041 const RegisterBank &DstRB =
4045 MachineInstr *Extract =
4046 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg,
OpIdx, MIB);
4050 I.eraseFromParent();
4054bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4055 MachineRegisterInfo &MRI) {
4056 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4057 "unexpected opcode");
4061 AArch64::FPRRegBankID ||
4063 AArch64::FPRRegBankID) {
4064 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4065 "currently unsupported.\n");
4071 unsigned NumElts =
I.getNumOperands() - 1;
4072 Register SrcReg =
I.getOperand(NumElts).getReg();
4073 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4074 const LLT WideTy = MRI.
getType(SrcReg);
4077 "source register size too small!");
4080 return selectSplitVectorUnmerge(
I, MRI);
4084 unsigned CopyOpc = 0;
4085 unsigned ExtractSubReg = 0;
4096 unsigned NumInsertRegs = NumElts - 1;
4109 const TargetRegisterClass *RC = getRegClassForTypeOnBank(
4111 unsigned SubReg = 0;
4114 assert(Found &&
"expected to find last operand's subeg idx");
4115 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4117 MachineInstr &ImpDefMI =
4118 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4123 MachineInstr &InsMI =
4125 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4142 Register CopyTo =
I.getOperand(0).getReg();
4143 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4144 .addReg(InsertRegs[0], {}, ExtractSubReg);
4148 unsigned LaneIdx = 1;
4149 for (
Register InsReg : InsertRegs) {
4150 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4151 MachineInstr &CopyInst =
4162 const TargetRegisterClass *RC =
4170 I.eraseFromParent();
4174bool AArch64InstructionSelector::selectConcatVectors(
4175 MachineInstr &
I, MachineRegisterInfo &MRI) {
4176 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4177 "Unexpected opcode");
4178 Register Dst =
I.getOperand(0).getReg();
4179 Register Op1 =
I.getOperand(1).getReg();
4180 Register Op2 =
I.getOperand(2).getReg();
4181 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4184 I.eraseFromParent();
4189AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4190 MachineFunction &MF)
const {
4198MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4199 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4200 const TargetRegisterClass *RC;
4206 RC = &AArch64::FPR128RegClass;
4207 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4210 RC = &AArch64::FPR64RegClass;
4211 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4214 RC = &AArch64::FPR32RegClass;
4215 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4218 RC = &AArch64::FPR16RegClass;
4219 Opc = AArch64::LDRHui;
4222 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4227 MachineInstr *LoadMI =
nullptr;
4228 auto &MF = MIRBuilder.
getMF();
4229 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4230 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4232 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4235 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4239 .addConstantPoolIndex(
4255static std::pair<unsigned, unsigned>
4257 unsigned Opc, SubregIdx;
4258 if (RB.
getID() == AArch64::GPRRegBankID) {
4260 Opc = AArch64::INSvi8gpr;
4261 SubregIdx = AArch64::bsub;
4262 }
else if (EltSize == 16) {
4263 Opc = AArch64::INSvi16gpr;
4264 SubregIdx = AArch64::ssub;
4265 }
else if (EltSize == 32) {
4266 Opc = AArch64::INSvi32gpr;
4267 SubregIdx = AArch64::ssub;
4268 }
else if (EltSize == 64) {
4269 Opc = AArch64::INSvi64gpr;
4270 SubregIdx = AArch64::dsub;
4276 Opc = AArch64::INSvi8lane;
4277 SubregIdx = AArch64::bsub;
4278 }
else if (EltSize == 16) {
4279 Opc = AArch64::INSvi16lane;
4280 SubregIdx = AArch64::hsub;
4281 }
else if (EltSize == 32) {
4282 Opc = AArch64::INSvi32lane;
4283 SubregIdx = AArch64::ssub;
4284 }
else if (EltSize == 64) {
4285 Opc = AArch64::INSvi64lane;
4286 SubregIdx = AArch64::dsub;
4291 return std::make_pair(
Opc, SubregIdx);
4294MachineInstr *AArch64InstructionSelector::emitInstr(
4295 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4296 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4297 const ComplexRendererFns &RenderFns)
const {
4298 assert(Opcode &&
"Expected an opcode?");
4300 "Function should only be used to produce selected instructions!");
4301 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4303 for (
auto &Fn : *RenderFns)
4309MachineInstr *AArch64InstructionSelector::emitAddSub(
4310 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4312 MachineIRBuilder &MIRBuilder)
const {
4314 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4318 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4319 bool Is32Bit =
Size == 32;
4322 if (
auto Fns = selectArithImmed(
RHS))
4323 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4327 if (
auto Fns = selectNegArithImmed(
RHS))
4328 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4332 if (
auto Fns = selectArithExtendedRegister(
RHS))
4333 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4337 if (
auto Fns = selectShiftedRegister(
RHS))
4338 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4340 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4345AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4346 MachineOperand &
RHS,
4347 MachineIRBuilder &MIRBuilder)
const {
4348 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4349 {{AArch64::ADDXri, AArch64::ADDWri},
4350 {AArch64::ADDXrs, AArch64::ADDWrs},
4351 {AArch64::ADDXrr, AArch64::ADDWrr},
4352 {AArch64::SUBXri, AArch64::SUBWri},
4353 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4354 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4358AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4359 MachineOperand &
RHS,
4360 MachineIRBuilder &MIRBuilder)
const {
4361 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4362 {{AArch64::ADDSXri, AArch64::ADDSWri},
4363 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4364 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4365 {AArch64::SUBSXri, AArch64::SUBSWri},
4366 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4367 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4371AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4372 MachineOperand &
RHS,
4373 MachineIRBuilder &MIRBuilder)
const {
4374 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4375 {{AArch64::SUBSXri, AArch64::SUBSWri},
4376 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4377 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4378 {AArch64::ADDSXri, AArch64::ADDSWri},
4379 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4380 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4384AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4385 MachineOperand &
RHS,
4386 MachineIRBuilder &MIRBuilder)
const {
4387 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4388 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4390 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4391 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4395AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4396 MachineOperand &
RHS,
4397 MachineIRBuilder &MIRBuilder)
const {
4398 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4399 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4401 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4402 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4406AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4407 MachineIRBuilder &MIRBuilder)
const {
4410 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4415AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4416 MachineIRBuilder &MIRBuilder)
const {
4419 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4424AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4425 MachineIRBuilder &MIRBuilder)
const {
4426 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4430 bool Is32Bit = (
RegSize == 32);
4431 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4432 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4433 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4437 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4440 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4447 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4448 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4449 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4452MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4453 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4454 MachineIRBuilder &MIRBuilder)
const {
4455 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4462 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4464 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4466 return emitCMP(
LHS,
RHS, MIRBuilder);
4469MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4471 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4475 "Expected a 32-bit scalar register?");
4477 const Register ZReg = AArch64::WZR;
4482 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4484 const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4488 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4489 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4490 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4495MachineInstr *AArch64InstructionSelector::emitFPCompare(
4497 std::optional<CmpInst::Predicate> Pred)
const {
4498 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4503 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4514 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4518 ShouldUseImm =
true;
4522 unsigned CmpOpcTbl[2][3] = {
4523 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4524 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4526 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4538MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4540 MachineIRBuilder &MIRBuilder)
const {
4547 const LLT Op1Ty = MRI.
getType(Op1);
4548 const LLT Op2Ty = MRI.
getType(Op2);
4550 if (Op1Ty != Op2Ty) {
4551 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4554 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4557 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4568 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4569 const TargetRegisterClass *DstRC =
4572 MachineInstr *WidenedOp1 =
4573 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4574 MachineInstr *WidenedOp2 =
4575 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4576 if (!WidenedOp1 || !WidenedOp2) {
4577 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4582 unsigned InsertOpc, InsSubRegIdx;
4583 std::tie(InsertOpc, InsSubRegIdx) =
4601 MachineIRBuilder &MIRBuilder)
const {
4602 auto &MRI = *MIRBuilder.
getMRI();
4608 Size =
TRI.getRegSizeInBits(*RC);
4612 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4613 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4614 unsigned Opc = OpcTable[
Size == 64];
4615 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4620MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4622 MachineRegisterInfo *MRI = MIB.
getMRI();
4623 unsigned Opcode =
I.getOpcode();
4627 bool NeedsNegatedCarry =
4628 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4637 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4638 if (SrcMI ==
I.getPrevNode()) {
4640 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4641 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4642 CarrySrcMI->isUnsigned() &&
4643 CarrySrcMI->getCarryOutReg() == CarryReg &&
4644 selectAndRestoreState(*SrcMI))
4651 if (NeedsNegatedCarry) {
4654 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4658 auto Fns = select12BitValueWithLeftShift(1);
4659 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4662bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4663 MachineRegisterInfo &MRI) {
4668 emitCarryIn(
I, CarryInMI->getCarryInReg());
4672 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4673 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4675 Register CarryOutReg = CarryMI.getCarryOutReg();
4684 emitCSINC(CarryOutReg, ZReg, ZReg,
4685 getInvertedCondCode(OpAndCC.second), MIB);
4688 I.eraseFromParent();
4692std::pair<MachineInstr *, AArch64CC::CondCode>
4693AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4694 MachineOperand &
LHS,
4695 MachineOperand &
RHS,
4696 MachineIRBuilder &MIRBuilder)
const {
4700 case TargetOpcode::G_SADDO:
4702 case TargetOpcode::G_UADDO:
4704 case TargetOpcode::G_SSUBO:
4706 case TargetOpcode::G_USUBO:
4708 case TargetOpcode::G_SADDE:
4710 case TargetOpcode::G_UADDE:
4712 case TargetOpcode::G_SSUBE:
4714 case TargetOpcode::G_USUBE:
4735 unsigned Depth = 0) {
4742 MustBeFirst =
false;
4748 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4749 bool IsOR = Opcode == TargetOpcode::G_OR;
4761 if (MustBeFirstL && MustBeFirstR)
4767 if (!CanNegateL && !CanNegateR)
4771 CanNegate = WillNegate && CanNegateL && CanNegateR;
4774 MustBeFirst = !CanNegate;
4776 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4779 MustBeFirst = MustBeFirstL || MustBeFirstR;
4786MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4789 MachineIRBuilder &MIB)
const {
4790 auto &MRI = *MIB.
getMRI();
4793 std::optional<ValueAndVReg>
C;
4797 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4798 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4799 else if (
C->Value.ule(31))
4800 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4802 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4808 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4809 CCmpOpc = AArch64::FCCMPHrr;
4812 CCmpOpc = AArch64::FCCMPSrr;
4815 CCmpOpc = AArch64::FCCMPDrr;
4825 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4826 CCmp.
addImm(
C->Value.getZExtValue());
4827 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4828 CCmp.
addImm(
C->Value.abs().getZExtValue());
4836MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4840 auto &MRI = *MIB.
getMRI();
4858 MachineInstr *ExtraCmp;
4860 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4872 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4873 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4874 Cmp->getOperand(3).getReg(), MIB);
4881 bool IsOR = Opcode == TargetOpcode::G_OR;
4887 assert(ValidL &&
"Valid conjunction/disjunction tree");
4894 assert(ValidR &&
"Valid conjunction/disjunction tree");
4899 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4908 bool NegateAfterAll;
4909 if (Opcode == TargetOpcode::G_OR) {
4912 assert(CanNegateR &&
"at least one side must be negatable");
4913 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4917 NegateAfterR =
true;
4920 NegateR = CanNegateR;
4921 NegateAfterR = !CanNegateR;
4924 NegateAfterAll = !Negate;
4926 assert(Opcode == TargetOpcode::G_AND &&
4927 "Valid conjunction/disjunction tree");
4928 assert(!Negate &&
"Valid conjunction/disjunction tree");
4932 NegateAfterR =
false;
4933 NegateAfterAll =
false;
4938 MachineInstr *CmpR =
4949MachineInstr *AArch64InstructionSelector::emitConjunction(
4951 bool DummyCanNegate;
4952 bool DummyMustBeFirst;
4959bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4960 MachineInstr &CondMI) {
4971bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4972 MachineRegisterInfo &MRI = *MIB.
getMRI();
4991 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5000 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5006 unsigned CondOpc = CondDef->
getOpcode();
5007 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5008 if (tryOptSelectConjunction(
I, *CondDef))
5014 if (CondOpc == TargetOpcode::G_ICMP) {
5043 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5044 I.getOperand(3).getReg(), CondCode, MIB);
5045 I.eraseFromParent();
5049MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5050 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5051 MachineIRBuilder &MIRBuilder)
const {
5053 "Unexpected MachineOperand");
5054 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5077 if (
isCMN(RHSDef,
P, MRI))
5092 if (
isCMN(LHSDef,
P, MRI)) {
5109 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5112 if (!ValAndVReg || ValAndVReg->Value != 0)
5122bool AArch64InstructionSelector::selectShuffleVector(
5123 MachineInstr &
I, MachineRegisterInfo &MRI) {
5124 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5125 Register Src1Reg =
I.getOperand(1).getReg();
5126 Register Src2Reg =
I.getOperand(2).getReg();
5127 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5136 for (
int Val : Mask) {
5139 Val = Val < 0 ? 0 : Val;
5140 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5158 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5165 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5169 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5174 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5175 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5177 I.eraseFromParent();
5185 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5188 I.eraseFromParent();
5192MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5194 unsigned LaneIdx,
const RegisterBank &RB,
5195 MachineIRBuilder &MIRBuilder)
const {
5196 MachineInstr *InsElt =
nullptr;
5197 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5198 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5207 if (RB.
getID() == AArch64::FPRRegBankID) {
5208 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5211 .
addUse(InsSub->getOperand(0).getReg())
5223bool AArch64InstructionSelector::selectUSMovFromExtend(
5224 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5225 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5226 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5227 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5229 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5230 const Register DefReg =
MI.getOperand(0).getReg();
5231 const LLT DstTy = MRI.
getType(DefReg);
5234 if (DstSize != 32 && DstSize != 64)
5237 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5238 MI.getOperand(1).getReg(), MRI);
5244 const LLT VecTy = MRI.
getType(Src0);
5249 const MachineInstr *ScalarToVector = emitScalarToVector(
5250 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5251 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5257 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5259 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5261 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5263 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5265 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5273 MachineInstr *ExtI =
nullptr;
5274 if (DstSize == 64 && !IsSigned) {
5276 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5277 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5279 .
addImm(AArch64::sub_32);
5282 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5285 MI.eraseFromParent();
5289MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5290 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5292 if (DstSize == 128) {
5293 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5295 Op = AArch64::MOVIv16b_ns;
5297 Op = AArch64::MOVIv8b_ns;
5300 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5304 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5311MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5312 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5316 if (DstSize == 128) {
5317 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5319 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5321 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5324 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5341MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5342 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5346 if (DstSize == 128) {
5347 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5349 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5351 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5354 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5377MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5378 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5381 if (DstSize == 128) {
5382 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5384 Op = AArch64::MOVIv2d_ns;
5386 Op = AArch64::MOVID;
5389 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5392 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5399MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5400 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5404 if (DstSize == 128) {
5405 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5407 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5409 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5412 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5429MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5430 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5433 bool IsWide =
false;
5434 if (DstSize == 128) {
5435 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5437 Op = AArch64::FMOVv4f32_ns;
5440 Op = AArch64::FMOVv2f32_ns;
5443 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5449 Op = AArch64::FMOVv2f64_ns;
5453 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5458bool AArch64InstructionSelector::selectIndexedExtLoad(
5459 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5462 Register WriteBack = ExtLd.getWritebackReg();
5467 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5468 bool IsPre = ExtLd.isPre();
5470 unsigned InsertIntoSubReg = 0;
5476 if ((IsSExt && IsFPR) || Ty.
isVector())
5484 if (MemSizeBits == 8) {
5487 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5489 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5490 NewLdDstTy = IsDst64 ? s64 : s32;
5492 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5493 InsertIntoSubReg = AArch64::bsub;
5496 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5497 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5500 }
else if (MemSizeBits == 16) {
5503 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5505 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5506 NewLdDstTy = IsDst64 ? s64 : s32;
5508 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5509 InsertIntoSubReg = AArch64::hsub;
5512 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5513 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5516 }
else if (MemSizeBits == 32) {
5518 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5521 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5522 InsertIntoSubReg = AArch64::ssub;
5525 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5526 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5538 .addImm(Cst->getSExtValue());
5543 if (InsertIntoSubReg) {
5545 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5546 .addUse(LdMI.getReg(1))
5547 .
addImm(InsertIntoSubReg);
5550 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5557 MI.eraseFromParent();
5562bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5563 MachineRegisterInfo &MRI) {
5566 Register WriteBack = Ld.getWritebackReg();
5570 "Unexpected type for indexed load");
5571 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5574 return selectIndexedExtLoad(
MI, MRI);
5578 static constexpr unsigned GPROpcodes[] = {
5579 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5581 static constexpr unsigned FPROpcodes[] = {
5582 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5585 ? FPROpcodes[
Log2_32(MemSize)]
5586 : GPROpcodes[
Log2_32(MemSize)];
5589 static constexpr unsigned GPROpcodes[] = {
5590 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5592 static constexpr unsigned FPROpcodes[] = {
5593 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5594 AArch64::LDRDpost, AArch64::LDRQpost};
5596 ? FPROpcodes[
Log2_32(MemSize)]
5597 : GPROpcodes[
Log2_32(MemSize)];
5607 MI.eraseFromParent();
5611bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5612 MachineRegisterInfo &MRI) {
5618 "Unexpected type for indexed store");
5620 LocationSize MemSize =
I.getMMO().getSize();
5621 unsigned MemSizeInBytes = MemSize.
getValue();
5623 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5624 "Unexpected indexed store size");
5625 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5629 static constexpr unsigned GPROpcodes[] = {
5630 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5632 static constexpr unsigned FPROpcodes[] = {
5633 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5637 Opc = FPROpcodes[MemSizeLog2];
5639 Opc = GPROpcodes[MemSizeLog2];
5641 static constexpr unsigned GPROpcodes[] = {
5642 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5644 static constexpr unsigned FPROpcodes[] = {
5645 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5646 AArch64::STRDpost, AArch64::STRQpost};
5649 Opc = FPROpcodes[MemSizeLog2];
5651 Opc = GPROpcodes[MemSizeLog2];
5659 Str.cloneMemRefs(
I);
5661 I.eraseFromParent();
5666AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5667 MachineIRBuilder &MIRBuilder,
5668 MachineRegisterInfo &MRI) {
5671 assert((DstSize == 64 || DstSize == 128) &&
5672 "Unexpected vector constant size");
5675 if (DstSize == 128) {
5677 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5682 if (DstSize == 64) {
5685 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5688 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5695 APInt SplatValueAsInt =
5698 : SplatValue->getUniqueInteger();
5701 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5702 MachineInstr *NewOp;
5726 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5730 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5731 unsigned NegOpc) -> MachineInstr * {
5734 APInt NegBits(DstSize, 0);
5735 unsigned NumElts = DstSize / NumBits;
5736 for (
unsigned i = 0; i < NumElts; i++)
5737 NegBits |= Neg << (NumBits * i);
5738 NegBits = DefBits ^ NegBits;
5742 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5744 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5746 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5751 if ((R = TryWithFNeg(DefBits, 32,
5752 DstSize == 64 ? AArch64::FNEGv2f32
5753 : AArch64::FNEGv4f32)) ||
5754 (R = TryWithFNeg(DefBits, 64,
5755 DstSize == 64 ? AArch64::FNEGDr
5756 : AArch64::FNEGv2f64)) ||
5757 (STI.hasFullFP16() &&
5758 (R = TryWithFNeg(DefBits, 16,
5759 DstSize == 64 ? AArch64::FNEGv4f16
5760 : AArch64::FNEGv8f16))))
5766 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5770 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5772 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5776bool AArch64InstructionSelector::tryOptConstantBuildVec(
5777 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5778 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5780 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5786 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5787 Register OpReg =
I.getOperand(Idx).getReg();
5796 std::move(AnyConst->Value)));
5809 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5811 I.eraseFromParent();
5815bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5816 MachineInstr &
I, MachineRegisterInfo &MRI) {
5821 Register Dst =
I.getOperand(0).getReg();
5822 Register EltReg =
I.getOperand(1).getReg();
5823 LLT EltTy = MRI.
getType(EltReg);
5826 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5831 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5835 const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5838 const TargetRegisterClass *DstRC =
5839 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5844 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5847 I.eraseFromParent();
5852bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5853 MachineRegisterInfo &MRI) {
5854 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5857 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5858 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5861 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5863 if (tryOptBuildVecToSubregToReg(
I, MRI))
5866 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5868 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5870 const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
5871 MachineInstr *ScalarToVec =
5873 I.getOperand(1).getReg(), MIB);
5882 MachineInstr *PrevMI = ScalarToVec;
5883 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5886 Register OpReg =
I.getOperand(i).getReg();
5889 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5896 if (DstSize < 128) {
5898 const TargetRegisterClass *RC =
5899 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5902 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5907 unsigned SubReg = 0;
5910 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5911 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5917 Register DstReg =
I.getOperand(0).getReg();
5919 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5920 MachineOperand &RegOp =
I.getOperand(1);
5940 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5941 const TargetRegisterClass *RC =
5942 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5951bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5954 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5956 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5957 auto &MRI = *MIB.
getMRI();
5958 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5961 "Destination must be 64 bits or 128 bits?");
5962 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5963 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5966 Load.cloneMemRefs(
I);
5968 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5969 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5970 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5971 .addReg(SelectedLoadDst, {}, SubReg + Idx);
5980bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5981 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5982 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5984 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5985 auto &MRI = *MIB.
getMRI();
5986 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5989 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
5991 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
5992 [](
auto MO) { return MO.getReg(); });
5996 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6011 .
addImm(LaneNo->getZExtValue())
6013 Load.cloneMemRefs(
I);
6015 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6016 unsigned SubReg = AArch64::qsub0;
6017 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6018 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6019 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6020 : DstOp(
I.getOperand(Idx).
getReg())},
6022 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6027 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6033void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6036 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6037 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6038 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6041 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6042 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6051bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6052 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6053 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6054 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6058 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6059 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6063 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6073 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6076 .
addImm(LaneNo->getZExtValue())
6083bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6084 MachineInstr &
I, MachineRegisterInfo &MRI) {
6097 case Intrinsic::aarch64_ldxp:
6098 case Intrinsic::aarch64_ldaxp: {
6100 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6101 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6107 case Intrinsic::aarch64_neon_ld1x2: {
6108 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6111 Opc = AArch64::LD1Twov8b;
6113 Opc = AArch64::LD1Twov16b;
6115 Opc = AArch64::LD1Twov4h;
6117 Opc = AArch64::LD1Twov8h;
6119 Opc = AArch64::LD1Twov2s;
6121 Opc = AArch64::LD1Twov4s;
6123 Opc = AArch64::LD1Twov2d;
6124 else if (Ty ==
S64 || Ty == P0)
6125 Opc = AArch64::LD1Twov1d;
6128 selectVectorLoadIntrinsic(
Opc, 2,
I);
6131 case Intrinsic::aarch64_neon_ld1x3: {
6132 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6135 Opc = AArch64::LD1Threev8b;
6137 Opc = AArch64::LD1Threev16b;
6139 Opc = AArch64::LD1Threev4h;
6141 Opc = AArch64::LD1Threev8h;
6143 Opc = AArch64::LD1Threev2s;
6145 Opc = AArch64::LD1Threev4s;
6147 Opc = AArch64::LD1Threev2d;
6148 else if (Ty ==
S64 || Ty == P0)
6149 Opc = AArch64::LD1Threev1d;
6152 selectVectorLoadIntrinsic(
Opc, 3,
I);
6155 case Intrinsic::aarch64_neon_ld1x4: {
6156 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6159 Opc = AArch64::LD1Fourv8b;
6161 Opc = AArch64::LD1Fourv16b;
6163 Opc = AArch64::LD1Fourv4h;
6165 Opc = AArch64::LD1Fourv8h;
6167 Opc = AArch64::LD1Fourv2s;
6169 Opc = AArch64::LD1Fourv4s;
6171 Opc = AArch64::LD1Fourv2d;
6172 else if (Ty ==
S64 || Ty == P0)
6173 Opc = AArch64::LD1Fourv1d;
6176 selectVectorLoadIntrinsic(
Opc, 4,
I);
6179 case Intrinsic::aarch64_neon_ld2: {
6180 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6183 Opc = AArch64::LD2Twov8b;
6185 Opc = AArch64::LD2Twov16b;
6187 Opc = AArch64::LD2Twov4h;
6189 Opc = AArch64::LD2Twov8h;
6191 Opc = AArch64::LD2Twov2s;
6193 Opc = AArch64::LD2Twov4s;
6195 Opc = AArch64::LD2Twov2d;
6196 else if (Ty ==
S64 || Ty == P0)
6197 Opc = AArch64::LD1Twov1d;
6200 selectVectorLoadIntrinsic(
Opc, 2,
I);
6203 case Intrinsic::aarch64_neon_ld2lane: {
6204 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6207 Opc = AArch64::LD2i8;
6209 Opc = AArch64::LD2i16;
6211 Opc = AArch64::LD2i32;
6214 Opc = AArch64::LD2i64;
6217 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6221 case Intrinsic::aarch64_neon_ld2r: {
6222 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6225 Opc = AArch64::LD2Rv8b;
6227 Opc = AArch64::LD2Rv16b;
6229 Opc = AArch64::LD2Rv4h;
6231 Opc = AArch64::LD2Rv8h;
6233 Opc = AArch64::LD2Rv2s;
6235 Opc = AArch64::LD2Rv4s;
6237 Opc = AArch64::LD2Rv2d;
6238 else if (Ty ==
S64 || Ty == P0)
6239 Opc = AArch64::LD2Rv1d;
6242 selectVectorLoadIntrinsic(
Opc, 2,
I);
6245 case Intrinsic::aarch64_neon_ld3: {
6246 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6249 Opc = AArch64::LD3Threev8b;
6251 Opc = AArch64::LD3Threev16b;
6253 Opc = AArch64::LD3Threev4h;
6255 Opc = AArch64::LD3Threev8h;
6257 Opc = AArch64::LD3Threev2s;
6259 Opc = AArch64::LD3Threev4s;
6261 Opc = AArch64::LD3Threev2d;
6262 else if (Ty ==
S64 || Ty == P0)
6263 Opc = AArch64::LD1Threev1d;
6266 selectVectorLoadIntrinsic(
Opc, 3,
I);
6269 case Intrinsic::aarch64_neon_ld3lane: {
6270 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6273 Opc = AArch64::LD3i8;
6275 Opc = AArch64::LD3i16;
6277 Opc = AArch64::LD3i32;
6280 Opc = AArch64::LD3i64;
6283 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6287 case Intrinsic::aarch64_neon_ld3r: {
6288 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6291 Opc = AArch64::LD3Rv8b;
6293 Opc = AArch64::LD3Rv16b;
6295 Opc = AArch64::LD3Rv4h;
6297 Opc = AArch64::LD3Rv8h;
6299 Opc = AArch64::LD3Rv2s;
6301 Opc = AArch64::LD3Rv4s;
6303 Opc = AArch64::LD3Rv2d;
6304 else if (Ty ==
S64 || Ty == P0)
6305 Opc = AArch64::LD3Rv1d;
6308 selectVectorLoadIntrinsic(
Opc, 3,
I);
6311 case Intrinsic::aarch64_neon_ld4: {
6312 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6315 Opc = AArch64::LD4Fourv8b;
6317 Opc = AArch64::LD4Fourv16b;
6319 Opc = AArch64::LD4Fourv4h;
6321 Opc = AArch64::LD4Fourv8h;
6323 Opc = AArch64::LD4Fourv2s;
6325 Opc = AArch64::LD4Fourv4s;
6327 Opc = AArch64::LD4Fourv2d;
6328 else if (Ty ==
S64 || Ty == P0)
6329 Opc = AArch64::LD1Fourv1d;
6332 selectVectorLoadIntrinsic(
Opc, 4,
I);
6335 case Intrinsic::aarch64_neon_ld4lane: {
6336 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6339 Opc = AArch64::LD4i8;
6341 Opc = AArch64::LD4i16;
6343 Opc = AArch64::LD4i32;
6346 Opc = AArch64::LD4i64;
6349 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6353 case Intrinsic::aarch64_neon_ld4r: {
6354 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6357 Opc = AArch64::LD4Rv8b;
6359 Opc = AArch64::LD4Rv16b;
6361 Opc = AArch64::LD4Rv4h;
6363 Opc = AArch64::LD4Rv8h;
6365 Opc = AArch64::LD4Rv2s;
6367 Opc = AArch64::LD4Rv4s;
6369 Opc = AArch64::LD4Rv2d;
6370 else if (Ty ==
S64 || Ty == P0)
6371 Opc = AArch64::LD4Rv1d;
6374 selectVectorLoadIntrinsic(
Opc, 4,
I);
6377 case Intrinsic::aarch64_neon_st1x2: {
6378 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6381 Opc = AArch64::ST1Twov8b;
6383 Opc = AArch64::ST1Twov16b;
6385 Opc = AArch64::ST1Twov4h;
6387 Opc = AArch64::ST1Twov8h;
6389 Opc = AArch64::ST1Twov2s;
6391 Opc = AArch64::ST1Twov4s;
6393 Opc = AArch64::ST1Twov2d;
6394 else if (Ty ==
S64 || Ty == P0)
6395 Opc = AArch64::ST1Twov1d;
6398 selectVectorStoreIntrinsic(
I, 2,
Opc);
6401 case Intrinsic::aarch64_neon_st1x3: {
6402 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6405 Opc = AArch64::ST1Threev8b;
6407 Opc = AArch64::ST1Threev16b;
6409 Opc = AArch64::ST1Threev4h;
6411 Opc = AArch64::ST1Threev8h;
6413 Opc = AArch64::ST1Threev2s;
6415 Opc = AArch64::ST1Threev4s;
6417 Opc = AArch64::ST1Threev2d;
6418 else if (Ty ==
S64 || Ty == P0)
6419 Opc = AArch64::ST1Threev1d;
6422 selectVectorStoreIntrinsic(
I, 3,
Opc);
6425 case Intrinsic::aarch64_neon_st1x4: {
6426 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6429 Opc = AArch64::ST1Fourv8b;
6431 Opc = AArch64::ST1Fourv16b;
6433 Opc = AArch64::ST1Fourv4h;
6435 Opc = AArch64::ST1Fourv8h;
6437 Opc = AArch64::ST1Fourv2s;
6439 Opc = AArch64::ST1Fourv4s;
6441 Opc = AArch64::ST1Fourv2d;
6442 else if (Ty ==
S64 || Ty == P0)
6443 Opc = AArch64::ST1Fourv1d;
6446 selectVectorStoreIntrinsic(
I, 4,
Opc);
6449 case Intrinsic::aarch64_neon_st2: {
6450 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6453 Opc = AArch64::ST2Twov8b;
6455 Opc = AArch64::ST2Twov16b;
6457 Opc = AArch64::ST2Twov4h;
6459 Opc = AArch64::ST2Twov8h;
6461 Opc = AArch64::ST2Twov2s;
6463 Opc = AArch64::ST2Twov4s;
6465 Opc = AArch64::ST2Twov2d;
6466 else if (Ty ==
S64 || Ty == P0)
6467 Opc = AArch64::ST1Twov1d;
6470 selectVectorStoreIntrinsic(
I, 2,
Opc);
6473 case Intrinsic::aarch64_neon_st3: {
6474 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6477 Opc = AArch64::ST3Threev8b;
6479 Opc = AArch64::ST3Threev16b;
6481 Opc = AArch64::ST3Threev4h;
6483 Opc = AArch64::ST3Threev8h;
6485 Opc = AArch64::ST3Threev2s;
6487 Opc = AArch64::ST3Threev4s;
6489 Opc = AArch64::ST3Threev2d;
6490 else if (Ty ==
S64 || Ty == P0)
6491 Opc = AArch64::ST1Threev1d;
6494 selectVectorStoreIntrinsic(
I, 3,
Opc);
6497 case Intrinsic::aarch64_neon_st4: {
6498 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6501 Opc = AArch64::ST4Fourv8b;
6503 Opc = AArch64::ST4Fourv16b;
6505 Opc = AArch64::ST4Fourv4h;
6507 Opc = AArch64::ST4Fourv8h;
6509 Opc = AArch64::ST4Fourv2s;
6511 Opc = AArch64::ST4Fourv4s;
6513 Opc = AArch64::ST4Fourv2d;
6514 else if (Ty ==
S64 || Ty == P0)
6515 Opc = AArch64::ST1Fourv1d;
6518 selectVectorStoreIntrinsic(
I, 4,
Opc);
6521 case Intrinsic::aarch64_neon_st2lane: {
6522 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6525 Opc = AArch64::ST2i8;
6527 Opc = AArch64::ST2i16;
6529 Opc = AArch64::ST2i32;
6532 Opc = AArch64::ST2i64;
6535 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6539 case Intrinsic::aarch64_neon_st3lane: {
6540 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6543 Opc = AArch64::ST3i8;
6545 Opc = AArch64::ST3i16;
6547 Opc = AArch64::ST3i32;
6550 Opc = AArch64::ST3i64;
6553 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6557 case Intrinsic::aarch64_neon_st4lane: {
6558 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6561 Opc = AArch64::ST4i8;
6563 Opc = AArch64::ST4i16;
6565 Opc = AArch64::ST4i32;
6568 Opc = AArch64::ST4i64;
6571 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6575 case Intrinsic::aarch64_mops_memset_tag: {
6588 Register DstDef =
I.getOperand(0).getReg();
6590 Register DstUse =
I.getOperand(2).getReg();
6591 Register ValUse =
I.getOperand(3).getReg();
6592 Register SizeUse =
I.getOperand(4).getReg();
6599 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6600 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6605 case Intrinsic::ptrauth_resign_load_relative: {
6606 Register DstReg =
I.getOperand(0).getReg();
6607 Register ValReg =
I.getOperand(2).getReg();
6608 uint64_t AUTKey =
I.getOperand(3).getImm();
6609 Register AUTDisc =
I.getOperand(4).getReg();
6610 uint64_t PACKey =
I.getOperand(5).getImm();
6611 Register PACDisc =
I.getOperand(6).getReg();
6612 int64_t Addend =
I.getOperand(7).getImm();
6615 uint16_t AUTConstDiscC = 0;
6616 std::tie(AUTConstDiscC, AUTAddrDisc) =
6620 uint16_t PACConstDiscC = 0;
6621 std::tie(PACConstDiscC, PACAddrDisc) =
6624 MIB.
buildCopy({AArch64::X16}, {ValReg});
6638 I.eraseFromParent();
6643 I.eraseFromParent();
6647bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6648 MachineRegisterInfo &MRI) {
6654 case Intrinsic::ptrauth_resign: {
6655 Register DstReg =
I.getOperand(0).getReg();
6656 Register ValReg =
I.getOperand(2).getReg();
6657 uint64_t AUTKey =
I.getOperand(3).getImm();
6658 Register AUTDisc =
I.getOperand(4).getReg();
6659 uint64_t PACKey =
I.getOperand(5).getImm();
6660 Register PACDisc =
I.getOperand(6).getReg();
6663 uint16_t AUTConstDiscC = 0;
6664 std::tie(AUTConstDiscC, AUTAddrDisc) =
6668 uint16_t PACConstDiscC = 0;
6669 std::tie(PACConstDiscC, PACAddrDisc) =
6672 MIB.
buildCopy({AArch64::X16}, {ValReg});
6673 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6685 I.eraseFromParent();
6688 case Intrinsic::ptrauth_auth: {
6689 Register DstReg =
I.getOperand(0).getReg();
6690 Register ValReg =
I.getOperand(2).getReg();
6691 uint64_t AUTKey =
I.getOperand(3).getImm();
6692 Register AUTDisc =
I.getOperand(4).getReg();
6695 uint16_t AUTConstDiscC = 0;
6696 std::tie(AUTConstDiscC, AUTAddrDisc) =
6700 MIB.
buildCopy({AArch64::X16}, {ValReg});
6701 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6722 I.eraseFromParent();
6725 case Intrinsic::frameaddress:
6726 case Intrinsic::returnaddress: {
6727 MachineFunction &MF = *
I.getParent()->getParent();
6730 unsigned Depth =
I.getOperand(2).getImm();
6731 Register DstReg =
I.getOperand(0).getReg();
6734 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6735 if (!MFReturnAddr) {
6740 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6743 if (STI.hasPAuth()) {
6744 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6751 I.eraseFromParent();
6760 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6762 FrameAddr = NextFrame;
6765 if (IntrinID == Intrinsic::frameaddress)
6770 if (STI.hasPAuth()) {
6772 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6773 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6782 I.eraseFromParent();
6785 case Intrinsic::aarch64_neon_tbl2:
6786 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6788 case Intrinsic::aarch64_neon_tbl3:
6789 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6792 case Intrinsic::aarch64_neon_tbl4:
6793 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6795 case Intrinsic::aarch64_neon_tbx2:
6796 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6798 case Intrinsic::aarch64_neon_tbx3:
6799 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6801 case Intrinsic::aarch64_neon_tbx4:
6802 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6804 case Intrinsic::swift_async_context_addr:
6805 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6812 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6813 I.eraseFromParent();
6848bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6849 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6850 Register DefReg =
I.getOperand(0).getReg();
6851 Register Addr =
I.getOperand(1).getReg();
6852 uint64_t
Key =
I.getOperand(2).getImm();
6853 Register AddrDisc =
I.getOperand(3).getReg();
6854 uint64_t Disc =
I.getOperand(4).getImm();
6864 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6880 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6892 const GlobalValue *GV;
6903 MachineIRBuilder MIB(
I);
6909 "unsupported non-GOT op flags on ptrauth global reference");
6911 "unsupported non-GOT reference to weak ptrauth global");
6914 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6921 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6922 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6923 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6926 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6931 I.eraseFromParent();
6943 "unsupported non-zero offset in weak ptrauth global reference");
6948 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6949 .addGlobalAddress(GV,
Offset)
6954 I.eraseFromParent();
6958void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
6959 MachineRegisterInfo &MRI,
6960 unsigned NumVec,
unsigned Opc1,
6961 unsigned Opc2,
bool isExt) {
6962 Register DstReg =
I.getOperand(0).getReg();
6967 for (
unsigned i = 0; i < NumVec; i++)
6968 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6971 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
6972 MachineInstrBuilder
Instr;
6979 I.eraseFromParent();
6982InstructionSelector::ComplexRendererFns
6983AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
6985 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6986 return std::nullopt;
6987 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
6988 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
6991InstructionSelector::ComplexRendererFns
6992AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
6994 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6995 return std::nullopt;
6996 uint64_t Enc = 31 - *MaybeImmed;
6997 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7000InstructionSelector::ComplexRendererFns
7001AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7003 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7004 return std::nullopt;
7005 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7006 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7009InstructionSelector::ComplexRendererFns
7010AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7012 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7013 return std::nullopt;
7014 uint64_t Enc = 63 - *MaybeImmed;
7015 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7023InstructionSelector::ComplexRendererFns
7024AArch64InstructionSelector::select12BitValueWithLeftShift(
7025 uint64_t Immed)
const {
7027 if (Immed >> 12 == 0) {
7029 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7031 Immed = Immed >> 12;
7033 return std::nullopt;
7037 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7038 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7045InstructionSelector::ComplexRendererFns
7046AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7053 if (MaybeImmed == std::nullopt)
7054 return std::nullopt;
7055 return select12BitValueWithLeftShift(*MaybeImmed);
7060InstructionSelector::ComplexRendererFns
7061AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7065 return std::nullopt;
7067 if (MaybeImmed == std::nullopt)
7068 return std::nullopt;
7069 uint64_t Immed = *MaybeImmed;
7075 return std::nullopt;
7081 Immed = ~((uint32_t)Immed) + 1;
7083 Immed = ~Immed + 1ULL;
7085 if (Immed & 0xFFFFFFFFFF000000ULL)
7086 return std::nullopt;
7088 Immed &= 0xFFFFFFULL;
7089 return select12BitValueWithLeftShift(Immed);
7106std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7107 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7108 if (
MI.getOpcode() == AArch64::G_SHL) {
7112 MI.getOperand(2).getReg(), MRI)) {
7113 const APInt ShiftVal = ValAndVeg->Value;
7116 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7119 return std::nullopt;
7127bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7128 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7129 bool IsAddrOperand)
const {
7134 MI.getParent()->getParent()->getFunction().hasOptSize())
7137 if (IsAddrOperand) {
7139 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7143 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7144 MachineInstr *OffsetInst =
7150 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7161 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7164InstructionSelector::ComplexRendererFns
7165AArch64InstructionSelector::selectExtendedSHL(
7166 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7167 unsigned SizeInBytes,
bool WantsExt)
const {
7168 assert(
Base.isReg() &&
"Expected base to be a register operand");
7169 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7174 unsigned OffsetOpc = OffsetInst->
getOpcode();
7175 bool LookedThroughZExt =
false;
7176 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7178 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7179 return std::nullopt;
7183 LookedThroughZExt =
true;
7185 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7186 return std::nullopt;
7189 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7190 if (LegalShiftVal == 0)
7191 return std::nullopt;
7192 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7193 return std::nullopt;
7204 if (OffsetOpc == TargetOpcode::G_SHL)
7205 return std::nullopt;
7211 return std::nullopt;
7216 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7220 if (OffsetOpc == TargetOpcode::G_MUL) {
7222 return std::nullopt;
7228 if ((ImmVal & 0x7) != ImmVal)
7229 return std::nullopt;
7233 if (ImmVal != LegalShiftVal)
7234 return std::nullopt;
7236 unsigned SignExtend = 0;
7240 if (!LookedThroughZExt) {
7242 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7244 return std::nullopt;
7249 return std::nullopt;
7255 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7260 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7261 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7262 [=](MachineInstrBuilder &MIB) {
7265 MIB.addImm(SignExtend);
7278InstructionSelector::ComplexRendererFns
7279AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7280 MachineOperand &Root,
unsigned SizeInBytes)
const {
7282 return std::nullopt;
7297 MachineInstr *PtrAdd =
7299 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7300 return std::nullopt;
7304 MachineInstr *OffsetInst =
7306 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7319InstructionSelector::ComplexRendererFns
7320AArch64InstructionSelector::selectAddrModeRegisterOffset(
7321 MachineOperand &Root)
const {
7326 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7327 return std::nullopt;
7333 return std::nullopt;
7336 return {{[=](MachineInstrBuilder &MIB) {
7339 [=](MachineInstrBuilder &MIB) {
7342 [=](MachineInstrBuilder &MIB) {
7352InstructionSelector::ComplexRendererFns
7353AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7354 unsigned SizeInBytes)
const {
7357 return std::nullopt;
7358 MachineInstr *PtrAdd =
7361 return std::nullopt;
7379 unsigned Scale =
Log2_32(SizeInBytes);
7380 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7384 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7385 ImmOff < (0x1000 << Scale))
7386 return std::nullopt;
7391 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7395 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7401 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7402 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7407 return std::nullopt;
7411 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7417 return selectAddrModeRegisterOffset(Root);
7426InstructionSelector::ComplexRendererFns
7427AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7428 unsigned SizeInBytes)
const {
7431 MachineInstr *PtrAdd =
7433 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7434 return std::nullopt;
7455 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7464 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7465 return std::nullopt;
7469 getExtendTypeForInst(*OffsetInst, MRI,
true);
7471 return std::nullopt;
7474 MachineIRBuilder MIB(*PtrAdd);
7476 AArch64::GPR32RegClass, MIB);
7480 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7481 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7482 [=](MachineInstrBuilder &MIB) {
7483 MIB.addImm(SignExtend);
7493InstructionSelector::ComplexRendererFns
7494AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7495 unsigned Size)
const {
7496 MachineRegisterInfo &MRI =
7500 return std::nullopt;
7502 if (!isBaseWithConstantOffset(Root, MRI))
7503 return std::nullopt;
7507 MachineOperand &OffImm = RootDef->
getOperand(2);
7508 if (!OffImm.
isReg())
7509 return std::nullopt;
7511 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7512 return std::nullopt;
7514 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7516 return std::nullopt;
7519 if (RHSC >= -256 && RHSC < 256) {
7522 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7523 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7526 return std::nullopt;
7529InstructionSelector::ComplexRendererFns
7530AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7532 MachineRegisterInfo &MRI)
const {
7533 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7534 return std::nullopt;
7537 return std::nullopt;
7542 return std::nullopt;
7546 return std::nullopt;
7550 return std::nullopt;
7553 MachineIRBuilder MIRBuilder(RootDef);
7555 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7556 [=](MachineInstrBuilder &MIB) {
7557 MIB.addGlobalAddress(GV,
Offset,
7566InstructionSelector::ComplexRendererFns
7567AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7568 unsigned Size)
const {
7573 return std::nullopt;
7576 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7578 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7579 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7587 MachineInstr *RootParent = Root.
getParent();
7589 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7591 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7596 if (isBaseWithConstantOffset(Root, MRI)) {
7604 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7605 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7607 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7608 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7612 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7613 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7620 if (selectAddrModeUnscaled(Root,
Size))
7621 return std::nullopt;
7624 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7625 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7632 switch (
MI.getOpcode()) {
7635 case TargetOpcode::G_SHL:
7637 case TargetOpcode::G_LSHR:
7639 case TargetOpcode::G_ASHR:
7641 case TargetOpcode::G_ROTR:
7648InstructionSelector::ComplexRendererFns
7649AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7650 bool AllowROR)
const {
7652 return std::nullopt;
7653 MachineRegisterInfo &MRI =
7661 return std::nullopt;
7663 return std::nullopt;
7664 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7665 return std::nullopt;
7668 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7671 return std::nullopt;
7675 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7679 unsigned Val = *Immed & (NumBits - 1);
7682 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7683 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7687 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7688 unsigned Opc =
MI.getOpcode();
7691 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7693 if (
Opc == TargetOpcode::G_SEXT)
7696 Size =
MI.getOperand(2).getImm();
7697 assert(
Size != 64 &&
"Extend from 64 bits?");
7710 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7712 assert(
Size != 64 &&
"Extend from 64 bits?");
7727 if (
Opc != TargetOpcode::G_AND)
7733 uint64_t AndMask = *MaybeAndMask;
7746Register AArch64InstructionSelector::moveScalarRegClass(
7747 Register Reg,
const TargetRegisterClass &RC, MachineIRBuilder &MIB)
const {
7748 MachineRegisterInfo &MRI = *MIB.
getMRI();
7758 return Copy.getReg(0);
7763InstructionSelector::ComplexRendererFns
7764AArch64InstructionSelector::selectArithExtendedRegister(
7765 MachineOperand &Root)
const {
7767 return std::nullopt;
7768 MachineRegisterInfo &MRI =
7771 uint64_t ShiftVal = 0;
7776 return std::nullopt;
7778 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7779 return std::nullopt;
7782 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7787 return std::nullopt;
7788 ShiftVal = *MaybeShiftVal;
7790 return std::nullopt;
7795 return std::nullopt;
7796 Ext = getExtendTypeForInst(*ExtDef, MRI);
7798 return std::nullopt;
7802 Ext = getExtendTypeForInst(*RootDef, MRI);
7804 return std::nullopt;
7812 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7813 if (isDef32(*ExtInst))
7814 return std::nullopt;
7820 MachineIRBuilder MIB(*RootDef);
7821 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7823 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7824 [=](MachineInstrBuilder &MIB) {
7825 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7829InstructionSelector::ComplexRendererFns
7830AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7832 return std::nullopt;
7833 MachineRegisterInfo &MRI =
7837 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7842 return std::nullopt;
7844 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7847 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7850 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7855 LaneIdx->Value.getSExtValue() == 1) {
7857 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7861 return std::nullopt;
7864InstructionSelector::ComplexRendererFns
7865AArch64InstructionSelector::selectCVTFixedPointVecBase(
7866 const MachineOperand &Root)
const {
7868 return std::nullopt;
7869 const MachineRegisterInfo &MRI =
7874 return std::nullopt;
7875 std::optional<ValueAndVReg> CstVal =
7878 return std::nullopt;
7884 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7887 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7890 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7893 return std::nullopt;
7897 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7899 return std::nullopt;
7902InstructionSelector::ComplexRendererFns
7903AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
7904 return selectCVTFixedPointVecBase(Root);
7907void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
7908 const MachineInstr &
MI,
7913 InstructionSelector::ComplexRendererFns Renderer =
7914 selectCVTFixedPointVecBase(
MI.getOperand(2));
7915 assert((Renderer && Renderer->size() == 1) &&
7916 "Expected selectCVTFixedPointVec to provide a function\n");
7917 (Renderer->front())(MIB);
7920void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7921 const MachineInstr &
MI,
7923 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
7924 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7925 "Expected G_CONSTANT");
7926 std::optional<int64_t> CstVal =
7928 assert(CstVal &&
"Expected constant value");
7932void AArch64InstructionSelector::renderLogicalImm32(
7933 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7934 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7935 "Expected G_CONSTANT");
7936 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7941void AArch64InstructionSelector::renderLogicalImm64(
7942 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
7943 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT &&
OpIdx == -1 &&
7944 "Expected G_CONSTANT");
7945 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7950void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7951 const MachineInstr &
MI,
7953 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP &&
OpIdx == 0 &&
7954 "Expected G_UBSANTRAP");
7955 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7958void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7959 const MachineInstr &
MI,
7961 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7962 "Expected G_FCONSTANT");
7967void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7968 const MachineInstr &
MI,
7970 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7971 "Expected G_FCONSTANT");
7976void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7977 const MachineInstr &
MI,
7979 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7980 "Expected G_FCONSTANT");
7985void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7986 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7987 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT &&
OpIdx == -1 &&
7988 "Expected G_FCONSTANT");
7996bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7997 const MachineInstr &
MI,
unsigned NumBytes)
const {
7998 if (!
MI.mayLoadOrStore())
8001 "Expected load/store to have only one mem op!");
8002 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8005bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8006 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8014 switch (
MI.getOpcode()) {
8017 case TargetOpcode::COPY:
8018 case TargetOpcode::G_BITCAST:
8019 case TargetOpcode::G_TRUNC:
8020 case TargetOpcode::G_PHI:
8030 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8033 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8051 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8056 MO.setReg(Copy.getReg(0));
8061void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
8065 for (
auto &BB : MF) {
8066 for (
auto &
MI : BB) {
8067 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8072 for (
auto *
MI : Phis) {
8094 bool HasGPROp =
false, HasFPROp =
false;
8098 const LLT &Ty = MRI.
getType(MO.getReg());
8108 if (RB->
getID() == AArch64::GPRRegBankID)
8114 if (HasGPROp && HasFPROp)
8120InstructionSelector *
8124 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
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.