46#include "llvm/IR/IntrinsicsAArch64.h"
53#define DEBUG_TYPE "aarch64-isel"
66#define GET_GLOBALISEL_PREDICATE_BITSET
67#include "AArch64GenGlobalISel.inc"
68#undef GET_GLOBALISEL_PREDICATE_BITSET
88 ProduceNonFlagSettingCondBr =
136 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
203 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
205 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
207 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
209 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
226 unsigned Opc1,
unsigned Opc2,
bool isExt);
232 unsigned emitConstantPoolEntry(
const Constant *CPVal,
251 std::optional<CmpInst::Predicate> = std::nullopt)
const;
254 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
255 std::initializer_list<llvm::SrcOp> SrcOps,
257 const ComplexRendererFns &RenderFns = std::nullopt)
const;
292 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
315 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
337 std::pair<MachineInstr *, AArch64CC::CondCode>
372 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
373 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
374 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
375 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
377 template <
unsigned ShiftW
idth>
379 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
381 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
384 unsigned Size)
const;
386 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
387 return selectAddrModeUnscaled(Root, 1);
389 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
390 return selectAddrModeUnscaled(Root, 2);
392 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
393 return selectAddrModeUnscaled(Root, 4);
395 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
396 return selectAddrModeUnscaled(Root, 8);
398 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
399 return selectAddrModeUnscaled(Root, 16);
404 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
408 unsigned Size)
const;
410 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
411 return selectAddrModeIndexed(Root, Width / 8);
420 bool IsAddrOperand)
const;
423 unsigned SizeInBytes)
const;
431 bool WantsExt)
const;
432 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
434 unsigned SizeInBytes)
const;
436 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
437 return selectAddrModeXRO(Root, Width / 8);
441 unsigned SizeInBytes)
const;
443 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
444 return selectAddrModeWRO(Root, Width / 8);
448 bool AllowROR =
false)
const;
450 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
451 return selectShiftedRegister(Root);
454 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
455 return selectShiftedRegister(Root,
true);
465 bool IsLoadStore =
false)
const;
476 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
479 template <
unsigned W
idth>
480 ComplexRendererFns selectCVTFixedPoint(
MachineOperand &Root)
const;
481 template <
unsigned W
idth>
482 ComplexRendererFns selectCVTFixedPosRecipOperand(
MachineOperand &Root)
const;
483 ComplexRendererFns selectCVTFixedPointBase(
const MachineOperand &Root,
485 bool isReciprocal =
false)
const;
486 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
491 unsigned getFixedPointWidthFromOperand(
const MachineOperand &Root)
const;
493 int OpIdx = -1)
const;
497 unsigned Width,
bool isReciprocal)
const;
499 int OpIdx = -1)
const;
501 int OpIdx = -1)
const;
503 int OpIdx = -1)
const;
507 int OpIdx = -1)
const;
509 int OpIdx = -1)
const;
511 int OpIdx = -1)
const;
514 int OpIdx = -1)
const;
520 bool tryOptSelect(
GSelect &Sel);
527 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
540 bool ProduceNonFlagSettingCondBr =
false;
549#define GET_GLOBALISEL_PREDICATES_DECL
550#include "AArch64GenGlobalISel.inc"
551#undef GET_GLOBALISEL_PREDICATES_DECL
555#define GET_GLOBALISEL_TEMPORARIES_DECL
556#include "AArch64GenGlobalISel.inc"
557#undef GET_GLOBALISEL_TEMPORARIES_DECL
562#define GET_GLOBALISEL_IMPL
563#include "AArch64GenGlobalISel.inc"
564#undef GET_GLOBALISEL_IMPL
566AArch64InstructionSelector::AArch64InstructionSelector(
569 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
572#include
"AArch64GenGlobalISel.inc"
575#include
"AArch64GenGlobalISel.inc"
587 bool GetAllRegSet =
false) {
588 if (RB.
getID() == AArch64::GPRRegBankID) {
589 if (Ty.getSizeInBits() <= 32)
590 return GetAllRegSet ? &AArch64::GPR32allRegClass
591 : &AArch64::GPR32RegClass;
592 if (Ty.getSizeInBits() == 64)
593 return GetAllRegSet ? &AArch64::GPR64allRegClass
594 : &AArch64::GPR64RegClass;
595 if (Ty.getSizeInBits() == 128)
596 return &AArch64::XSeqPairsClassRegClass;
600 if (RB.
getID() == AArch64::FPRRegBankID) {
601 switch (Ty.getSizeInBits()) {
603 return &AArch64::FPR8RegClass;
605 return &AArch64::FPR16RegClass;
607 return &AArch64::FPR32RegClass;
609 return &AArch64::FPR64RegClass;
611 return &AArch64::FPR128RegClass;
623 bool GetAllRegSet =
false) {
626 "Expected FPR regbank for scalable type size");
627 return &AArch64::ZPRRegClass;
630 unsigned RegBankID = RB.
getID();
632 if (RegBankID == AArch64::GPRRegBankID) {
634 if (SizeInBits <= 32)
635 return GetAllRegSet ? &AArch64::GPR32allRegClass
636 : &AArch64::GPR32RegClass;
637 if (SizeInBits == 64)
638 return GetAllRegSet ? &AArch64::GPR64allRegClass
639 : &AArch64::GPR64RegClass;
640 if (SizeInBits == 128)
641 return &AArch64::XSeqPairsClassRegClass;
644 if (RegBankID == AArch64::FPRRegBankID) {
647 "Unexpected scalable register size");
648 return &AArch64::ZPRRegClass;
651 switch (SizeInBits) {
655 return &AArch64::FPR8RegClass;
657 return &AArch64::FPR16RegClass;
659 return &AArch64::FPR32RegClass;
661 return &AArch64::FPR64RegClass;
663 return &AArch64::FPR128RegClass;
673 switch (
TRI.getRegSizeInBits(*RC)) {
675 SubReg = AArch64::bsub;
678 SubReg = AArch64::hsub;
681 if (RC != &AArch64::FPR32RegClass)
682 SubReg = AArch64::sub_32;
684 SubReg = AArch64::ssub;
687 SubReg = AArch64::dsub;
691 dbgs() <<
"Couldn't find appropriate subregister for register class.");
700 switch (RB.
getID()) {
701 case AArch64::GPRRegBankID:
703 case AArch64::FPRRegBankID:
726 const unsigned RegClassIDs[],
728 unsigned NumRegs = Regs.
size();
731 assert(NumRegs >= 2 && NumRegs <= 4 &&
732 "Only support between two and 4 registers in a tuple!");
734 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
736 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
737 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
738 RegSequence.addUse(Regs[
I]);
739 RegSequence.addImm(SubRegs[
I]);
741 return RegSequence.getReg(0);
746 static const unsigned RegClassIDs[] = {
747 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
748 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
749 AArch64::dsub2, AArch64::dsub3};
750 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
755 static const unsigned RegClassIDs[] = {
756 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
757 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
758 AArch64::qsub2, AArch64::qsub3};
759 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
764 auto &
MBB = *
MI.getParent();
765 auto &MF = *
MBB.getParent();
766 auto &MRI = MF.getRegInfo();
772 else if (Root.
isReg()) {
777 Immed = ValAndVReg->Value.getSExtValue();
788 if (RegBankID == AArch64::GPRRegBankID) {
790 switch (GenericOpc) {
791 case TargetOpcode::G_SHL:
792 return AArch64::LSLVWr;
793 case TargetOpcode::G_LSHR:
794 return AArch64::LSRVWr;
795 case TargetOpcode::G_ASHR:
796 return AArch64::ASRVWr;
800 }
else if (OpSize == 64) {
801 switch (GenericOpc) {
802 case TargetOpcode::G_SHL:
803 return AArch64::LSLVXr;
804 case TargetOpcode::G_LSHR:
805 return AArch64::LSRVXr;
806 case TargetOpcode::G_ASHR:
807 return AArch64::ASRVXr;
823 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
825 case AArch64::GPRRegBankID:
828 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
830 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
832 return isStore ? AArch64::STRWui : AArch64::LDRWui;
834 return isStore ? AArch64::STRXui : AArch64::LDRXui;
837 case AArch64::FPRRegBankID:
840 return isStore ? AArch64::STRBui : AArch64::LDRBui;
842 return isStore ? AArch64::STRHui : AArch64::LDRHui;
844 return isStore ? AArch64::STRSui : AArch64::LDRSui;
846 return isStore ? AArch64::STRDui : AArch64::LDRDui;
848 return isStore ? AArch64::STRQui : AArch64::LDRQui;
862 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
863 assert(To &&
"Destination register class cannot be null");
864 assert(SubReg &&
"Expected a valid subregister");
868 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
870 RegOp.
setReg(SubRegCopy.getReg(0));
874 if (!
I.getOperand(0).getReg().isPhysical())
891 if (
Reg.isPhysical())
899 RC = getRegClassForTypeOnBank(Ty, RB);
902 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
915 Register DstReg =
I.getOperand(0).getReg();
916 Register SrcReg =
I.getOperand(1).getReg();
947 if (
I.getOpcode() == TargetOpcode::G_BITCAST &&
949 if (DstRegBank.
getID() == AArch64::FPRRegBankID &&
950 SrcRegBank.
getID() == AArch64::GPRRegBankID) {
959 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::FMOVWSr))
962 I.setDesc(
TII.get(TargetOpcode::COPY));
963 I.getOperand(1).setReg(FPR32);
964 I.getOperand(1).setSubReg(AArch64::hsub);
968 if (DstRegBank.
getID() == AArch64::GPRRegBankID &&
969 SrcRegBank.
getID() == AArch64::FPRRegBankID) {
979 TII.get(TargetOpcode::SUBREG_TO_REG))
983 I.setDesc(
TII.get(AArch64::FMOVSWr));
984 I.getOperand(1).setReg(FPR32);
993 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
997 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
998 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
999 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
1013 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1014 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
1015 }
else if (SrcSize > DstSize) {
1022 }
else if (DstSize > SrcSize) {
1031 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1035 RegOp.
setReg(PromoteReg);
1054 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1055 I.setDesc(
TII.get(AArch64::COPY));
1056 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1060 I.setDesc(
TII.get(AArch64::COPY));
1068 MachineRegisterInfo &MRI = *MIB.
getMRI();
1071 "Expected both select operands to have the same regbank?");
1077 "Expected 32 bit or 64 bit select only?");
1078 const bool Is32Bit =
Size == 32;
1080 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1087 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1089 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1104 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1121 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1140 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1156 auto TryOptSelectCst = [&
Opc, &
True, &
False, &CC, Is32Bit, &MRI,
1162 if (!TrueCst && !FalseCst)
1165 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1166 if (TrueCst && FalseCst) {
1167 int64_t
T = TrueCst->Value.getSExtValue();
1168 int64_t
F = FalseCst->Value.getSExtValue();
1170 if (
T == 0 &&
F == 1) {
1172 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1178 if (
T == 0 &&
F == -1) {
1180 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1188 int64_t
T = TrueCst->Value.getSExtValue();
1191 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1200 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1209 int64_t
F = FalseCst->Value.getSExtValue();
1212 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1219 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1232 return &*SelectInst;
1237 MachineRegisterInfo *MRI =
nullptr) {
1250 if (ValAndVReg && ValAndVReg->Value == 0)
1257 if (ValAndVReg && ValAndVReg->Value == 0)
1361 assert(
Reg.isValid() &&
"Expected valid register!");
1362 bool HasZext =
false;
1364 unsigned Opc =
MI->getOpcode();
1366 if (!
MI->getOperand(0).isReg() ||
1375 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1376 Opc == TargetOpcode::G_TRUNC) {
1377 if (
Opc == TargetOpcode::G_ZEXT)
1380 Register NextReg =
MI->getOperand(1).getReg();
1394 std::optional<uint64_t>
C;
1399 case TargetOpcode::G_AND:
1400 case TargetOpcode::G_XOR: {
1401 TestReg =
MI->getOperand(1).getReg();
1402 Register ConstantReg =
MI->getOperand(2).getReg();
1413 C = VRegAndVal->Value.getZExtValue();
1415 C = VRegAndVal->Value.getSExtValue();
1419 case TargetOpcode::G_ASHR:
1420 case TargetOpcode::G_LSHR:
1421 case TargetOpcode::G_SHL: {
1422 TestReg =
MI->getOperand(1).getReg();
1426 C = VRegAndVal->Value.getSExtValue();
1442 case TargetOpcode::G_AND:
1444 if ((*
C >> Bit) & 1)
1447 case TargetOpcode::G_SHL:
1450 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1455 case TargetOpcode::G_ASHR:
1460 if (Bit >= TestRegSize)
1461 Bit = TestRegSize - 1;
1463 case TargetOpcode::G_LSHR:
1465 if ((Bit + *
C) < TestRegSize) {
1470 case TargetOpcode::G_XOR:
1479 if ((*
C >> Bit) & 1)
1494MachineInstr *AArch64InstructionSelector::emitTestBit(
1495 Register TestReg,
uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1496 MachineIRBuilder &MIB)
const {
1498 assert(ProduceNonFlagSettingCondBr &&
1499 "Cannot emit TB(N)Z with speculation tracking!");
1500 MachineRegisterInfo &MRI = *MIB.
getMRI();
1504 LLT Ty = MRI.
getType(TestReg);
1507 assert(Bit < 64 &&
"Bit is too large!");
1511 bool UseWReg =
Bit < 32;
1512 unsigned NecessarySize = UseWReg ? 32 : 64;
1513 if (
Size != NecessarySize)
1514 TestReg = moveScalarRegClass(
1515 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1518 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1519 {AArch64::TBZW, AArch64::TBNZW}};
1520 unsigned Opc = OpcTable[UseWReg][IsNegative];
1527bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1528 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1529 MachineIRBuilder &MIB)
const {
1530 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1557 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1564 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1568MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1570 MachineBasicBlock *DestMBB,
1571 MachineIRBuilder &MIB)
const {
1572 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1573 MachineRegisterInfo &MRI = *MIB.
getMRI();
1575 AArch64::GPRRegBankID &&
1576 "Expected GPRs only?");
1577 auto Ty = MRI.
getType(CompareReg);
1580 assert(Width <= 64 &&
"Expected width to be at most 64?");
1581 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1582 {AArch64::CBNZW, AArch64::CBNZX}};
1583 unsigned Opc = OpcTable[IsNegative][Width == 64];
1584 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1589bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1590 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1592 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1600 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1604 I.eraseFromParent();
1608bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1609 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1611 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1617 if (!ProduceNonFlagSettingCondBr)
1620 MachineRegisterInfo &MRI = *MIB.
getMRI();
1621 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1636 if (VRegAndVal && !AndInst) {
1637 int64_t
C = VRegAndVal->Value.getSExtValue();
1643 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1644 I.eraseFromParent();
1652 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1653 I.eraseFromParent();
1661 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1662 I.eraseFromParent();
1676 if (VRegAndVal && VRegAndVal->Value == 0) {
1684 tryOptAndIntoCompareBranch(
1686 I.eraseFromParent();
1692 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1694 I.eraseFromParent();
1703bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1704 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1706 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1707 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1711 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1718 I.eraseFromParent();
1722bool AArch64InstructionSelector::selectCompareBranch(
1724 Register CondReg =
I.getOperand(0).getReg();
1725 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1729 if (CCMIOpc == TargetOpcode::G_FCMP)
1730 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1731 if (CCMIOpc == TargetOpcode::G_ICMP)
1732 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1737 if (ProduceNonFlagSettingCondBr) {
1738 emitTestBit(CondReg, 0,
true,
1739 I.getOperand(1).getMBB(), MIB);
1740 I.eraseFromParent();
1750 .
addMBB(
I.getOperand(1).getMBB());
1751 I.eraseFromParent();
1764 return std::nullopt;
1774 return std::nullopt;
1777 if (
Imm >= SrcTy.getElementType().getSizeInBits())
1778 return std::nullopt;
1782bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1783 MachineRegisterInfo &MRI) {
1784 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1785 Register DstReg =
I.getOperand(0).getReg();
1786 const LLT Ty = MRI.
getType(DstReg);
1787 Register Src1Reg =
I.getOperand(1).getReg();
1788 Register Src2Reg =
I.getOperand(2).getReg();
1799 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1801 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1803 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1805 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1807 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1809 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1811 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1823 I.eraseFromParent();
1827bool AArch64InstructionSelector::selectVectorAshrLshr(
1828 MachineInstr &
I, MachineRegisterInfo &MRI) {
1829 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1830 I.getOpcode() == TargetOpcode::G_LSHR);
1831 Register DstReg =
I.getOperand(0).getReg();
1832 const LLT Ty = MRI.
getType(DstReg);
1833 Register Src1Reg =
I.getOperand(1).getReg();
1834 Register Src2Reg =
I.getOperand(2).getReg();
1839 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1849 unsigned NegOpc = 0;
1851 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1853 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1854 NegOpc = AArch64::NEGv2i64;
1856 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1857 NegOpc = AArch64::NEGv4i32;
1859 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1860 NegOpc = AArch64::NEGv2i32;
1862 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1863 NegOpc = AArch64::NEGv4i16;
1865 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1866 NegOpc = AArch64::NEGv8i16;
1868 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1869 NegOpc = AArch64::NEGv16i8;
1871 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1872 NegOpc = AArch64::NEGv8i8;
1878 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1882 I.eraseFromParent();
1886bool AArch64InstructionSelector::selectVaStartAAPCS(
1896 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1898 const auto *PtrRegClass =
1899 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1901 const MCInstrDesc &MCIDAddAddr =
1903 const MCInstrDesc &MCIDStoreAddr =
1915 const auto VAList =
I.getOperand(0).getReg();
1918 unsigned OffsetBytes = 0;
1922 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1924 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1931 const auto *MMO = *
I.memoperands_begin();
1932 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1935 .
addImm(OffsetBytes / PtrSize)
1937 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1941 OffsetBytes += PtrSize;
1957 const auto PushIntConstant = [&](
const int32_t
Value) {
1958 constexpr int IntSize = 4;
1961 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
1966 const auto *MMO = *
I.memoperands_begin();
1967 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
1970 .
addImm(OffsetBytes / IntSize)
1972 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1975 OffsetBytes += IntSize;
1979 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
1982 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
1986 I.eraseFromParent();
1990bool AArch64InstructionSelector::selectVaStartDarwin(
1992 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1993 Register ListReg =
I.getOperand(0).getReg();
1998 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2006 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2014 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2021 I.eraseFromParent();
2025void AArch64InstructionSelector::materializeLargeCMVal(
2026 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2031 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2046 GV, MovZ->getOperand(1).getOffset(), Flags));
2050 MovZ->getOperand(1).getOffset(), Flags));
2056 Register DstReg = BuildMovK(MovZ.getReg(0),
2062bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2067 switch (
I.getOpcode()) {
2068 case TargetOpcode::G_CONSTANT: {
2069 Register DefReg =
I.getOperand(0).getReg();
2070 const LLT DefTy = MRI.
getType(DefReg);
2076 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2077 I.getOperand(1).setCImm(
2082 I.getOperand(0).setReg(WideReg);
2091 if (PtrSize != 32 && PtrSize != 64)
2097 case TargetOpcode::G_STORE: {
2098 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2099 MachineOperand &SrcOp =
I.getOperand(0);
2112 case TargetOpcode::G_PTR_ADD: {
2116 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2118 return convertPtrAddToAdd(
I, MRI);
2120 case TargetOpcode::G_LOAD: {
2125 Register DstReg =
I.getOperand(0).getReg();
2126 const LLT DstTy = MRI.
getType(DstReg);
2132 case TargetOpcode::G_VECREDUCE_ADD:
2133 case TargetOpcode::G_VECREDUCE_SMAX:
2134 case TargetOpcode::G_VECREDUCE_SMIN:
2135 case TargetOpcode::G_VECREDUCE_UMAX:
2136 case TargetOpcode::G_VECREDUCE_UMIN: {
2139 Register DstReg =
I.getOperand(0).getReg();
2140 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2141 if (DstRB.
getID() != AArch64::GPRRegBankID)
2144 LLT DstTy = MRI.
getType(DstReg);
2146 getRegClassForTypeOnBank(DstTy, DstRB,
true);
2152 I.getOperand(0).setReg(FPRDst);
2154 BuildMI(
MBB, std::next(
I.getIterator()), MIMetadata(
I),
2155 TII.get(TargetOpcode::COPY), DstReg)
2159 case TargetOpcode::G_SPLAT_VECTOR: {
2161 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2165 MRI.
setType(
I.getOperand(0).getReg(),
2167 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2168 I.getOperand(1).setReg(NewSrc.getReg(0));
2171 case AArch64::G_INSERT_VECTOR_ELT: {
2172 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2173 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2177 MRI.
setType(
I.getOperand(1).getReg(),
2179 MRI.
setType(
I.getOperand(0).getReg(),
2181 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2182 I.getOperand(2).setReg(NewSrc.getReg(0));
2186 Register EltReg =
I.getOperand(2).getReg();
2187 LLT EltTy = MRI.
getType(EltReg);
2193 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2194 I.getOperand(2).setReg(NewElt.getReg(0));
2199 case TargetOpcode::G_UITOFP:
2200 case TargetOpcode::G_SITOFP: {
2205 Register SrcReg =
I.getOperand(1).getReg();
2206 LLT SrcTy = MRI.
getType(SrcReg);
2207 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2216 I.getOperand(1).setReg(
Copy.getReg(0));
2218 getRegClassForTypeOnBank(
2219 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2221 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2222 I.setDesc(
TII.get(AArch64::G_SITOF));
2224 I.setDesc(
TII.get(AArch64::G_UITOF));
2242bool AArch64InstructionSelector::convertPtrAddToAdd(
2243 MachineInstr &
I, MachineRegisterInfo &MRI) {
2244 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2245 Register DstReg =
I.getOperand(0).getReg();
2246 Register AddOp1Reg =
I.getOperand(1).getReg();
2247 const LLT PtrTy = MRI.
getType(DstReg);
2251 const LLT CastPtrTy = PtrTy.
isVector()
2263 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2264 MRI.
setType(DstReg, CastPtrTy);
2265 I.getOperand(1).setReg(PtrToInt.getReg(0));
2266 if (!select(*PtrToInt)) {
2267 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2276 I.getOperand(2).setReg(NegatedReg);
2277 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2281bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2282 MachineRegisterInfo &MRI) {
2286 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2287 const auto &MO =
I.getOperand(2);
2292 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2296 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2297 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2299 if (!Imm1Fn || !Imm2Fn)
2303 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2304 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2306 for (
auto &RenderFn : *Imm1Fn)
2308 for (
auto &RenderFn : *Imm2Fn)
2311 I.eraseFromParent();
2316bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2317 MachineInstr &
I, MachineRegisterInfo &MRI) {
2318 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2336 LLT DefDstTy = MRI.
getType(DefDstReg);
2337 Register StoreSrcReg =
I.getOperand(0).getReg();
2338 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2354 I.getOperand(0).setReg(DefDstReg);
2358bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2359 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2360 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2366 switch (
I.getOpcode()) {
2367 case TargetOpcode::G_SPLAT_VECTOR: {
2368 Register Dst =
I.getOperand(0).getReg();
2374 Register Src =
I.getOperand(1).getReg();
2376 Src, MRI,
true,
true);
2387 if (!emitConstantVector(Dst, CV,
Imm, MRI))
2389 I.eraseFromParent();
2392 case TargetOpcode::G_SEXT:
2395 if (selectUSMovFromExtend(
I, MRI))
2398 case TargetOpcode::G_BR:
2400 case TargetOpcode::G_SHL:
2401 return earlySelectSHL(
I, MRI);
2402 case TargetOpcode::G_CONSTANT: {
2403 bool IsZero =
false;
2404 if (
I.getOperand(1).isCImm())
2405 IsZero =
I.getOperand(1).getCImm()->isZero();
2406 else if (
I.getOperand(1).isImm())
2407 IsZero =
I.getOperand(1).getImm() == 0;
2412 Register DefReg =
I.getOperand(0).getReg();
2415 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2418 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2423 I.setDesc(
TII.get(TargetOpcode::COPY));
2427 case TargetOpcode::G_ADD: {
2436 Register AddDst =
I.getOperand(0).getReg();
2437 Register AddLHS =
I.getOperand(1).getReg();
2438 Register AddRHS =
I.getOperand(2).getReg();
2448 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2469 MachineInstr *
Cmp = MatchCmp(AddRHS);
2473 Cmp = MatchCmp(AddRHS);
2477 auto &PredOp =
Cmp->getOperand(1);
2479 emitIntegerCompare(
Cmp->getOperand(2),
2480 Cmp->getOperand(3), PredOp, MIB);
2484 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2485 I.eraseFromParent();
2488 case TargetOpcode::G_OR: {
2492 Register Dst =
I.getOperand(0).getReg();
2512 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2515 int64_t Immr =
Size - ShiftImm;
2516 int64_t Imms =
Size - ShiftImm - 1;
2517 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2518 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2519 I.eraseFromParent();
2522 case TargetOpcode::G_FENCE: {
2523 if (
I.getOperand(1).getImm() == 0)
2527 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2528 I.eraseFromParent();
2531 case TargetOpcode::G_BRINDIRECT: {
2533 if (std::optional<uint16_t> BADisc =
2535 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2539 I.eraseFromParent();
2552bool AArch64InstructionSelector::select(MachineInstr &
I) {
2553 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2554 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2560 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2561 if (Subtarget->requiresStrictAlign()) {
2563 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2569 unsigned Opcode =
I.getOpcode();
2571 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2574 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2579 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2580 const Register DefReg =
I.getOperand(0).getReg();
2581 const LLT DefTy = MRI.
getType(DefReg);
2594 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2601 I.setDesc(
TII.get(TargetOpcode::PHI));
2609 if (
I.isDebugInstr())
2616 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2618 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2625 if (preISelLower(
I)) {
2626 Opcode =
I.getOpcode();
2637 if (selectImpl(
I, *CoverageInfo))
2641 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2644 case TargetOpcode::G_SBFX:
2645 case TargetOpcode::G_UBFX: {
2646 static const unsigned OpcTable[2][2] = {
2647 {AArch64::UBFMWri, AArch64::UBFMXri},
2648 {AArch64::SBFMWri, AArch64::SBFMXri}};
2649 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2651 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2654 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2657 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2658 auto LSB = Cst1->Value.getZExtValue();
2659 auto Width = Cst2->Value.getZExtValue();
2663 .
addImm(LSB + Width - 1);
2664 I.eraseFromParent();
2668 case TargetOpcode::G_BRCOND:
2669 return selectCompareBranch(
I, MF, MRI);
2671 case TargetOpcode::G_BRJT:
2672 return selectBrJT(
I, MRI);
2674 case AArch64::G_ADD_LOW: {
2679 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2680 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2681 I.setDesc(
TII.get(AArch64::ADDXri));
2687 "Expected small code model");
2689 auto Op2 =
I.getOperand(2);
2690 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2691 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2692 Op1.getTargetFlags())
2694 Op2.getTargetFlags());
2695 I.eraseFromParent();
2700 case TargetOpcode::G_FCONSTANT: {
2701 const Register DefReg =
I.getOperand(0).getReg();
2702 const LLT DefTy = MRI.
getType(DefReg);
2708 (DefSize == 16 || DefSize == 32 || DefSize == 64 || DefSize == 128) &&
2709 "Unexpected destination size for G_FCONSTANT?");
2712 const ConstantFP *FPImm =
I.getOperand(1).getFPImm();
2713 APInt
Imm = DefSize >= 64
2716 if (
auto *Mov = emitConstantMOVVector(
2717 DefSize >= 64 ? DstOp(DefReg) : DstOp(&AArch64::FPR64RegClass),
Imm,
2720 MIB.
buildInstr(TargetOpcode::COPY, {DefReg}, {})
2721 .addReg(Mov->getOperand(0).getReg(), {},
2722 DefSize == 16 ? AArch64::hsub : AArch64::ssub);
2725 I.eraseFromParent();
2731 bool OptForSize = shouldOptForSize(&MF);
2733 if ((DefSize == 32 || DefSize == 64) &&
2734 TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2738 DefSize == 64 ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass);
2739 MachineOperand &RegOp =
I.getOperand(0);
2745 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2749 MachineOperand &ImmOp =
I.getOperand(1);
2753 const unsigned MovOpc =
2754 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2755 I.setDesc(
TII.get(MovOpc));
2763 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2766 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2767 I.eraseFromParent();
2770 case TargetOpcode::G_EXTRACT: {
2771 Register DstReg =
I.getOperand(0).getReg();
2772 Register SrcReg =
I.getOperand(1).getReg();
2773 LLT SrcTy = MRI.
getType(SrcReg);
2774 LLT DstTy = MRI.
getType(DstReg);
2786 unsigned Offset =
I.getOperand(2).getImm();
2791 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2792 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2795 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2797 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2799 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2801 AArch64::GPR64RegClass, NewI->getOperand(0));
2802 I.eraseFromParent();
2808 unsigned LaneIdx =
Offset / 64;
2809 MachineInstr *Extract = emitExtractVectorElt(
2810 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2813 I.eraseFromParent();
2817 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2818 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2823 "unexpected G_EXTRACT types");
2830 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2831 .addReg(DstReg, {}, AArch64::sub_32);
2833 AArch64::GPR32RegClass, MRI);
2834 I.getOperand(0).setReg(DstReg);
2840 case TargetOpcode::G_INSERT: {
2841 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2842 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2849 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2850 unsigned LSB =
I.getOperand(3).getImm();
2852 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2853 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2857 "unexpected G_INSERT types");
2864 TII.get(AArch64::SUBREG_TO_REG))
2866 .
addUse(
I.getOperand(2).getReg())
2867 .
addImm(AArch64::sub_32);
2869 AArch64::GPR32RegClass, MRI);
2870 I.getOperand(2).setReg(SrcReg);
2875 case TargetOpcode::G_FRAME_INDEX: {
2882 I.setDesc(
TII.get(AArch64::ADDXri));
2892 case TargetOpcode::G_GLOBAL_VALUE: {
2893 const GlobalValue *GV =
nullptr;
2895 if (
I.getOperand(1).isSymbol()) {
2896 OpFlags =
I.getOperand(1).getTargetFlags();
2902 return selectTLSGlobalValue(
I, MRI);
2908 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2909 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2910 I.getOperand(1).setTargetFlags(OpFlags);
2911 I.addImplicitDefUseOperands(MF);
2912 I.setImplicitPhysRegDefsDead();
2916 materializeLargeCMVal(
I, GV, OpFlags);
2917 I.eraseFromParent();
2920 I.setDesc(
TII.get(AArch64::ADR));
2921 I.getOperand(1).setTargetFlags(OpFlags);
2923 I.setDesc(
TII.get(AArch64::MOVaddr));
2925 MachineInstrBuilder MIB(MF,
I);
2926 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2933 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2934 return selectPtrAuthGlobalValue(
I, MRI);
2936 case TargetOpcode::G_ZEXTLOAD:
2937 case TargetOpcode::G_LOAD:
2938 case TargetOpcode::G_STORE: {
2940 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2955 assert(MemSizeInBytes <= 8 &&
2956 "128-bit atomics should already be custom-legalized");
2959 static constexpr unsigned LDAPROpcodes[] = {
2960 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2961 static constexpr unsigned LDAROpcodes[] = {
2962 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2963 ArrayRef<unsigned> Opcodes =
2964 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2967 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2969 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2970 AArch64::STLRW, AArch64::STLRX};
2975 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2976 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2977 I.getOperand(0).setReg(NewVal);
2979 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2987 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2990 "Load/Store pointer operand isn't a GPR");
2992 "Load/Store pointer operand isn't a pointer");
2997 LLT ValTy = MRI.
getType(ValReg);
3002 RB.
getID() == AArch64::FPRRegBankID) {
3005 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3011 .addReg(ValReg, {}, SubReg)
3018 if (RB.
getID() == AArch64::FPRRegBankID) {
3021 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3031 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3034 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3043 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3045 const unsigned NewOpc =
3047 if (NewOpc ==
I.getOpcode())
3051 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3054 I.setDesc(
TII.get(NewOpc));
3060 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3061 Register CurValReg =
I.getOperand(0).getReg();
3062 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3063 NewInst.cloneMemRefs(
I);
3064 for (
auto &Fn : *AddrModeFns)
3066 I.eraseFromParent();
3070 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3075 if (Opcode == TargetOpcode::G_STORE) {
3077 LoadStore->getOperand(0).getReg(), MRI);
3078 if (CVal && CVal->Value == 0) {
3080 case AArch64::STRWui:
3081 case AArch64::STRHHui:
3082 case AArch64::STRBBui:
3083 LoadStore->getOperand(0).setReg(AArch64::WZR);
3085 case AArch64::STRXui:
3086 LoadStore->getOperand(0).setReg(AArch64::XZR);
3092 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3093 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3105 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3107 .
addImm(AArch64::sub_32);
3116 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3117 case TargetOpcode::G_INDEXED_SEXTLOAD:
3118 return selectIndexedExtLoad(
I, MRI);
3119 case TargetOpcode::G_INDEXED_LOAD:
3120 return selectIndexedLoad(
I, MRI);
3121 case TargetOpcode::G_INDEXED_STORE:
3124 case TargetOpcode::G_LSHR:
3125 case TargetOpcode::G_ASHR:
3127 return selectVectorAshrLshr(
I, MRI);
3129 case TargetOpcode::G_SHL: {
3130 if (Opcode == TargetOpcode::G_SHL &&
3132 return selectVectorSHL(
I, MRI);
3139 Register SrcReg =
I.getOperand(1).getReg();
3140 Register ShiftReg =
I.getOperand(2).getReg();
3141 const LLT ShiftTy = MRI.
getType(ShiftReg);
3142 const LLT SrcTy = MRI.
getType(SrcReg);
3147 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3148 .addReg(ShiftReg, {}, AArch64::sub_32);
3150 I.getOperand(2).setReg(Trunc.getReg(0));
3155 const Register DefReg =
I.getOperand(0).getReg();
3159 if (NewOpc ==
I.getOpcode())
3162 I.setDesc(
TII.get(NewOpc));
3170 case TargetOpcode::G_PTR_ADD: {
3171 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3172 I.eraseFromParent();
3176 case TargetOpcode::G_SADDE:
3177 case TargetOpcode::G_UADDE:
3178 case TargetOpcode::G_SSUBE:
3179 case TargetOpcode::G_USUBE:
3180 case TargetOpcode::G_SADDO:
3181 case TargetOpcode::G_UADDO:
3182 case TargetOpcode::G_SSUBO:
3183 case TargetOpcode::G_USUBO:
3184 return selectOverflowOp(
I, MRI);
3186 case TargetOpcode::G_PTRMASK: {
3187 Register MaskReg =
I.getOperand(2).getReg();
3194 I.setDesc(
TII.get(AArch64::ANDXri));
3195 I.getOperand(2).ChangeToImmediate(
3201 case TargetOpcode::G_PTRTOINT:
3202 case TargetOpcode::G_TRUNC: {
3203 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3204 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3206 const Register DstReg =
I.getOperand(0).getReg();
3207 const Register SrcReg =
I.getOperand(1).getReg();
3209 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3210 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3214 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3218 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3229 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3233 if (DstRC == SrcRC) {
3235 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3239 }
else if (DstRC == &AArch64::GPR32RegClass &&
3240 SrcRC == &AArch64::GPR64RegClass) {
3241 I.getOperand(1).setSubReg(AArch64::sub_32);
3244 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3248 I.setDesc(
TII.get(TargetOpcode::COPY));
3250 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3253 I.setDesc(
TII.get(AArch64::XTNv4i16));
3259 MachineInstr *Extract = emitExtractVectorElt(
3263 I.eraseFromParent();
3268 if (Opcode == TargetOpcode::G_PTRTOINT) {
3269 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3270 I.setDesc(
TII.get(TargetOpcode::COPY));
3278 case TargetOpcode::G_ANYEXT: {
3279 if (selectUSMovFromExtend(
I, MRI))
3282 const Register DstReg =
I.getOperand(0).getReg();
3283 const Register SrcReg =
I.getOperand(1).getReg();
3285 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3286 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3288 <<
", expected: GPR\n");
3292 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3293 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3295 <<
", expected: GPR\n");
3302 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3306 if (DstSize != 64 && DstSize > 32) {
3308 <<
", expected: 32 or 64\n");
3318 .
addImm(AArch64::sub_32);
3319 I.getOperand(1).setReg(ExtSrc);
3324 case TargetOpcode::G_ZEXT:
3325 case TargetOpcode::G_SEXT_INREG:
3326 case TargetOpcode::G_SEXT: {
3327 if (selectUSMovFromExtend(
I, MRI))
3330 unsigned Opcode =
I.getOpcode();
3331 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3332 const Register DefReg =
I.getOperand(0).getReg();
3333 Register SrcReg =
I.getOperand(1).getReg();
3334 const LLT DstTy = MRI.
getType(DefReg);
3335 const LLT SrcTy = MRI.
getType(SrcReg);
3341 if (Opcode == TargetOpcode::G_SEXT_INREG)
3342 SrcSize =
I.getOperand(2).getImm();
3348 AArch64::GPRRegBankID &&
3349 "Unexpected ext regbank");
3360 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3363 if (LoadMI && IsGPR) {
3364 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3365 unsigned BytesLoaded = MemOp->getSize().getValue();
3372 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3375 const Register ZReg = AArch64::WZR;
3376 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3379 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3380 .addUse(SubregToRegSrc)
3381 .
addImm(AArch64::sub_32);
3385 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3395 I.eraseFromParent();
3400 if (DstSize == 64) {
3401 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3409 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3410 {&AArch64::GPR64RegClass}, {})
3416 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3420 }
else if (DstSize <= 32) {
3421 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3430 I.eraseFromParent();
3434 case TargetOpcode::G_FREEZE:
3437 case TargetOpcode::G_INTTOPTR:
3442 case TargetOpcode::G_BITCAST:
3450 case TargetOpcode::G_SELECT: {
3452 const Register CondReg = Sel.getCondReg();
3454 const Register FReg = Sel.getFalseReg();
3456 if (tryOptSelect(Sel))
3462 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3467 Sel.eraseFromParent();
3470 case TargetOpcode::G_ICMP: {
3480 auto &PredOp =
I.getOperand(1);
3481 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3485 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3486 AArch64::WZR, InvCC, MIB);
3487 I.eraseFromParent();
3491 case TargetOpcode::G_FCMP: {
3494 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3496 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3498 I.eraseFromParent();
3501 case TargetOpcode::G_VASTART:
3503 : selectVaStartAAPCS(
I, MF, MRI);
3504 case TargetOpcode::G_INTRINSIC:
3505 return selectIntrinsic(
I, MRI);
3506 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3507 return selectIntrinsicWithSideEffects(
I, MRI);
3508 case TargetOpcode::G_IMPLICIT_DEF: {
3509 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3510 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3511 const Register DstReg =
I.getOperand(0).getReg();
3512 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3517 case TargetOpcode::G_BLOCK_ADDR: {
3518 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3519 if (std::optional<uint16_t> BADisc =
3529 AArch64::GPR64RegClass, MRI);
3530 I.eraseFromParent();
3534 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3535 I.eraseFromParent();
3538 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3539 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3540 I.getOperand(0).getReg())
3544 I.getOperand(1).getBlockAddress(), 0,
3546 I.eraseFromParent();
3551 case TargetOpcode::G_BUILD_VECTOR:
3552 return selectBuildVector(
I, MRI);
3553 case TargetOpcode::G_MERGE_VALUES:
3555 case TargetOpcode::G_UNMERGE_VALUES:
3557 case TargetOpcode::G_SHUFFLE_VECTOR:
3558 return selectShuffleVector(
I, MRI);
3559 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3560 return selectExtractElt(
I, MRI);
3561 case TargetOpcode::G_CONCAT_VECTORS:
3562 return selectConcatVectors(
I, MRI);
3563 case TargetOpcode::G_JUMP_TABLE:
3564 return selectJumpTable(
I, MRI);
3565 case TargetOpcode::G_MEMCPY:
3566 case TargetOpcode::G_MEMCPY_INLINE:
3567 case TargetOpcode::G_MEMMOVE:
3568 case TargetOpcode::G_MEMSET:
3569 case TargetOpcode::G_MEMSET_INLINE:
3570 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3571 return selectMOPS(
I, MRI);
3577bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3578 MachineIRBuilderState OldMIBState = MIB.
getState();
3584bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3585 MachineRegisterInfo &MRI) {
3588 case TargetOpcode::G_MEMCPY:
3589 case TargetOpcode::G_MEMCPY_INLINE:
3590 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3592 case TargetOpcode::G_MEMMOVE:
3593 Mopcode = AArch64::MOPSMemoryMovePseudo;
3595 case TargetOpcode::G_MEMSET:
3596 case TargetOpcode::G_MEMSET_INLINE:
3598 Mopcode = AArch64::MOPSMemorySetPseudo;
3611 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3612 const auto &SrcValRegClass =
3613 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3631 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3632 {DstPtrCopy, SizeCopy, SrcValCopy})
3636 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3637 {DstPtrCopy, SrcValCopy, SizeCopy})
3645bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3646 MachineRegisterInfo &MRI) {
3647 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3648 Register JTAddr =
I.getOperand(0).getReg();
3649 unsigned JTI =
I.getOperand(1).getIndex();
3652 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3664 "jump table hardening only supported on MachO/ELF");
3672 I.eraseFromParent();
3679 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3680 {TargetReg, ScratchReg}, {JTAddr,
Index})
3681 .addJumpTableIndex(JTI);
3683 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3684 {
static_cast<int64_t
>(JTI)});
3686 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3687 I.eraseFromParent();
3692bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3693 MachineRegisterInfo &MRI) {
3694 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3695 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3697 Register DstReg =
I.getOperand(0).getReg();
3698 unsigned JTI =
I.getOperand(1).getIndex();
3701 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3704 I.eraseFromParent();
3709bool AArch64InstructionSelector::selectTLSLocalExecELF(
3710 const GlobalValue *GV, MachineInstr &
I, MachineRegisterInfo &MRI) {
3711 auto ConstrainRegOps = [&](MachineInstrBuilder MIB) {
3715 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {}));
3723 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()},
3734 MIB.
buildInstr(AArch64::ADDXri, {Addr}, {ThreadBase})
3738 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()}, {Addr})
3755 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3760 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3761 {ThreadBase, Addr2}));
3775 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3781 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr3}, {Addr2})
3786 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3787 {ThreadBase, Addr3}));
3791 I.eraseFromParent();
3797bool AArch64InstructionSelector::selectTLSGlobalValueELF(
3798 MachineInstr &
I, MachineRegisterInfo &MRI) {
3799 const GlobalValue *GV =
I.
getOperand(1).getGlobal();
3800 auto *FuncInfo = MF->
getInfo<AArch64FunctionInfo>();
3807 return selectTLSLocalExecELF(GV,
I, MRI);
3809 MIB.
buildInstr(AArch64::LOADgot, {TPOff}, {})
3815 SMEAttrs
Attrs = MF->
getInfo<AArch64FunctionInfo>()->getSMEFnAttrs();
3817 !
Attrs.hasStreamingCompatibleInterface() &&
3818 "unsupported SME features reached GlobalISel TLS lowering");
3821 ? AArch64::TLSDESC_AUTH_CALLSEQ
3822 : AArch64::TLSDESC_CALLSEQ;
3841 MIB.
buildInstr(AArch64::ADDXri, {TPOff}, {Add1.getReg(0)})
3842 .addGlobalAddress(GV, 0,
3851 MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {});
3852 auto Add = MIB.
buildInstr(AArch64::ADDXrr, {
I.getOperand(0).getReg()},
3853 {ThreadBase, TPOff});
3856 I.eraseFromParent();
3860bool AArch64InstructionSelector::selectTLSGlobalValueMachO(
3861 MachineInstr &
I, MachineRegisterInfo &MRI) {
3862 const auto &GlobalOp =
I.getOperand(1);
3863 assert(GlobalOp.getOffset() == 0 &&
3864 "Shouldn't have an offset on TLS globals!");
3866 const GlobalValue &GV = *GlobalOp.getGlobal();
3869 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3872 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3873 {LoadGOT.getReg(0)})
3884 assert(Opcode == AArch64::BLR);
3885 Opcode = AArch64::BLRAAZ;
3890 .
addUse(AArch64::X0, RegState::Implicit)
3891 .
addDef(AArch64::X0, RegState::Implicit)
3897 I.eraseFromParent();
3901bool AArch64InstructionSelector::selectTLSGlobalValue(
3902 MachineInstr &
I, MachineRegisterInfo &MRI) {
3908 return selectTLSGlobalValueELF(
I, MRI);
3911 return selectTLSGlobalValueMachO(
I, MRI);
3916MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3918 MachineIRBuilder &MIRBuilder)
const {
3919 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3921 auto BuildFn = [&](
unsigned SubregIndex) {
3925 .addImm(SubregIndex);
3933 return BuildFn(AArch64::bsub);
3935 return BuildFn(AArch64::hsub);
3937 return BuildFn(AArch64::ssub);
3939 return BuildFn(AArch64::dsub);
3946AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3947 MachineIRBuilder &MIB,
3948 MachineRegisterInfo &MRI)
const {
3949 LLT DstTy = MRI.
getType(DstReg);
3951 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3952 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3956 unsigned SubReg = 0;
3959 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3965 .addReg(SrcReg, {}, SubReg);
3970bool AArch64InstructionSelector::selectMergeValues(
3971 MachineInstr &
I, MachineRegisterInfo &MRI) {
3972 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3973 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3974 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3976 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3978 if (
I.getNumOperands() != 3)
3985 Register DstReg =
I.getOperand(0).getReg();
3986 Register Src1Reg =
I.getOperand(1).getReg();
3987 Register Src2Reg =
I.getOperand(2).getReg();
3988 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3989 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3993 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3994 Src2Reg, 1, RB, MIB);
3999 I.eraseFromParent();
4003 if (RB.
getID() != AArch64::GPRRegBankID)
4009 auto *DstRC = &AArch64::GPR64RegClass;
4011 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4012 TII.get(TargetOpcode::SUBREG_TO_REG))
4014 .
addUse(
I.getOperand(1).getReg())
4015 .
addImm(AArch64::sub_32);
4018 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4019 TII.get(TargetOpcode::SUBREG_TO_REG))
4021 .
addUse(
I.getOperand(2).getReg())
4022 .
addImm(AArch64::sub_32);
4024 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
4025 .
addDef(
I.getOperand(0).getReg())
4033 I.eraseFromParent();
4038 const unsigned EltSize) {
4043 CopyOpc = AArch64::DUPi8;
4044 ExtractSubReg = AArch64::bsub;
4047 CopyOpc = AArch64::DUPi16;
4048 ExtractSubReg = AArch64::hsub;
4051 CopyOpc = AArch64::DUPi32;
4052 ExtractSubReg = AArch64::ssub;
4055 CopyOpc = AArch64::DUPi64;
4056 ExtractSubReg = AArch64::dsub;
4060 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
4066MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
4067 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
4068 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
4069 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4070 unsigned CopyOpc = 0;
4071 unsigned ExtractSubReg = 0;
4074 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
4079 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
4081 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
4085 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
4086 const LLT &VecTy = MRI.
getType(VecReg);
4088 getRegClassForTypeOnBank(VecTy, VecRB,
true);
4090 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4100 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4101 .addReg(VecReg, {}, ExtractSubReg);
4110 MachineInstr *ScalarToVector = emitScalarToVector(
4111 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4112 if (!ScalarToVector)
4117 MachineInstr *LaneCopyMI =
4118 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4126bool AArch64InstructionSelector::selectExtractElt(
4127 MachineInstr &
I, MachineRegisterInfo &MRI) {
4128 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4129 "unexpected opcode!");
4130 Register DstReg =
I.getOperand(0).getReg();
4131 const LLT NarrowTy = MRI.
getType(DstReg);
4132 const Register SrcReg =
I.getOperand(1).getReg();
4133 const LLT WideTy = MRI.
getType(SrcReg);
4135 "source register size too small!");
4136 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4139 MachineOperand &LaneIdxOp =
I.getOperand(2);
4140 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4146 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4148 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4149 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4153 Opcode = AArch64::UMOVvi8;
4156 Opcode = AArch64::UMOVvi16;
4159 Opcode = AArch64::UMOVvi32;
4166 MachineInstr *ScalarToVector = emitScalarToVector(
4167 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4168 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4172 I.setDesc(
TII.get(Opcode));
4173 I.getOperand(2).ChangeToImmediate(LaneIdx);
4178 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4183 I.eraseFromParent();
4187bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4188 MachineInstr &
I, MachineRegisterInfo &MRI) {
4189 unsigned NumElts =
I.getNumOperands() - 1;
4190 Register SrcReg =
I.getOperand(NumElts).getReg();
4191 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4192 const LLT SrcTy = MRI.
getType(SrcReg);
4194 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4196 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4202 const RegisterBank &DstRB =
4204 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4205 Register Dst =
I.getOperand(OpIdx).getReg();
4206 MachineInstr *Extract =
4207 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4211 I.eraseFromParent();
4215bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4216 MachineRegisterInfo &MRI) {
4217 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4218 "unexpected opcode");
4222 unsigned NumElts =
I.getNumOperands() - 1;
4223 Register SrcReg =
I.getOperand(NumElts).getReg();
4224 Register LoReg =
I.getOperand(0).getReg();
4225 Register HiReg =
I.getOperand(1).getReg();
4226 const LLT NarrowTy = MRI.
getType(LoReg);
4227 const LLT WideTy = MRI.
getType(SrcReg);
4228 const RegisterBank &LoRB = *RBI.
getRegBank(LoReg, MRI,
TRI);
4229 const RegisterBank &HiRB = *RBI.
getRegBank(HiReg, MRI,
TRI);
4230 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
4234 LoRB.
getID() == AArch64::GPRRegBankID &&
4235 HiRB.
getID() == AArch64::GPRRegBankID &&
4236 SrcRB.
getID() == AArch64::FPRRegBankID) {
4237 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4238 TII.get(AArch64::UMOVvi64), LoReg)
4241 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4242 TII.get(AArch64::UMOVvi64), HiReg)
4247 I.eraseFromParent();
4252 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4253 HiRB.
getID() != AArch64::FPRRegBankID) {
4254 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4255 "currently unsupported.\n");
4260 "source register size too small!");
4263 return selectSplitVectorUnmerge(
I, MRI);
4267 unsigned CopyOpc = 0;
4268 unsigned ExtractSubReg = 0;
4279 unsigned NumInsertRegs = NumElts - 1;
4285 InsertRegs.
assign(NumInsertRegs, SrcReg);
4294 unsigned SubReg = 0;
4297 assert(Found &&
"expected to find last operand's subeg idx");
4298 for (
unsigned Idx = 0;
Idx < NumInsertRegs; ++
Idx) {
4300 MachineInstr &ImpDefMI =
4301 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4306 MachineInstr &InsMI =
4308 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4325 Register CopyTo =
I.getOperand(0).getReg();
4326 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4327 .addReg(InsertRegs[0], {}, ExtractSubReg);
4331 unsigned LaneIdx = 1;
4332 for (
Register InsReg : InsertRegs) {
4333 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4334 MachineInstr &CopyInst =
4353 I.eraseFromParent();
4357bool AArch64InstructionSelector::selectConcatVectors(
4358 MachineInstr &
I, MachineRegisterInfo &MRI) {
4359 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4360 "Unexpected opcode");
4361 Register Dst =
I.getOperand(0).getReg();
4362 Register Op1 =
I.getOperand(1).getReg();
4363 Register Op2 =
I.getOperand(2).getReg();
4364 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4367 I.eraseFromParent();
4372AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4381MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4382 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4389 RC = &AArch64::FPR128RegClass;
4390 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4393 RC = &AArch64::FPR64RegClass;
4394 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4397 RC = &AArch64::FPR32RegClass;
4398 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4401 RC = &AArch64::FPR16RegClass;
4402 Opc = AArch64::LDRHui;
4405 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4410 MachineInstr *LoadMI =
nullptr;
4411 auto &MF = MIRBuilder.
getMF();
4412 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4413 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4415 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4418 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4422 .addConstantPoolIndex(
4438static std::pair<unsigned, unsigned>
4440 unsigned Opc, SubregIdx;
4441 if (RB.
getID() == AArch64::GPRRegBankID) {
4443 Opc = AArch64::INSvi8gpr;
4444 SubregIdx = AArch64::bsub;
4445 }
else if (EltSize == 16) {
4446 Opc = AArch64::INSvi16gpr;
4447 SubregIdx = AArch64::ssub;
4448 }
else if (EltSize == 32) {
4449 Opc = AArch64::INSvi32gpr;
4450 SubregIdx = AArch64::ssub;
4451 }
else if (EltSize == 64) {
4452 Opc = AArch64::INSvi64gpr;
4453 SubregIdx = AArch64::dsub;
4459 Opc = AArch64::INSvi8lane;
4460 SubregIdx = AArch64::bsub;
4461 }
else if (EltSize == 16) {
4462 Opc = AArch64::INSvi16lane;
4463 SubregIdx = AArch64::hsub;
4464 }
else if (EltSize == 32) {
4465 Opc = AArch64::INSvi32lane;
4466 SubregIdx = AArch64::ssub;
4467 }
else if (EltSize == 64) {
4468 Opc = AArch64::INSvi64lane;
4469 SubregIdx = AArch64::dsub;
4474 return std::make_pair(
Opc, SubregIdx);
4477MachineInstr *AArch64InstructionSelector::emitInstr(
4478 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4479 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4480 const ComplexRendererFns &RenderFns)
const {
4481 assert(Opcode &&
"Expected an opcode?");
4483 "Function should only be used to produce selected instructions!");
4484 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4486 for (
auto &Fn : *RenderFns)
4492MachineInstr *AArch64InstructionSelector::emitAddSub(
4493 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4495 MachineIRBuilder &MIRBuilder)
const {
4497 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4501 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4502 bool Is32Bit =
Size == 32;
4505 if (
auto Fns = selectArithImmed(
RHS))
4506 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4510 if (
auto Fns = selectNegArithImmed(
RHS))
4511 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4515 if (
auto Fns = selectArithExtendedRegister(
RHS))
4516 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4520 if (
auto Fns = selectShiftedRegister(
RHS))
4521 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4523 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4528AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4529 MachineOperand &
RHS,
4530 MachineIRBuilder &MIRBuilder)
const {
4531 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4532 {{AArch64::ADDXri, AArch64::ADDWri},
4533 {AArch64::ADDXrs, AArch64::ADDWrs},
4534 {AArch64::ADDXrr, AArch64::ADDWrr},
4535 {AArch64::SUBXri, AArch64::SUBWri},
4536 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4537 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4541AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4542 MachineOperand &
RHS,
4543 MachineIRBuilder &MIRBuilder)
const {
4544 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4545 {{AArch64::ADDSXri, AArch64::ADDSWri},
4546 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4547 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4548 {AArch64::SUBSXri, AArch64::SUBSWri},
4549 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4550 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4554AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4555 MachineOperand &
RHS,
4556 MachineIRBuilder &MIRBuilder)
const {
4557 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4558 {{AArch64::SUBSXri, AArch64::SUBSWri},
4559 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4560 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4561 {AArch64::ADDSXri, AArch64::ADDSWri},
4562 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4563 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4567AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4568 MachineOperand &
RHS,
4569 MachineIRBuilder &MIRBuilder)
const {
4570 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4571 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4573 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4574 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4578AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4579 MachineOperand &
RHS,
4580 MachineIRBuilder &MIRBuilder)
const {
4581 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4582 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4584 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4585 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4589AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4590 MachineIRBuilder &MIRBuilder)
const {
4593 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4598AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4599 MachineIRBuilder &MIRBuilder)
const {
4602 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4607AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4608 MachineIRBuilder &MIRBuilder)
const {
4609 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4613 bool Is32Bit = (
RegSize == 32);
4614 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4615 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4616 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4620 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4623 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4630 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4631 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4632 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4635MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4636 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4637 MachineIRBuilder &MIRBuilder)
const {
4638 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4645 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4647 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4649 return emitCMP(
LHS,
RHS, MIRBuilder);
4652MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4654 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4658 "Expected a 32-bit scalar register?");
4660 const Register ZReg = AArch64::WZR;
4665 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4671 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4672 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4673 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4678MachineInstr *AArch64InstructionSelector::emitFPCompare(
4680 std::optional<CmpInst::Predicate> Pred)
const {
4681 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4686 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4696 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4699 ShouldUseImm =
true;
4703 unsigned CmpOpcTbl[2][3] = {
4704 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4705 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4707 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4719MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4721 MachineIRBuilder &MIRBuilder)
const {
4728 const LLT Op1Ty = MRI.
getType(Op1);
4729 const LLT Op2Ty = MRI.
getType(Op2);
4731 if (Op1Ty != Op2Ty) {
4732 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4735 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4738 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4749 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4753 MachineInstr *WidenedOp1 =
4754 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4755 MachineInstr *WidenedOp2 =
4756 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4757 if (!WidenedOp1 || !WidenedOp2) {
4758 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4763 unsigned InsertOpc, InsSubRegIdx;
4764 std::tie(InsertOpc, InsSubRegIdx) =
4782 MachineIRBuilder &MIRBuilder)
const {
4783 auto &MRI = *MIRBuilder.
getMRI();
4789 Size =
TRI.getRegSizeInBits(*RC);
4793 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4794 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4795 unsigned Opc = OpcTable[
Size == 64];
4801MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4803 MachineRegisterInfo *MRI = MIB.
getMRI();
4804 unsigned Opcode =
I.getOpcode();
4808 bool NeedsNegatedCarry =
4809 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4818 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4826 if (SrcMI == PrevMI) {
4828 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4829 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4830 CarrySrcMI->isUnsigned() &&
4831 CarrySrcMI->getCarryOutReg() == CarryReg &&
4832 selectAndRestoreState(*SrcMI))
4839 if (NeedsNegatedCarry) {
4842 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4846 auto Fns = select12BitValueWithLeftShift(1);
4847 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4850bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4851 MachineRegisterInfo &MRI) {
4856 emitCarryIn(
I, CarryInMI->getCarryInReg());
4860 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4861 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4863 Register CarryOutReg = CarryMI.getCarryOutReg();
4867 OpAndCC.first->addRegisterDead(AArch64::NZCV, &
TRI);
4874 emitCSINC(CarryOutReg, ZReg, ZReg,
4875 getInvertedCondCode(OpAndCC.second), MIB);
4878 I.eraseFromParent();
4882std::pair<MachineInstr *, AArch64CC::CondCode>
4883AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4884 MachineOperand &
LHS,
4885 MachineOperand &
RHS,
4886 MachineIRBuilder &MIRBuilder)
const {
4890 case TargetOpcode::G_SADDO:
4892 case TargetOpcode::G_UADDO:
4894 case TargetOpcode::G_SSUBO:
4896 case TargetOpcode::G_USUBO:
4898 case TargetOpcode::G_SADDE:
4900 case TargetOpcode::G_UADDE:
4902 case TargetOpcode::G_SSUBE:
4904 case TargetOpcode::G_USUBE:
4925 unsigned Depth = 0) {
4932 MustBeFirst =
false;
4938 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4939 bool IsOR = Opcode == TargetOpcode::G_OR;
4951 if (MustBeFirstL && MustBeFirstR)
4957 if (!CanNegateL && !CanNegateR)
4961 CanNegate = WillNegate && CanNegateL && CanNegateR;
4964 MustBeFirst = !CanNegate;
4966 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4969 MustBeFirst = MustBeFirstL || MustBeFirstR;
4976MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4979 MachineIRBuilder &MIB)
const {
4980 auto &MRI = *MIB.
getMRI();
4983 std::optional<ValueAndVReg>
C;
4987 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4988 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4989 else if (
C->Value.ule(31))
4990 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4992 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4998 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4999 CCmpOpc = AArch64::FCCMPHrr;
5002 CCmpOpc = AArch64::FCCMPSrr;
5005 CCmpOpc = AArch64::FCCMPDrr;
5015 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
5016 CCmp.
addImm(
C->Value.getZExtValue());
5017 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
5018 CCmp.
addImm(
C->Value.abs().getZExtValue());
5026MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
5030 auto &MRI = *MIB.
getMRI();
5048 MachineInstr *ExtraCmp;
5050 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
5062 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
5063 return emitFPCompare(
Cmp->getOperand(2).getReg(),
5064 Cmp->getOperand(3).getReg(), MIB);
5071 bool IsOR = Opcode == TargetOpcode::G_OR;
5077 assert(ValidL &&
"Valid conjunction/disjunction tree");
5084 assert(ValidR &&
"Valid conjunction/disjunction tree");
5089 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
5098 bool NegateAfterAll;
5099 if (Opcode == TargetOpcode::G_OR) {
5102 assert(CanNegateR &&
"at least one side must be negatable");
5103 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
5107 NegateAfterR =
true;
5110 NegateR = CanNegateR;
5111 NegateAfterR = !CanNegateR;
5114 NegateAfterAll = !Negate;
5116 assert(Opcode == TargetOpcode::G_AND &&
5117 "Valid conjunction/disjunction tree");
5118 assert(!Negate &&
"Valid conjunction/disjunction tree");
5122 NegateAfterR =
false;
5123 NegateAfterAll =
false;
5128 MachineInstr *CmpR =
5139MachineInstr *AArch64InstructionSelector::emitConjunction(
5141 bool DummyCanNegate;
5142 bool DummyMustBeFirst;
5149bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5150 MachineInstr &CondMI) {
5161bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5162 MachineRegisterInfo &MRI = *MIB.
getMRI();
5181 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5190 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5196 unsigned CondOpc = CondDef->
getOpcode();
5197 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5198 if (tryOptSelectConjunction(
I, *CondDef))
5204 if (CondOpc == TargetOpcode::G_ICMP) {
5233 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5234 I.getOperand(3).getReg(), CondCode, MIB);
5235 I.eraseFromParent();
5239MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5240 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5241 MachineIRBuilder &MIRBuilder)
const {
5243 "Unexpected MachineOperand");
5244 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5267 if (
isCMN(RHSDef,
P, MRI))
5282 if (
isCMN(LHSDef,
P, MRI)) {
5299 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5302 if (!ValAndVReg || ValAndVReg->Value != 0)
5312bool AArch64InstructionSelector::selectShuffleVector(
5313 MachineInstr &
I, MachineRegisterInfo &MRI) {
5314 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5315 Register Src1Reg =
I.getOperand(1).getReg();
5316 Register Src2Reg =
I.getOperand(2).getReg();
5317 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5319 "Expected equal shuffle types during selection");
5328 SmallVector<int> NewMask;
5329 bool FirstUsed =
false;
5330 bool SecondUsed =
false;
5331 for (
int M : Mask) {
5333 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5336 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5341 FirstUsed |=
M < NumElts;
5342 SecondUsed |=
M >= NumElts;
5343 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5352 for (
int &M : NewMask) {
5354 assert(M >= ByteLanes && M < 2 * ByteLanes);
5364 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5365 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5378 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5385 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5389 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5394 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5395 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5397 I.eraseFromParent();
5402 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5405 I.eraseFromParent();
5413 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5416 I.eraseFromParent();
5420MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5422 unsigned LaneIdx,
const RegisterBank &RB,
5423 MachineIRBuilder &MIRBuilder)
const {
5424 MachineInstr *InsElt =
nullptr;
5426 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5435 if (RB.
getID() == AArch64::FPRRegBankID) {
5436 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5439 .
addUse(InsSub->getOperand(0).getReg())
5451bool AArch64InstructionSelector::selectUSMovFromExtend(
5452 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5453 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5454 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5455 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5457 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5458 const Register DefReg =
MI.getOperand(0).getReg();
5459 const LLT DstTy = MRI.
getType(DefReg);
5462 if (DstSize != 32 && DstSize != 64)
5465 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5466 MI.getOperand(1).getReg(), MRI);
5472 const LLT VecTy = MRI.
getType(Src0);
5477 const MachineInstr *ScalarToVector = emitScalarToVector(
5478 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5479 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5485 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5487 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5489 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5491 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5493 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5501 MachineInstr *ExtI =
nullptr;
5502 if (DstSize == 64 && !IsSigned) {
5505 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5507 .
addImm(AArch64::sub_32);
5513 MI.eraseFromParent();
5517bool AArch64InstructionSelector::selectIndexedExtLoad(
5518 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5521 Register WriteBack = ExtLd.getWritebackReg();
5526 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5527 bool IsPre = ExtLd.isPre();
5529 unsigned InsertIntoSubReg = 0;
5535 if ((IsSExt && IsFPR) || Ty.
isVector())
5543 if (MemSizeBits == 8) {
5546 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5548 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5549 NewLdDstTy = IsDst64 ? s64 : s32;
5551 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5552 InsertIntoSubReg = AArch64::bsub;
5555 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5556 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5559 }
else if (MemSizeBits == 16) {
5562 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5564 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5565 NewLdDstTy = IsDst64 ? s64 : s32;
5567 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5568 InsertIntoSubReg = AArch64::hsub;
5571 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5572 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5575 }
else if (MemSizeBits == 32) {
5577 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5580 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5581 InsertIntoSubReg = AArch64::ssub;
5584 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5585 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5597 .addImm(Cst->getSExtValue());
5602 if (InsertIntoSubReg) {
5604 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5605 .addUse(LdMI.getReg(1))
5606 .
addImm(InsertIntoSubReg);
5609 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5616 MI.eraseFromParent();
5621bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5622 MachineRegisterInfo &MRI) {
5625 Register WriteBack = Ld.getWritebackReg();
5629 "Unexpected type for indexed load");
5630 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5633 return selectIndexedExtLoad(
MI, MRI);
5637 static constexpr unsigned GPROpcodes[] = {
5638 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5640 static constexpr unsigned FPROpcodes[] = {
5641 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5644 ? FPROpcodes[
Log2_32(MemSize)]
5645 : GPROpcodes[
Log2_32(MemSize)];
5648 static constexpr unsigned GPROpcodes[] = {
5649 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5651 static constexpr unsigned FPROpcodes[] = {
5652 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5653 AArch64::LDRDpost, AArch64::LDRQpost};
5655 ? FPROpcodes[
Log2_32(MemSize)]
5656 : GPROpcodes[
Log2_32(MemSize)];
5666 MI.eraseFromParent();
5670bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5671 MachineRegisterInfo &MRI) {
5677 "Unexpected type for indexed store");
5679 LocationSize MemSize =
I.getMMO().getSize();
5680 unsigned MemSizeInBytes = MemSize.
getValue();
5682 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5683 "Unexpected indexed store size");
5684 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5688 static constexpr unsigned GPROpcodes[] = {
5689 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5691 static constexpr unsigned FPROpcodes[] = {
5692 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5696 Opc = FPROpcodes[MemSizeLog2];
5698 Opc = GPROpcodes[MemSizeLog2];
5700 static constexpr unsigned GPROpcodes[] = {
5701 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5703 static constexpr unsigned FPROpcodes[] = {
5704 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5705 AArch64::STRDpost, AArch64::STRQpost};
5708 Opc = FPROpcodes[MemSizeLog2];
5710 Opc = GPROpcodes[MemSizeLog2];
5718 Str.cloneMemRefs(
I);
5720 I.eraseFromParent();
5725AArch64InstructionSelector::emitConstantMOVVector(DstOp Dst, APInt
Imm,
5726 MachineRegisterInfo &MRI) {
5727 unsigned DstSize =
Imm.getBitWidth();
5728 assert((DstSize == 64 || DstSize == 128) &&
5729 "Unexpected vector constant size");
5733 for (AArch64_IMM::ImmInsnModel Insn : Insns) {
5734 switch (Insn.Opcode) {
5735 case AArch64::FMOVD0: {
5739 AArch64::MOVIv2d_ns,
5740 {DstSize == 128 ? Dst : DstOp(&AArch64::FPR128RegClass)}, {})
5743 if (DstSize != 128) {
5744 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5745 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5751 case AArch64::FMOVDi:
5752 case AArch64::FMOVv2f32_ns:
5753 case AArch64::FMOVv2f64_ns:
5754 case AArch64::FMOVv4f32_ns:
5755 case AArch64::FMOVv4f16_ns:
5756 case AArch64::FMOVv8f16_ns:
5757 case AArch64::MOVID:
5758 case AArch64::MOVIv16b_ns:
5759 case AArch64::MOVIv2d_ns:
5760 case AArch64::MOVIv2i32:
5761 case AArch64::MOVIv2s_msl:
5762 case AArch64::MOVIv4i16:
5763 case AArch64::MOVIv4i32:
5764 case AArch64::MOVIv4s_msl:
5765 case AArch64::MOVIv8b_ns:
5766 case AArch64::MOVIv8i16:
5767 case AArch64::MVNIv2i32:
5768 case AArch64::MVNIv2s_msl:
5769 case AArch64::MVNIv4i16:
5770 case AArch64::MVNIv4i32:
5771 case AArch64::MVNIv4s_msl:
5772 case AArch64::MVNIv8i16: {
5773 auto Mov = MIB.
buildInstr(Insn.Opcode, {Dst}, {});
5781 case AArch64::DUPM_ZI: {
5782 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5785 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5786 .addReg(Mov.getReg(0), {},
5787 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5789 DstSize == 64 ? AArch64::FPR64RegClass
5790 : AArch64::FPR128RegClass,
5794 case AArch64::DUP_ZI_D: {
5795 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5799 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5800 .addReg(Mov.getReg(0), {},
5801 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5803 DstSize == 64 ? AArch64::FPR64RegClass
5804 : AArch64::FPR128RegClass,
5816MachineInstr *AArch64InstructionSelector::emitConstantVector(
5817 Register Dst, Constant *CV, APInt
Imm, MachineRegisterInfo &MRI) {
5818 if (
auto *MovI = emitConstantMOVVector(Dst,
Imm, MRI))
5823 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5829 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5833bool AArch64InstructionSelector::tryOptConstantBuildVec(
5834 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5835 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5837 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5843 APInt
Imm(DstSize, 0);
5844 for (
unsigned Idx = 1;
Idx <
I.getNumOperands(); ++
Idx) {
5845 Register OpReg =
I.getOperand(Idx).getReg();
5857 std::move(AnyConst->Value)));
5870 if (!emitConstantVector(
I.getOperand(0).getReg(), CV,
Imm, MRI))
5872 I.eraseFromParent();
5876bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5877 MachineInstr &
I, MachineRegisterInfo &MRI) {
5882 Register Dst =
I.getOperand(0).getReg();
5883 Register EltReg =
I.getOperand(1).getReg();
5884 LLT EltTy = MRI.
getType(EltReg);
5887 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5892 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5900 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5905 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5908 I.eraseFromParent();
5913bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5914 MachineRegisterInfo &MRI) {
5915 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5918 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5919 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5922 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5924 if (tryOptBuildVecToSubregToReg(
I, MRI))
5927 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5929 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5932 MachineInstr *ScalarToVec =
5934 I.getOperand(1).getReg(), MIB);
5943 MachineInstr *PrevMI = ScalarToVec;
5944 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5947 Register OpReg =
I.getOperand(i).getReg();
5950 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5957 if (DstSize < 128) {
5960 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5963 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5968 unsigned SubReg = 0;
5971 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5972 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5978 Register DstReg =
I.getOperand(0).getReg();
5980 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5981 MachineOperand &RegOp =
I.getOperand(1);
6001 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6003 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6012bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6015 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6017 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6018 auto &MRI = *MIB.
getMRI();
6019 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6022 "Destination must be 64 bits or 128 bits?");
6023 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6024 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6029 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6030 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6031 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6032 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6041bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6042 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6043 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6045 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6046 auto &MRI = *MIB.
getMRI();
6047 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6050 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6052 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6053 [](
auto MO) { return MO.getReg(); });
6057 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6072 .
addImm(LaneNo->getZExtValue())
6076 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6077 unsigned SubReg = AArch64::qsub0;
6078 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6079 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6080 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6083 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6088 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6094void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6097 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6098 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6099 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6102 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6103 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6112bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6113 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6114 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6115 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6119 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6120 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6124 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6134 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6137 .
addImm(LaneNo->getZExtValue())
6144bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6145 MachineInstr &
I, MachineRegisterInfo &MRI) {
6158 case Intrinsic::aarch64_ldxp:
6159 case Intrinsic::aarch64_ldaxp: {
6161 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6162 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6168 case Intrinsic::aarch64_neon_ld1x2: {
6169 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6172 Opc = AArch64::LD1Twov8b;
6174 Opc = AArch64::LD1Twov16b;
6176 Opc = AArch64::LD1Twov4h;
6178 Opc = AArch64::LD1Twov8h;
6180 Opc = AArch64::LD1Twov2s;
6182 Opc = AArch64::LD1Twov4s;
6184 Opc = AArch64::LD1Twov2d;
6185 else if (Ty ==
S64 || Ty == P0)
6186 Opc = AArch64::LD1Twov1d;
6189 selectVectorLoadIntrinsic(
Opc, 2,
I);
6192 case Intrinsic::aarch64_neon_ld1x3: {
6193 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6196 Opc = AArch64::LD1Threev8b;
6198 Opc = AArch64::LD1Threev16b;
6200 Opc = AArch64::LD1Threev4h;
6202 Opc = AArch64::LD1Threev8h;
6204 Opc = AArch64::LD1Threev2s;
6206 Opc = AArch64::LD1Threev4s;
6208 Opc = AArch64::LD1Threev2d;
6209 else if (Ty ==
S64 || Ty == P0)
6210 Opc = AArch64::LD1Threev1d;
6213 selectVectorLoadIntrinsic(
Opc, 3,
I);
6216 case Intrinsic::aarch64_neon_ld1x4: {
6217 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6220 Opc = AArch64::LD1Fourv8b;
6222 Opc = AArch64::LD1Fourv16b;
6224 Opc = AArch64::LD1Fourv4h;
6226 Opc = AArch64::LD1Fourv8h;
6228 Opc = AArch64::LD1Fourv2s;
6230 Opc = AArch64::LD1Fourv4s;
6232 Opc = AArch64::LD1Fourv2d;
6233 else if (Ty ==
S64 || Ty == P0)
6234 Opc = AArch64::LD1Fourv1d;
6237 selectVectorLoadIntrinsic(
Opc, 4,
I);
6240 case Intrinsic::aarch64_neon_ld2: {
6241 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6244 Opc = AArch64::LD2Twov8b;
6246 Opc = AArch64::LD2Twov16b;
6248 Opc = AArch64::LD2Twov4h;
6250 Opc = AArch64::LD2Twov8h;
6252 Opc = AArch64::LD2Twov2s;
6254 Opc = AArch64::LD2Twov4s;
6256 Opc = AArch64::LD2Twov2d;
6257 else if (Ty ==
S64 || Ty == P0)
6258 Opc = AArch64::LD1Twov1d;
6261 selectVectorLoadIntrinsic(
Opc, 2,
I);
6264 case Intrinsic::aarch64_neon_ld2lane: {
6265 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6268 Opc = AArch64::LD2i8;
6270 Opc = AArch64::LD2i16;
6272 Opc = AArch64::LD2i32;
6275 Opc = AArch64::LD2i64;
6278 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6282 case Intrinsic::aarch64_neon_ld2r: {
6283 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6286 Opc = AArch64::LD2Rv8b;
6288 Opc = AArch64::LD2Rv16b;
6290 Opc = AArch64::LD2Rv4h;
6292 Opc = AArch64::LD2Rv8h;
6294 Opc = AArch64::LD2Rv2s;
6296 Opc = AArch64::LD2Rv4s;
6298 Opc = AArch64::LD2Rv2d;
6299 else if (Ty ==
S64 || Ty == P0)
6300 Opc = AArch64::LD2Rv1d;
6303 selectVectorLoadIntrinsic(
Opc, 2,
I);
6306 case Intrinsic::aarch64_neon_ld3: {
6307 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6310 Opc = AArch64::LD3Threev8b;
6312 Opc = AArch64::LD3Threev16b;
6314 Opc = AArch64::LD3Threev4h;
6316 Opc = AArch64::LD3Threev8h;
6318 Opc = AArch64::LD3Threev2s;
6320 Opc = AArch64::LD3Threev4s;
6322 Opc = AArch64::LD3Threev2d;
6323 else if (Ty ==
S64 || Ty == P0)
6324 Opc = AArch64::LD1Threev1d;
6327 selectVectorLoadIntrinsic(
Opc, 3,
I);
6330 case Intrinsic::aarch64_neon_ld3lane: {
6331 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6334 Opc = AArch64::LD3i8;
6336 Opc = AArch64::LD3i16;
6338 Opc = AArch64::LD3i32;
6341 Opc = AArch64::LD3i64;
6344 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6348 case Intrinsic::aarch64_neon_ld3r: {
6349 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6352 Opc = AArch64::LD3Rv8b;
6354 Opc = AArch64::LD3Rv16b;
6356 Opc = AArch64::LD3Rv4h;
6358 Opc = AArch64::LD3Rv8h;
6360 Opc = AArch64::LD3Rv2s;
6362 Opc = AArch64::LD3Rv4s;
6364 Opc = AArch64::LD3Rv2d;
6365 else if (Ty ==
S64 || Ty == P0)
6366 Opc = AArch64::LD3Rv1d;
6369 selectVectorLoadIntrinsic(
Opc, 3,
I);
6372 case Intrinsic::aarch64_neon_ld4: {
6373 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6376 Opc = AArch64::LD4Fourv8b;
6378 Opc = AArch64::LD4Fourv16b;
6380 Opc = AArch64::LD4Fourv4h;
6382 Opc = AArch64::LD4Fourv8h;
6384 Opc = AArch64::LD4Fourv2s;
6386 Opc = AArch64::LD4Fourv4s;
6388 Opc = AArch64::LD4Fourv2d;
6389 else if (Ty ==
S64 || Ty == P0)
6390 Opc = AArch64::LD1Fourv1d;
6393 selectVectorLoadIntrinsic(
Opc, 4,
I);
6396 case Intrinsic::aarch64_neon_ld4lane: {
6397 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6400 Opc = AArch64::LD4i8;
6402 Opc = AArch64::LD4i16;
6404 Opc = AArch64::LD4i32;
6407 Opc = AArch64::LD4i64;
6410 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6414 case Intrinsic::aarch64_neon_ld4r: {
6415 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6418 Opc = AArch64::LD4Rv8b;
6420 Opc = AArch64::LD4Rv16b;
6422 Opc = AArch64::LD4Rv4h;
6424 Opc = AArch64::LD4Rv8h;
6426 Opc = AArch64::LD4Rv2s;
6428 Opc = AArch64::LD4Rv4s;
6430 Opc = AArch64::LD4Rv2d;
6431 else if (Ty ==
S64 || Ty == P0)
6432 Opc = AArch64::LD4Rv1d;
6435 selectVectorLoadIntrinsic(
Opc, 4,
I);
6438 case Intrinsic::aarch64_neon_st1x2: {
6439 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6442 Opc = AArch64::ST1Twov8b;
6444 Opc = AArch64::ST1Twov16b;
6446 Opc = AArch64::ST1Twov4h;
6448 Opc = AArch64::ST1Twov8h;
6450 Opc = AArch64::ST1Twov2s;
6452 Opc = AArch64::ST1Twov4s;
6454 Opc = AArch64::ST1Twov2d;
6455 else if (Ty ==
S64 || Ty == P0)
6456 Opc = AArch64::ST1Twov1d;
6459 selectVectorStoreIntrinsic(
I, 2,
Opc);
6462 case Intrinsic::aarch64_neon_st1x3: {
6463 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6466 Opc = AArch64::ST1Threev8b;
6468 Opc = AArch64::ST1Threev16b;
6470 Opc = AArch64::ST1Threev4h;
6472 Opc = AArch64::ST1Threev8h;
6474 Opc = AArch64::ST1Threev2s;
6476 Opc = AArch64::ST1Threev4s;
6478 Opc = AArch64::ST1Threev2d;
6479 else if (Ty ==
S64 || Ty == P0)
6480 Opc = AArch64::ST1Threev1d;
6483 selectVectorStoreIntrinsic(
I, 3,
Opc);
6486 case Intrinsic::aarch64_neon_st1x4: {
6487 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6490 Opc = AArch64::ST1Fourv8b;
6492 Opc = AArch64::ST1Fourv16b;
6494 Opc = AArch64::ST1Fourv4h;
6496 Opc = AArch64::ST1Fourv8h;
6498 Opc = AArch64::ST1Fourv2s;
6500 Opc = AArch64::ST1Fourv4s;
6502 Opc = AArch64::ST1Fourv2d;
6503 else if (Ty ==
S64 || Ty == P0)
6504 Opc = AArch64::ST1Fourv1d;
6507 selectVectorStoreIntrinsic(
I, 4,
Opc);
6510 case Intrinsic::aarch64_neon_st2: {
6511 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6514 Opc = AArch64::ST2Twov8b;
6516 Opc = AArch64::ST2Twov16b;
6518 Opc = AArch64::ST2Twov4h;
6520 Opc = AArch64::ST2Twov8h;
6522 Opc = AArch64::ST2Twov2s;
6524 Opc = AArch64::ST2Twov4s;
6526 Opc = AArch64::ST2Twov2d;
6527 else if (Ty ==
S64 || Ty == P0)
6528 Opc = AArch64::ST1Twov1d;
6531 selectVectorStoreIntrinsic(
I, 2,
Opc);
6534 case Intrinsic::aarch64_neon_st3: {
6535 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6538 Opc = AArch64::ST3Threev8b;
6540 Opc = AArch64::ST3Threev16b;
6542 Opc = AArch64::ST3Threev4h;
6544 Opc = AArch64::ST3Threev8h;
6546 Opc = AArch64::ST3Threev2s;
6548 Opc = AArch64::ST3Threev4s;
6550 Opc = AArch64::ST3Threev2d;
6551 else if (Ty ==
S64 || Ty == P0)
6552 Opc = AArch64::ST1Threev1d;
6555 selectVectorStoreIntrinsic(
I, 3,
Opc);
6558 case Intrinsic::aarch64_neon_st4: {
6559 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6562 Opc = AArch64::ST4Fourv8b;
6564 Opc = AArch64::ST4Fourv16b;
6566 Opc = AArch64::ST4Fourv4h;
6568 Opc = AArch64::ST4Fourv8h;
6570 Opc = AArch64::ST4Fourv2s;
6572 Opc = AArch64::ST4Fourv4s;
6574 Opc = AArch64::ST4Fourv2d;
6575 else if (Ty ==
S64 || Ty == P0)
6576 Opc = AArch64::ST1Fourv1d;
6579 selectVectorStoreIntrinsic(
I, 4,
Opc);
6582 case Intrinsic::aarch64_neon_st2lane: {
6583 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6586 Opc = AArch64::ST2i8;
6588 Opc = AArch64::ST2i16;
6590 Opc = AArch64::ST2i32;
6593 Opc = AArch64::ST2i64;
6596 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6600 case Intrinsic::aarch64_neon_st3lane: {
6601 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6604 Opc = AArch64::ST3i8;
6606 Opc = AArch64::ST3i16;
6608 Opc = AArch64::ST3i32;
6611 Opc = AArch64::ST3i64;
6614 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6618 case Intrinsic::aarch64_neon_st4lane: {
6619 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6622 Opc = AArch64::ST4i8;
6624 Opc = AArch64::ST4i16;
6626 Opc = AArch64::ST4i32;
6629 Opc = AArch64::ST4i64;
6632 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6636 case Intrinsic::aarch64_mops_memset_tag: {
6649 Register DstDef =
I.getOperand(0).getReg();
6651 Register DstUse =
I.getOperand(2).getReg();
6652 Register ValUse =
I.getOperand(3).getReg();
6653 Register SizeUse =
I.getOperand(4).getReg();
6660 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6661 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6667 case Intrinsic::ptrauth_resign_load_relative: {
6668 Register DstReg =
I.getOperand(0).getReg();
6669 Register ValReg =
I.getOperand(2).getReg();
6670 uint64_t AUTKey =
I.getOperand(3).getImm();
6671 Register AUTDisc =
I.getOperand(4).getReg();
6672 uint64_t PACKey =
I.getOperand(5).getImm();
6673 Register PACDisc =
I.getOperand(6).getReg();
6674 int64_t Addend =
I.getOperand(7).getImm();
6677 uint16_t AUTConstDiscC = 0;
6678 std::tie(AUTConstDiscC, AUTAddrDisc) =
6682 uint16_t PACConstDiscC = 0;
6683 std::tie(PACConstDiscC, PACAddrDisc) =
6686 MIB.
buildCopy({AArch64::X16}, {ValReg});
6702 I.eraseFromParent();
6707 I.eraseFromParent();
6711bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6712 MachineRegisterInfo &MRI) {
6718 case Intrinsic::ptrauth_resign: {
6719 Register DstReg =
I.getOperand(0).getReg();
6720 Register ValReg =
I.getOperand(2).getReg();
6721 uint64_t AUTKey =
I.getOperand(3).getImm();
6722 Register AUTDisc =
I.getOperand(4).getReg();
6723 uint64_t PACKey =
I.getOperand(5).getImm();
6724 Register PACDisc =
I.getOperand(6).getReg();
6727 uint16_t AUTConstDiscC = 0;
6728 std::tie(AUTConstDiscC, AUTAddrDisc) =
6732 uint16_t PACConstDiscC = 0;
6733 std::tie(PACConstDiscC, PACAddrDisc) =
6736 MIB.
buildCopy({AArch64::X16}, {ValReg});
6750 I.eraseFromParent();
6753 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6754 Register DstReg =
I.getOperand(0).getReg();
6755 Register ValReg =
I.getOperand(2).getReg();
6756 uint64_t AUTKey =
I.getOperand(3).getImm();
6757 Register AUTDisc =
I.getOperand(4).getReg();
6758 Register AUTPC =
I.getOperand(5).getReg();
6759 uint64_t PACKey =
I.getOperand(6).getImm();
6760 Register PACDisc =
I.getOperand(7).getReg();
6763 "auth_with_pc_and_resign only supports IA and IB keys");
6765 uint16_t PACConstDiscC = 0;
6767 std::tie(PACConstDiscC, PACAddrDisc) =
6771 PACAddrDisc = AArch64::XZR;
6773 MIB.
buildCopy({AArch64::X17}, {ValReg});
6774 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6789 I.eraseFromParent();
6792 case Intrinsic::ptrauth_auth: {
6793 Register DstReg =
I.getOperand(0).getReg();
6794 Register ValReg =
I.getOperand(2).getReg();
6795 uint64_t AUTKey =
I.getOperand(3).getImm();
6796 Register AUTDisc =
I.getOperand(4).getReg();
6799 uint16_t AUTConstDiscC = 0;
6800 std::tie(AUTConstDiscC, AUTAddrDisc) =
6804 MIB.
buildCopy({AArch64::X16}, {ValReg});
6824 Auth.constrainAllUses(
TII,
TRI, RBI);
6828 I.eraseFromParent();
6831 case Intrinsic::frameaddress:
6832 case Intrinsic::returnaddress: {
6836 unsigned Depth =
I.getOperand(2).getImm();
6837 Register DstReg =
I.getOperand(0).getReg();
6840 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6841 if (!MFReturnAddr) {
6846 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6849 if (STI.hasPAuth()) {
6850 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6857 I.eraseFromParent();
6866 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6868 FrameAddr = NextFrame;
6871 if (IntrinID == Intrinsic::frameaddress)
6876 if (STI.hasPAuth()) {
6878 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6879 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6888 I.eraseFromParent();
6891 case Intrinsic::aarch64_neon_tbl2:
6892 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6894 case Intrinsic::aarch64_neon_tbl3:
6895 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6898 case Intrinsic::aarch64_neon_tbl4:
6899 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6901 case Intrinsic::aarch64_neon_tbx2:
6902 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6904 case Intrinsic::aarch64_neon_tbx3:
6905 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6907 case Intrinsic::aarch64_neon_tbx4:
6908 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6910 case Intrinsic::swift_async_context_addr:
6911 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6918 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6919 I.eraseFromParent();
6954bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6955 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6956 Register DefReg =
I.getOperand(0).getReg();
6957 Register Addr =
I.getOperand(1).getReg();
6959 Register AddrDisc =
I.getOperand(3).getReg();
6960 uint64_t Disc =
I.getOperand(4).getImm();
6970 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6986 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6998 const GlobalValue *GV;
7009 MachineIRBuilder MIB(
I);
7015 "unsupported non-GOT op flags on ptrauth global reference");
7017 "unsupported non-GOT reference to weak ptrauth global");
7020 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7027 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7030 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7035 I.eraseFromParent();
7047 "unsupported non-zero offset in weak ptrauth global reference");
7052 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7053 .addGlobalAddress(GV,
Offset)
7058 I.eraseFromParent();
7062void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7063 MachineRegisterInfo &MRI,
7064 unsigned NumVec,
unsigned Opc1,
7065 unsigned Opc2,
bool isExt) {
7066 Register DstReg =
I.getOperand(0).getReg();
7071 for (
unsigned i = 0; i < NumVec; i++)
7072 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7075 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7076 MachineInstrBuilder
Instr;
7083 I.eraseFromParent();
7086InstructionSelector::ComplexRendererFns
7087AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7089 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7090 return std::nullopt;
7091 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7092 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7095InstructionSelector::ComplexRendererFns
7096AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7098 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7099 return std::nullopt;
7101 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7104InstructionSelector::ComplexRendererFns
7105AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7107 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7108 return std::nullopt;
7109 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7110 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7113InstructionSelector::ComplexRendererFns
7114AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7116 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7117 return std::nullopt;
7119 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7122template <
unsigned ShiftW
idth>
7123InstructionSelector::ComplexRendererFns
7124AArch64InstructionSelector::selectShiftMask(MachineOperand &Root)
const {
7126 return std::nullopt;
7128 MachineRegisterInfo &MRI =
7135 if (ShiftWidth == 32) {
7138 ShAmtReg = ZExtSrcReg;
7147 ShAmtReg = AndSrcReg;
7159 (AddImm % ShiftWidth == 0)) {
7160 ShAmtReg = AddSrcReg;
7161 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7170 SubImm != 0 && (SubImm % ShiftWidth == 0)) {
7171 return {{[=](MachineInstrBuilder &MIB) {
7172 MachineInstr *
I = MIB.getInstr();
7175 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7176 unsigned SubOpc = ShiftWidth == 32 ? AArch64::SUBWrr : AArch64::SUBXrr;
7177 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7179 auto NegMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7180 TII.get(SubOpc), NegReg)
7194 (NotImm % ShiftWidth == ShiftWidth - 1)) {
7195 return {{[=](MachineInstrBuilder &MIB) {
7196 MachineInstr *
I = MIB.getInstr();
7199 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7200 unsigned NotOpc = ShiftWidth == 32 ? AArch64::ORNWrr : AArch64::ORNXrr;
7201 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7203 auto NotMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7204 TII.get(NotOpc), NotReg)
7214 if (ShAmtReg == Root.
getReg())
7215 return std::nullopt;
7217 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7225InstructionSelector::ComplexRendererFns
7226AArch64InstructionSelector::select12BitValueWithLeftShift(
7229 if (Immed >> 12 == 0) {
7231 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7233 Immed = Immed >> 12;
7235 return std::nullopt;
7239 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7240 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7247InstructionSelector::ComplexRendererFns
7248AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7255 if (MaybeImmed == std::nullopt)
7256 return std::nullopt;
7257 return select12BitValueWithLeftShift(*MaybeImmed);
7262InstructionSelector::ComplexRendererFns
7263AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7267 return std::nullopt;
7269 if (MaybeImmed == std::nullopt)
7270 return std::nullopt;
7277 return std::nullopt;
7283 Immed = ~((uint32_t)Immed) + 1;
7285 Immed = ~Immed + 1ULL;
7287 if (Immed & 0xFFFFFFFFFF000000ULL)
7288 return std::nullopt;
7290 Immed &= 0xFFFFFFULL;
7291 return select12BitValueWithLeftShift(Immed);
7308std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7309 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7310 if (
MI.getOpcode() == AArch64::G_SHL) {
7314 MI.getOperand(2).getReg(), MRI)) {
7315 const APInt ShiftVal = ValAndVeg->Value;
7318 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7321 return std::nullopt;
7329bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7330 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7331 bool IsAddrOperand)
const {
7336 MI.getParent()->getParent()->getFunction().hasOptSize())
7339 if (IsAddrOperand) {
7341 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7345 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7346 MachineInstr *OffsetInst =
7352 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7363 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7366InstructionSelector::ComplexRendererFns
7367AArch64InstructionSelector::selectExtendedSHL(
7368 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7369 unsigned SizeInBytes,
bool WantsExt)
const {
7370 assert(
Base.isReg() &&
"Expected base to be a register operand");
7371 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7376 unsigned OffsetOpc = OffsetInst->
getOpcode();
7377 bool LookedThroughZExt =
false;
7378 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7380 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7381 return std::nullopt;
7385 LookedThroughZExt =
true;
7387 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7388 return std::nullopt;
7391 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7392 if (LegalShiftVal == 0)
7393 return std::nullopt;
7394 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7395 return std::nullopt;
7406 if (OffsetOpc == TargetOpcode::G_SHL)
7407 return std::nullopt;
7413 return std::nullopt;
7418 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7422 if (OffsetOpc == TargetOpcode::G_MUL) {
7424 return std::nullopt;
7430 if ((ImmVal & 0x7) != ImmVal)
7431 return std::nullopt;
7435 if (ImmVal != LegalShiftVal)
7436 return std::nullopt;
7438 unsigned SignExtend = 0;
7442 if (!LookedThroughZExt) {
7444 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7446 return std::nullopt;
7451 return std::nullopt;
7457 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7462 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7463 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7464 [=](MachineInstrBuilder &MIB) {
7467 MIB.addImm(SignExtend);
7480InstructionSelector::ComplexRendererFns
7481AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7482 MachineOperand &Root,
unsigned SizeInBytes)
const {
7484 return std::nullopt;
7499 MachineInstr *PtrAdd =
7501 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7502 return std::nullopt;
7506 MachineInstr *OffsetInst =
7508 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7521InstructionSelector::ComplexRendererFns
7522AArch64InstructionSelector::selectAddrModeRegisterOffset(
7523 MachineOperand &Root)
const {
7529 return std::nullopt;
7535 return std::nullopt;
7538 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7539 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7540 [=](MachineInstrBuilder &MIB) {
7550InstructionSelector::ComplexRendererFns
7551AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7552 unsigned SizeInBytes)
const {
7555 return std::nullopt;
7556 MachineInstr *PtrAdd =
7559 return std::nullopt;
7577 unsigned Scale =
Log2_32(SizeInBytes);
7578 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7582 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7583 ImmOff < (0x1000 << Scale))
7584 return std::nullopt;
7589 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7593 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7599 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7600 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7605 return std::nullopt;
7609 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7615 return selectAddrModeRegisterOffset(Root);
7624InstructionSelector::ComplexRendererFns
7625AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7626 unsigned SizeInBytes)
const {
7629 MachineInstr *PtrAdd =
7631 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7632 return std::nullopt;
7653 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7662 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7663 return std::nullopt;
7667 getExtendTypeForInst(*OffsetInst, MRI,
true);
7669 return std::nullopt;
7672 MachineIRBuilder MIB(*PtrAdd);
7674 AArch64::GPR32RegClass, MIB);
7678 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7679 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7680 [=](MachineInstrBuilder &MIB) {
7681 MIB.addImm(SignExtend);
7691InstructionSelector::ComplexRendererFns
7692AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7693 unsigned Size)
const {
7694 MachineRegisterInfo &MRI =
7698 return std::nullopt;
7700 if (!isBaseWithConstantOffset(Root, MRI))
7701 return std::nullopt;
7705 MachineOperand &OffImm = RootDef->
getOperand(2);
7706 if (!OffImm.
isReg())
7707 return std::nullopt;
7709 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7710 return std::nullopt;
7712 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7714 return std::nullopt;
7717 if (RHSC >= -256 && RHSC < 256) {
7720 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7721 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7724 return std::nullopt;
7727InstructionSelector::ComplexRendererFns
7728AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7730 MachineRegisterInfo &MRI)
const {
7731 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7732 return std::nullopt;
7735 return std::nullopt;
7740 return std::nullopt;
7744 return std::nullopt;
7748 return std::nullopt;
7751 MachineIRBuilder MIRBuilder(RootDef);
7753 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7754 [=](MachineInstrBuilder &MIB) {
7755 MIB.addGlobalAddress(GV,
Offset,
7764InstructionSelector::ComplexRendererFns
7765AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7766 unsigned Size)
const {
7771 return std::nullopt;
7774 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7776 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7777 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7785 MachineInstr *RootParent = Root.
getParent();
7787 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7789 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7794 if (isBaseWithConstantOffset(Root, MRI)) {
7802 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7803 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7805 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7806 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7810 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7811 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7818 if (selectAddrModeUnscaled(Root,
Size))
7819 return std::nullopt;
7822 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7823 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7830 switch (
MI.getOpcode()) {
7833 case TargetOpcode::G_SHL:
7835 case TargetOpcode::G_LSHR:
7837 case TargetOpcode::G_ASHR:
7839 case TargetOpcode::G_ROTR:
7846InstructionSelector::ComplexRendererFns
7847AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7848 bool AllowROR)
const {
7850 return std::nullopt;
7851 MachineRegisterInfo &MRI =
7859 return std::nullopt;
7861 return std::nullopt;
7862 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7863 return std::nullopt;
7866 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7869 return std::nullopt;
7873 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7877 unsigned Val = *Immed & (NumBits - 1);
7880 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7881 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7885 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7886 unsigned Opc =
MI.getOpcode();
7889 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7891 if (
Opc == TargetOpcode::G_SEXT)
7894 Size =
MI.getOperand(2).getImm();
7895 assert(
Size != 64 &&
"Extend from 64 bits?");
7908 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7910 assert(
Size != 64 &&
"Extend from 64 bits?");
7925 if (
Opc != TargetOpcode::G_AND)
7944Register AArch64InstructionSelector::moveScalarRegClass(
7946 MachineRegisterInfo &MRI = *MIB.
getMRI();
7956 return Copy.getReg(0);
7961InstructionSelector::ComplexRendererFns
7962AArch64InstructionSelector::selectArithExtendedRegister(
7963 MachineOperand &Root)
const {
7965 return std::nullopt;
7966 MachineRegisterInfo &MRI =
7974 return std::nullopt;
7976 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7977 return std::nullopt;
7980 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7985 return std::nullopt;
7986 ShiftVal = *MaybeShiftVal;
7988 return std::nullopt;
7993 return std::nullopt;
7994 Ext = getExtendTypeForInst(*ExtDef, MRI);
7996 return std::nullopt;
8000 Ext = getExtendTypeForInst(*RootDef, MRI);
8002 return std::nullopt;
8010 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
8011 if (isDef32(*ExtInst))
8012 return std::nullopt;
8018 MachineIRBuilder MIB(*RootDef);
8019 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
8021 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
8022 [=](MachineInstrBuilder &MIB) {
8023 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
8027InstructionSelector::ComplexRendererFns
8028AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
8030 return std::nullopt;
8031 MachineRegisterInfo &MRI =
8035 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
8040 return std::nullopt;
8043 if (Unmerge->getNumDefs() == 2 &&
8045 Register ExtReg = Unmerge->getSourceReg();
8046 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8050 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
8054 LaneIdx->Value.getSExtValue() == 1) {
8055 Register ExtReg = ExtElt->getVectorReg();
8056 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8060 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
8061 auto LaneIdx = Subvec->getIndexImm();
8063 Register ExtReg = Subvec->getSrcVec();
8064 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8068 return std::nullopt;
8071InstructionSelector::ComplexRendererFns
8072AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
8073 unsigned DstElemWidth,
8074 bool isReciprocal)
const {
8076 return std::nullopt;
8077 const MachineRegisterInfo &MRI =
8083 if (Dup && Dup->
getOpcode() == TargetOpcode::G_SPLAT_VECTOR)
8086 std::optional<ValueAndVReg> CstVal =
8090 return std::nullopt;
8094 switch (CstElemWidth) {
8096 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value.trunc(CstElemWidth));
8099 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8102 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8105 return std::nullopt;
8107 if (
unsigned FBits =
8109 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8111 return std::nullopt;
8114unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8115 const MachineOperand &Root)
const {
8123template <
unsigned W
idth>
8124InstructionSelector::ComplexRendererFns
8125AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8126 return selectCVTFixedPointBase(Root, Width,
false);
8129template <
unsigned W
idth>
8130InstructionSelector::ComplexRendererFns
8131AArch64InstructionSelector::selectCVTFixedPosRecipOperand(
8132 MachineOperand &Root)
const {
8133 return selectCVTFixedPointBase(Root, Width,
true);
8136InstructionSelector::ComplexRendererFns
8137AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8138 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8142InstructionSelector::ComplexRendererFns
8143AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8144 MachineOperand &Root)
const {
8145 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8149void AArch64InstructionSelector::renderFixedPointScalarXForm(
8150 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8151 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8152 "Expected vecshift immediate operand");
8153 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8156void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8157 const MachineOperand &Root,
8159 bool isReciprocal)
const {
8163 InstructionSelector::ComplexRendererFns Renderer =
8164 selectCVTFixedPointBase(Root, Width, isReciprocal);
8165 assert((Renderer && Renderer->size() == 1) &&
8166 "Expected selectCVTFixedPointBase to provide a function\n");
8167 (Renderer->front())(MIB);
8170void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8171 const MachineInstr &
MI,
8173 const MachineOperand &Root =
MI.getOperand(OpIdx);
8174 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8178void AArch64InstructionSelector::renderFixedPointRecipXForm(
8179 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8180 const MachineOperand &Root =
MI.getOperand(OpIdx);
8181 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8185void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8186 const MachineInstr &
MI,
8188 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8189 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8190 "Expected G_CONSTANT");
8191 std::optional<int64_t> CstVal =
8193 assert(CstVal &&
"Expected constant value");
8197void AArch64InstructionSelector::renderLogicalImm32(
8198 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8199 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8200 "Expected G_CONSTANT");
8201 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8206void AArch64InstructionSelector::renderLogicalImm64(
8207 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8208 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8209 "Expected G_CONSTANT");
8210 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8215void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8216 const MachineInstr &
MI,
8218 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8219 "Expected G_UBSANTRAP");
8220 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8223void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8224 const MachineInstr &
MI,
8226 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8227 "Expected G_FCONSTANT");
8232void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8233 const MachineInstr &
MI,
8235 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8236 "Expected G_FCONSTANT");
8241void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8242 const MachineInstr &
MI,
8244 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8245 "Expected G_FCONSTANT");
8250void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8251 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8252 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8253 "Expected G_FCONSTANT");
8261bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8262 const MachineInstr &
MI,
unsigned NumBytes)
const {
8263 if (!
MI.mayLoadOrStore())
8266 "Expected load/store to have only one mem op!");
8267 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8270bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8271 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8279 switch (
MI.getOpcode()) {
8282 case TargetOpcode::COPY:
8283 case TargetOpcode::G_BITCAST:
8284 case TargetOpcode::G_TRUNC:
8285 case TargetOpcode::G_PHI:
8295 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8298 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8316 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8321 MO.setReg(Copy.getReg(0));
8330 for (
auto &BB : MF) {
8331 for (
auto &
MI : BB) {
8332 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8337 for (
auto *
MI : Phis) {
8359 bool HasGPROp =
false, HasFPROp =
false;
8363 const LLT &Ty = MRI.
getType(MO.getReg());
8373 if (RB->
getID() == AArch64::GPRRegBankID)
8379 if (HasGPROp && HasFPROp)
8385InstructionSelector *
8389 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 bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
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 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 emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
#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 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 std::optional< APInt > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc, appropriate for the register ban...
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 std::optional< uint64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
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 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 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
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)
static MachineBasicBlock * emitSelect(MachineInstr &MI, MachineBasicBlock *BB, const TargetInstrInfo *TII, const PPCSubtarget &Subtarget)
Emit SELECT instruction, using ISEL if available, otherwise use branch-based control flow.
static StringRef getName(Value *V)
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
bool hasELFSignedGOT() const
int getVarArgsFPRIndex() const
void incNumLocalDynamicTLSAccesses()
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.
uint64_t getZExtValue() const
Get zero extended value.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
unsigned countr_one() const
Count the number of trailing one bits.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValue() const
const APFloat & getValueAPF() const
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.
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
LLVM_ABI 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.
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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 & setOperandDead(unsigned OpIdx) 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
bool isDebugInstr() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
void setImplicitPhysRegDefsDead()
Mark the implicit physreg defs named by the instruction description as dead.
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 LLVM_READONLY 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.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified 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.
const MachineFunction & getMF() const
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.
void assign(size_type NumElts, ValueParamT Elt)
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.
unsigned TLSSize
Bit size of immediate TLS offsets (0 == use the default).
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.
@ 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_HI12
MO_HI12 - This flag indicates that a symbol operand represents the bits 13-24 of a 64-bit address,...
@ 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 int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
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 isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
bool expandVectorMOVImm(APInt Imm, SmallVectorImpl< ImmInsnModel > &Insn, const AArch64Subtarget &ST)
TLSModel::Model getELFTLSModel(const GlobalValue *GV, const AArch64TargetMachine &TM, bool HasELFSignedGOT)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
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.
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)
auto m_PosZeroFP()
Matches a floating-point positive zero.
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.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
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.
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
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.
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.
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...
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
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.
@ O1
Optimize quickly without destroying debuggability.
@ O0
Disable as many optimizations as possible.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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 std::optional< Register > getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
MCRegisterClass TargetRegisterClass
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.