45#include "llvm/IR/IntrinsicsAArch64.h"
52#define DEBUG_TYPE "aarch64-isel"
65#define GET_GLOBALISEL_PREDICATE_BITSET
66#include "AArch64GenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATE_BITSET
87 ProduceNonFlagSettingCondBr =
135 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
213 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
215 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
217 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
219 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
237 unsigned Opc1,
unsigned Opc2,
bool isExt);
243 unsigned emitConstantPoolEntry(
const Constant *CPVal,
262 std::optional<CmpInst::Predicate> = std::nullopt)
const;
265 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
266 std::initializer_list<llvm::SrcOp> SrcOps,
268 const ComplexRendererFns &RenderFns = std::nullopt)
const;
303 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
326 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
348 std::pair<MachineInstr *, AArch64CC::CondCode>
383 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
384 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
385 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
386 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
388 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
390 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
393 unsigned Size)
const;
395 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
396 return selectAddrModeUnscaled(Root, 1);
398 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
399 return selectAddrModeUnscaled(Root, 2);
401 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
402 return selectAddrModeUnscaled(Root, 4);
404 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
405 return selectAddrModeUnscaled(Root, 8);
407 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
408 return selectAddrModeUnscaled(Root, 16);
413 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
417 unsigned Size)
const;
419 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
420 return selectAddrModeIndexed(Root, Width / 8);
429 bool IsAddrOperand)
const;
432 unsigned SizeInBytes)
const;
440 bool WantsExt)
const;
441 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
443 unsigned SizeInBytes)
const;
445 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
446 return selectAddrModeXRO(Root, Width / 8);
450 unsigned SizeInBytes)
const;
452 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
453 return selectAddrModeWRO(Root, Width / 8);
457 bool AllowROR =
false)
const;
459 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
460 return selectShiftedRegister(Root);
463 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
464 return selectShiftedRegister(Root,
true);
474 bool IsLoadStore =
false)
const;
485 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
488 template <
unsigned W
idth>
489 ComplexRendererFns selectCVTFixedPoint(
MachineOperand &Root)
const;
490 ComplexRendererFns selectCVTFixedPointBase(
const MachineOperand &Root,
492 bool isReciprocal =
false)
const;
493 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
498 unsigned getFixedPointWidthFromOperand(
const MachineOperand &Root)
const;
500 int OpIdx = -1)
const;
504 unsigned Width,
bool isReciprocal)
const;
506 int OpIdx = -1)
const;
508 int OpIdx = -1)
const;
510 int OpIdx = -1)
const;
514 int OpIdx = -1)
const;
516 int OpIdx = -1)
const;
518 int OpIdx = -1)
const;
521 int OpIdx = -1)
const;
527 bool tryOptSelect(
GSelect &Sel);
534 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
547 bool ProduceNonFlagSettingCondBr =
false;
556#define GET_GLOBALISEL_PREDICATES_DECL
557#include "AArch64GenGlobalISel.inc"
558#undef GET_GLOBALISEL_PREDICATES_DECL
562#define GET_GLOBALISEL_TEMPORARIES_DECL
563#include "AArch64GenGlobalISel.inc"
564#undef GET_GLOBALISEL_TEMPORARIES_DECL
569#define GET_GLOBALISEL_IMPL
570#include "AArch64GenGlobalISel.inc"
571#undef GET_GLOBALISEL_IMPL
573AArch64InstructionSelector::AArch64InstructionSelector(
576 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
579#include
"AArch64GenGlobalISel.inc"
582#include
"AArch64GenGlobalISel.inc"
594 bool GetAllRegSet =
false) {
595 if (RB.
getID() == AArch64::GPRRegBankID) {
596 if (Ty.getSizeInBits() <= 32)
597 return GetAllRegSet ? &AArch64::GPR32allRegClass
598 : &AArch64::GPR32RegClass;
599 if (Ty.getSizeInBits() == 64)
600 return GetAllRegSet ? &AArch64::GPR64allRegClass
601 : &AArch64::GPR64RegClass;
602 if (Ty.getSizeInBits() == 128)
603 return &AArch64::XSeqPairsClassRegClass;
607 if (RB.
getID() == AArch64::FPRRegBankID) {
608 switch (Ty.getSizeInBits()) {
610 return &AArch64::FPR8RegClass;
612 return &AArch64::FPR16RegClass;
614 return &AArch64::FPR32RegClass;
616 return &AArch64::FPR64RegClass;
618 return &AArch64::FPR128RegClass;
630 bool GetAllRegSet =
false) {
633 "Expected FPR regbank for scalable type size");
634 return &AArch64::ZPRRegClass;
637 unsigned RegBankID = RB.
getID();
639 if (RegBankID == AArch64::GPRRegBankID) {
641 if (SizeInBits <= 32)
642 return GetAllRegSet ? &AArch64::GPR32allRegClass
643 : &AArch64::GPR32RegClass;
644 if (SizeInBits == 64)
645 return GetAllRegSet ? &AArch64::GPR64allRegClass
646 : &AArch64::GPR64RegClass;
647 if (SizeInBits == 128)
648 return &AArch64::XSeqPairsClassRegClass;
651 if (RegBankID == AArch64::FPRRegBankID) {
654 "Unexpected scalable register size");
655 return &AArch64::ZPRRegClass;
658 switch (SizeInBits) {
662 return &AArch64::FPR8RegClass;
664 return &AArch64::FPR16RegClass;
666 return &AArch64::FPR32RegClass;
668 return &AArch64::FPR64RegClass;
670 return &AArch64::FPR128RegClass;
680 switch (
TRI.getRegSizeInBits(*RC)) {
682 SubReg = AArch64::bsub;
685 SubReg = AArch64::hsub;
688 if (RC != &AArch64::FPR32RegClass)
689 SubReg = AArch64::sub_32;
691 SubReg = AArch64::ssub;
694 SubReg = AArch64::dsub;
698 dbgs() <<
"Couldn't find appropriate subregister for register class.");
707 switch (RB.
getID()) {
708 case AArch64::GPRRegBankID:
710 case AArch64::FPRRegBankID:
733 const unsigned RegClassIDs[],
735 unsigned NumRegs = Regs.
size();
738 assert(NumRegs >= 2 && NumRegs <= 4 &&
739 "Only support between two and 4 registers in a tuple!");
741 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
743 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
744 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
745 RegSequence.addUse(Regs[
I]);
746 RegSequence.addImm(SubRegs[
I]);
748 return RegSequence.getReg(0);
753 static const unsigned RegClassIDs[] = {
754 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
755 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
756 AArch64::dsub2, AArch64::dsub3};
757 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
762 static const unsigned RegClassIDs[] = {
763 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
764 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
765 AArch64::qsub2, AArch64::qsub3};
766 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
771 auto &
MBB = *
MI.getParent();
772 auto &MF = *
MBB.getParent();
773 auto &MRI = MF.getRegInfo();
779 else if (Root.
isReg()) {
784 Immed = ValAndVReg->Value.getSExtValue();
795 if (RegBankID == AArch64::GPRRegBankID) {
797 switch (GenericOpc) {
798 case TargetOpcode::G_SHL:
799 return AArch64::LSLVWr;
800 case TargetOpcode::G_LSHR:
801 return AArch64::LSRVWr;
802 case TargetOpcode::G_ASHR:
803 return AArch64::ASRVWr;
807 }
else if (OpSize == 64) {
808 switch (GenericOpc) {
809 case TargetOpcode::G_SHL:
810 return AArch64::LSLVXr;
811 case TargetOpcode::G_LSHR:
812 return AArch64::LSRVXr;
813 case TargetOpcode::G_ASHR:
814 return AArch64::ASRVXr;
830 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
832 case AArch64::GPRRegBankID:
835 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
837 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
839 return isStore ? AArch64::STRWui : AArch64::LDRWui;
841 return isStore ? AArch64::STRXui : AArch64::LDRXui;
844 case AArch64::FPRRegBankID:
847 return isStore ? AArch64::STRBui : AArch64::LDRBui;
849 return isStore ? AArch64::STRHui : AArch64::LDRHui;
851 return isStore ? AArch64::STRSui : AArch64::LDRSui;
853 return isStore ? AArch64::STRDui : AArch64::LDRDui;
855 return isStore ? AArch64::STRQui : AArch64::LDRQui;
869 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
870 assert(To &&
"Destination register class cannot be null");
871 assert(SubReg &&
"Expected a valid subregister");
875 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
877 RegOp.
setReg(SubRegCopy.getReg(0));
881 if (!
I.getOperand(0).getReg().isPhysical())
898 if (
Reg.isPhysical())
906 RC = getRegClassForTypeOnBank(Ty, RB);
909 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
922 Register DstReg =
I.getOperand(0).getReg();
923 Register SrcReg =
I.getOperand(1).getReg();
954 if (
I.getOpcode() == TargetOpcode::G_BITCAST &&
956 if (DstRegBank.
getID() == AArch64::FPRRegBankID &&
957 SrcRegBank.
getID() == AArch64::GPRRegBankID) {
966 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::FMOVWSr))
969 I.setDesc(
TII.get(TargetOpcode::COPY));
970 I.getOperand(1).setReg(FPR32);
971 I.getOperand(1).setSubReg(AArch64::hsub);
975 if (DstRegBank.
getID() == AArch64::GPRRegBankID &&
976 SrcRegBank.
getID() == AArch64::FPRRegBankID) {
986 TII.get(TargetOpcode::SUBREG_TO_REG))
990 I.setDesc(
TII.get(AArch64::FMOVSWr));
991 I.getOperand(1).setReg(FPR32);
1000 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1004 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1005 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1006 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
1020 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1021 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
1022 }
else if (SrcSize > DstSize) {
1029 }
else if (DstSize > SrcSize) {
1038 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1042 RegOp.
setReg(PromoteReg);
1061 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1062 I.setDesc(
TII.get(AArch64::COPY));
1063 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1067 I.setDesc(
TII.get(AArch64::COPY));
1075 MachineRegisterInfo &MRI = *MIB.
getMRI();
1078 "Expected both select operands to have the same regbank?");
1084 "Expected 32 bit or 64 bit select only?");
1085 const bool Is32Bit =
Size == 32;
1087 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1088 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1094 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1096 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1111 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1128 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1147 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1163 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1169 if (!TrueCst && !FalseCst)
1172 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1173 if (TrueCst && FalseCst) {
1174 int64_t
T = TrueCst->Value.getSExtValue();
1175 int64_t
F = FalseCst->Value.getSExtValue();
1177 if (
T == 0 &&
F == 1) {
1179 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1185 if (
T == 0 &&
F == -1) {
1187 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1195 int64_t
T = TrueCst->Value.getSExtValue();
1198 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1207 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1216 int64_t
F = FalseCst->Value.getSExtValue();
1219 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1226 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1234 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1235 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1237 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1239 return &*SelectInst;
1244 MachineRegisterInfo *MRI =
nullptr) {
1257 if (ValAndVReg && ValAndVReg->Value == 0)
1264 if (ValAndVReg && ValAndVReg->Value == 0)
1368 assert(
Reg.isValid() &&
"Expected valid register!");
1369 bool HasZext =
false;
1371 unsigned Opc =
MI->getOpcode();
1373 if (!
MI->getOperand(0).isReg() ||
1382 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1383 Opc == TargetOpcode::G_TRUNC) {
1384 if (
Opc == TargetOpcode::G_ZEXT)
1387 Register NextReg =
MI->getOperand(1).getReg();
1401 std::optional<uint64_t>
C;
1406 case TargetOpcode::G_AND:
1407 case TargetOpcode::G_XOR: {
1408 TestReg =
MI->getOperand(1).getReg();
1409 Register ConstantReg =
MI->getOperand(2).getReg();
1420 C = VRegAndVal->Value.getZExtValue();
1422 C = VRegAndVal->Value.getSExtValue();
1426 case TargetOpcode::G_ASHR:
1427 case TargetOpcode::G_LSHR:
1428 case TargetOpcode::G_SHL: {
1429 TestReg =
MI->getOperand(1).getReg();
1433 C = VRegAndVal->Value.getSExtValue();
1449 case TargetOpcode::G_AND:
1451 if ((*
C >> Bit) & 1)
1454 case TargetOpcode::G_SHL:
1457 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1462 case TargetOpcode::G_ASHR:
1467 if (Bit >= TestRegSize)
1468 Bit = TestRegSize - 1;
1470 case TargetOpcode::G_LSHR:
1472 if ((Bit + *
C) < TestRegSize) {
1477 case TargetOpcode::G_XOR:
1486 if ((*
C >> Bit) & 1)
1501MachineInstr *AArch64InstructionSelector::emitTestBit(
1502 Register TestReg,
uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1503 MachineIRBuilder &MIB)
const {
1505 assert(ProduceNonFlagSettingCondBr &&
1506 "Cannot emit TB(N)Z with speculation tracking!");
1507 MachineRegisterInfo &MRI = *MIB.
getMRI();
1511 LLT Ty = MRI.
getType(TestReg);
1514 assert(Bit < 64 &&
"Bit is too large!");
1518 bool UseWReg =
Bit < 32;
1519 unsigned NecessarySize = UseWReg ? 32 : 64;
1520 if (
Size != NecessarySize)
1521 TestReg = moveScalarRegClass(
1522 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1525 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1526 {AArch64::TBZW, AArch64::TBNZW}};
1527 unsigned Opc = OpcTable[UseWReg][IsNegative];
1534bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1535 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1536 MachineIRBuilder &MIB)
const {
1537 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1564 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1571 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1575MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1577 MachineBasicBlock *DestMBB,
1578 MachineIRBuilder &MIB)
const {
1579 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1580 MachineRegisterInfo &MRI = *MIB.
getMRI();
1582 AArch64::GPRRegBankID &&
1583 "Expected GPRs only?");
1584 auto Ty = MRI.
getType(CompareReg);
1587 assert(Width <= 64 &&
"Expected width to be at most 64?");
1588 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1589 {AArch64::CBNZW, AArch64::CBNZX}};
1590 unsigned Opc = OpcTable[IsNegative][Width == 64];
1591 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1596bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1597 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1599 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1607 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1611 I.eraseFromParent();
1615bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1616 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1618 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1624 if (!ProduceNonFlagSettingCondBr)
1627 MachineRegisterInfo &MRI = *MIB.
getMRI();
1628 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1643 if (VRegAndVal && !AndInst) {
1644 int64_t
C = VRegAndVal->Value.getSExtValue();
1650 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1651 I.eraseFromParent();
1659 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1660 I.eraseFromParent();
1668 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1669 I.eraseFromParent();
1683 if (VRegAndVal && VRegAndVal->Value == 0) {
1691 tryOptAndIntoCompareBranch(
1693 I.eraseFromParent();
1699 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1701 I.eraseFromParent();
1710bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1711 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1713 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1714 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1718 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1725 I.eraseFromParent();
1729bool AArch64InstructionSelector::selectCompareBranch(
1731 Register CondReg =
I.getOperand(0).getReg();
1732 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1736 if (CCMIOpc == TargetOpcode::G_FCMP)
1737 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1738 if (CCMIOpc == TargetOpcode::G_ICMP)
1739 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1744 if (ProduceNonFlagSettingCondBr) {
1745 emitTestBit(CondReg, 0,
true,
1746 I.getOperand(1).getMBB(), MIB);
1747 I.eraseFromParent();
1757 .
addMBB(
I.getOperand(1).getMBB());
1758 I.eraseFromParent();
1778 return std::nullopt;
1780 int64_t
Imm = *ShiftImm;
1782 return std::nullopt;
1783 switch (SrcTy.getElementType().getSizeInBits()) {
1786 return std::nullopt;
1789 return std::nullopt;
1793 return std::nullopt;
1797 return std::nullopt;
1801 return std::nullopt;
1807bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1808 MachineRegisterInfo &MRI) {
1809 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1810 Register DstReg =
I.getOperand(0).getReg();
1811 const LLT Ty = MRI.
getType(DstReg);
1812 Register Src1Reg =
I.getOperand(1).getReg();
1813 Register Src2Reg =
I.getOperand(2).getReg();
1824 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1826 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1828 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1830 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1832 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1834 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1836 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1848 I.eraseFromParent();
1852bool AArch64InstructionSelector::selectVectorAshrLshr(
1853 MachineInstr &
I, MachineRegisterInfo &MRI) {
1854 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1855 I.getOpcode() == TargetOpcode::G_LSHR);
1856 Register DstReg =
I.getOperand(0).getReg();
1857 const LLT Ty = MRI.
getType(DstReg);
1858 Register Src1Reg =
I.getOperand(1).getReg();
1859 Register Src2Reg =
I.getOperand(2).getReg();
1864 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1874 unsigned NegOpc = 0;
1876 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1878 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1879 NegOpc = AArch64::NEGv2i64;
1881 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1882 NegOpc = AArch64::NEGv4i32;
1884 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1885 NegOpc = AArch64::NEGv2i32;
1887 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1888 NegOpc = AArch64::NEGv4i16;
1890 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1891 NegOpc = AArch64::NEGv8i16;
1893 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1894 NegOpc = AArch64::NEGv16i8;
1896 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1897 NegOpc = AArch64::NEGv8i8;
1903 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1907 I.eraseFromParent();
1911bool AArch64InstructionSelector::selectVaStartAAPCS(
1921 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1923 const auto *PtrRegClass =
1924 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1926 const MCInstrDesc &MCIDAddAddr =
1928 const MCInstrDesc &MCIDStoreAddr =
1940 const auto VAList =
I.getOperand(0).getReg();
1943 unsigned OffsetBytes = 0;
1947 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1949 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1956 const auto *MMO = *
I.memoperands_begin();
1957 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1960 .
addImm(OffsetBytes / PtrSize)
1962 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1966 OffsetBytes += PtrSize;
1982 const auto PushIntConstant = [&](
const int32_t
Value) {
1983 constexpr int IntSize = 4;
1986 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
1991 const auto *MMO = *
I.memoperands_begin();
1992 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
1995 .
addImm(OffsetBytes / IntSize)
1997 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2000 OffsetBytes += IntSize;
2004 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2007 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2011 I.eraseFromParent();
2015bool AArch64InstructionSelector::selectVaStartDarwin(
2017 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2018 Register ListReg =
I.getOperand(0).getReg();
2023 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2031 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2039 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2046 I.eraseFromParent();
2050void AArch64InstructionSelector::materializeLargeCMVal(
2051 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2056 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2071 GV, MovZ->getOperand(1).getOffset(), Flags));
2075 MovZ->getOperand(1).getOffset(), Flags));
2081 Register DstReg = BuildMovK(MovZ.getReg(0),
2087bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2092 switch (
I.getOpcode()) {
2093 case TargetOpcode::G_CONSTANT: {
2094 Register DefReg =
I.getOperand(0).getReg();
2095 const LLT DefTy = MRI.
getType(DefReg);
2101 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2102 I.getOperand(1).setCImm(
2107 I.getOperand(0).setReg(WideReg);
2116 if (PtrSize != 32 && PtrSize != 64)
2122 case TargetOpcode::G_STORE: {
2123 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2124 MachineOperand &SrcOp =
I.getOperand(0);
2137 case TargetOpcode::G_PTR_ADD: {
2141 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2143 return convertPtrAddToAdd(
I, MRI);
2145 case TargetOpcode::G_LOAD: {
2150 Register DstReg =
I.getOperand(0).getReg();
2151 const LLT DstTy = MRI.
getType(DstReg);
2157 case TargetOpcode::G_VECREDUCE_ADD:
2158 case TargetOpcode::G_VECREDUCE_SMAX:
2159 case TargetOpcode::G_VECREDUCE_SMIN:
2160 case TargetOpcode::G_VECREDUCE_UMAX:
2161 case TargetOpcode::G_VECREDUCE_UMIN: {
2164 Register DstReg =
I.getOperand(0).getReg();
2165 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2166 if (DstRB.
getID() != AArch64::GPRRegBankID)
2169 LLT DstTy = MRI.
getType(DstReg);
2171 getRegClassForTypeOnBank(DstTy, DstRB,
true);
2177 I.getOperand(0).setReg(FPRDst);
2179 BuildMI(
MBB, std::next(
I.getIterator()), MIMetadata(
I),
2180 TII.get(TargetOpcode::COPY), DstReg)
2184 case AArch64::G_DUP: {
2186 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2190 MRI.
setType(
I.getOperand(0).getReg(),
2192 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2193 I.getOperand(1).setReg(NewSrc.getReg(0));
2196 case AArch64::G_INSERT_VECTOR_ELT: {
2197 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2198 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2202 MRI.
setType(
I.getOperand(1).getReg(),
2204 MRI.
setType(
I.getOperand(0).getReg(),
2206 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2207 I.getOperand(2).setReg(NewSrc.getReg(0));
2211 Register EltReg =
I.getOperand(2).getReg();
2212 LLT EltTy = MRI.
getType(EltReg);
2218 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2219 I.getOperand(2).setReg(NewElt.getReg(0));
2224 case TargetOpcode::G_UITOFP:
2225 case TargetOpcode::G_SITOFP: {
2230 Register SrcReg =
I.getOperand(1).getReg();
2231 LLT SrcTy = MRI.
getType(SrcReg);
2232 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2241 I.getOperand(1).setReg(
Copy.getReg(0));
2243 getRegClassForTypeOnBank(
2244 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2246 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2247 I.setDesc(
TII.get(AArch64::G_SITOF));
2249 I.setDesc(
TII.get(AArch64::G_UITOF));
2267bool AArch64InstructionSelector::convertPtrAddToAdd(
2268 MachineInstr &
I, MachineRegisterInfo &MRI) {
2269 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2270 Register DstReg =
I.getOperand(0).getReg();
2271 Register AddOp1Reg =
I.getOperand(1).getReg();
2272 const LLT PtrTy = MRI.
getType(DstReg);
2276 const LLT CastPtrTy = PtrTy.
isVector()
2288 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2289 MRI.
setType(DstReg, CastPtrTy);
2290 I.getOperand(1).setReg(PtrToInt.getReg(0));
2291 if (!select(*PtrToInt)) {
2292 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2301 I.getOperand(2).setReg(NegatedReg);
2302 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2306bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2307 MachineRegisterInfo &MRI) {
2311 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2312 const auto &MO =
I.getOperand(2);
2317 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2321 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2322 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2324 if (!Imm1Fn || !Imm2Fn)
2328 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2329 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2331 for (
auto &RenderFn : *Imm1Fn)
2333 for (
auto &RenderFn : *Imm2Fn)
2336 I.eraseFromParent();
2341bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2342 MachineInstr &
I, MachineRegisterInfo &MRI) {
2343 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2361 LLT DefDstTy = MRI.
getType(DefDstReg);
2362 Register StoreSrcReg =
I.getOperand(0).getReg();
2363 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2379 I.getOperand(0).setReg(DefDstReg);
2383bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2384 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2385 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2391 switch (
I.getOpcode()) {
2392 case AArch64::G_DUP: {
2395 Register Src =
I.getOperand(1).getReg();
2397 Src, MRI,
true,
true);
2401 Register Dst =
I.getOperand(0).getReg();
2407 if (!emitConstantVector(Dst, CV, MIB, MRI))
2409 I.eraseFromParent();
2412 case TargetOpcode::G_SEXT:
2415 if (selectUSMovFromExtend(
I, MRI))
2418 case TargetOpcode::G_BR:
2420 case TargetOpcode::G_SHL:
2421 return earlySelectSHL(
I, MRI);
2422 case TargetOpcode::G_CONSTANT: {
2423 bool IsZero =
false;
2424 if (
I.getOperand(1).isCImm())
2425 IsZero =
I.getOperand(1).getCImm()->isZero();
2426 else if (
I.getOperand(1).isImm())
2427 IsZero =
I.getOperand(1).getImm() == 0;
2432 Register DefReg =
I.getOperand(0).getReg();
2435 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2438 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2443 I.setDesc(
TII.get(TargetOpcode::COPY));
2447 case TargetOpcode::G_ADD: {
2456 Register AddDst =
I.getOperand(0).getReg();
2457 Register AddLHS =
I.getOperand(1).getReg();
2458 Register AddRHS =
I.getOperand(2).getReg();
2468 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2489 MachineInstr *
Cmp = MatchCmp(AddRHS);
2493 Cmp = MatchCmp(AddRHS);
2497 auto &PredOp =
Cmp->getOperand(1);
2499 emitIntegerCompare(
Cmp->getOperand(2),
2500 Cmp->getOperand(3), PredOp, MIB);
2504 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2505 I.eraseFromParent();
2508 case TargetOpcode::G_OR: {
2512 Register Dst =
I.getOperand(0).getReg();
2532 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2535 int64_t Immr =
Size - ShiftImm;
2536 int64_t Imms =
Size - ShiftImm - 1;
2537 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2538 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2539 I.eraseFromParent();
2542 case TargetOpcode::G_FENCE: {
2543 if (
I.getOperand(1).getImm() == 0)
2547 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2548 I.eraseFromParent();
2556bool AArch64InstructionSelector::select(MachineInstr &
I) {
2557 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2558 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2564 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2565 if (Subtarget->requiresStrictAlign()) {
2567 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2573 unsigned Opcode =
I.getOpcode();
2575 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2578 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2583 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2584 const Register DefReg =
I.getOperand(0).getReg();
2585 const LLT DefTy = MRI.
getType(DefReg);
2598 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2605 I.setDesc(
TII.get(TargetOpcode::PHI));
2613 if (
I.isDebugInstr())
2620 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2622 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2629 if (preISelLower(
I)) {
2630 Opcode =
I.getOpcode();
2641 if (selectImpl(
I, *CoverageInfo))
2645 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2648 case TargetOpcode::G_SBFX:
2649 case TargetOpcode::G_UBFX: {
2650 static const unsigned OpcTable[2][2] = {
2651 {AArch64::UBFMWri, AArch64::UBFMXri},
2652 {AArch64::SBFMWri, AArch64::SBFMXri}};
2653 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2655 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2658 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2661 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2662 auto LSB = Cst1->Value.getZExtValue();
2663 auto Width = Cst2->Value.getZExtValue();
2667 .
addImm(LSB + Width - 1);
2668 I.eraseFromParent();
2672 case TargetOpcode::G_BRCOND:
2673 return selectCompareBranch(
I, MF, MRI);
2675 case TargetOpcode::G_BRINDIRECT: {
2677 if (std::optional<uint16_t> BADisc =
2679 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2683 I.eraseFromParent();
2687 I.setDesc(
TII.get(AArch64::BR));
2692 case TargetOpcode::G_BRJT:
2693 return selectBrJT(
I, MRI);
2695 case AArch64::G_ADD_LOW: {
2700 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2701 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2702 I.setDesc(
TII.get(AArch64::ADDXri));
2708 "Expected small code model");
2710 auto Op2 =
I.getOperand(2);
2711 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2712 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2713 Op1.getTargetFlags())
2715 Op2.getTargetFlags());
2716 I.eraseFromParent();
2721 case TargetOpcode::G_FCONSTANT: {
2722 const Register DefReg =
I.getOperand(0).getReg();
2723 const LLT DefTy = MRI.
getType(DefReg);
2734 bool OptForSize = shouldOptForSize(&MF);
2738 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2745 auto *FPImm =
I.getOperand(1).getFPImm();
2748 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2751 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2752 I.eraseFromParent();
2757 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2760 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2761 MachineOperand &RegOp =
I.getOperand(0);
2767 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2771 MachineOperand &ImmOp =
I.getOperand(1);
2775 const unsigned MovOpc =
2776 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2777 I.setDesc(
TII.get(MovOpc));
2781 case TargetOpcode::G_EXTRACT: {
2782 Register DstReg =
I.getOperand(0).getReg();
2783 Register SrcReg =
I.getOperand(1).getReg();
2784 LLT SrcTy = MRI.
getType(SrcReg);
2785 LLT DstTy = MRI.
getType(DstReg);
2797 unsigned Offset =
I.getOperand(2).getImm();
2802 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2803 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2806 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2808 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2810 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2812 AArch64::GPR64RegClass, NewI->getOperand(0));
2813 I.eraseFromParent();
2819 unsigned LaneIdx =
Offset / 64;
2820 MachineInstr *Extract = emitExtractVectorElt(
2821 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2824 I.eraseFromParent();
2828 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2829 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2834 "unexpected G_EXTRACT types");
2841 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2842 .addReg(DstReg, {}, AArch64::sub_32);
2844 AArch64::GPR32RegClass, MRI);
2845 I.getOperand(0).setReg(DstReg);
2851 case TargetOpcode::G_INSERT: {
2852 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2853 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2860 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2861 unsigned LSB =
I.getOperand(3).getImm();
2863 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2864 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2868 "unexpected G_INSERT types");
2875 TII.get(AArch64::SUBREG_TO_REG))
2877 .
addUse(
I.getOperand(2).getReg())
2878 .
addImm(AArch64::sub_32);
2880 AArch64::GPR32RegClass, MRI);
2881 I.getOperand(2).setReg(SrcReg);
2886 case TargetOpcode::G_FRAME_INDEX: {
2893 I.setDesc(
TII.get(AArch64::ADDXri));
2903 case TargetOpcode::G_GLOBAL_VALUE: {
2904 const GlobalValue *GV =
nullptr;
2906 if (
I.getOperand(1).isSymbol()) {
2907 OpFlags =
I.getOperand(1).getTargetFlags();
2913 return selectTLSGlobalValue(
I, MRI);
2919 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2920 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2921 I.getOperand(1).setTargetFlags(OpFlags);
2922 I.addImplicitDefUseOperands(MF);
2926 materializeLargeCMVal(
I, GV, OpFlags);
2927 I.eraseFromParent();
2930 I.setDesc(
TII.get(AArch64::ADR));
2931 I.getOperand(1).setTargetFlags(OpFlags);
2933 I.setDesc(
TII.get(AArch64::MOVaddr));
2935 MachineInstrBuilder MIB(MF,
I);
2936 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2943 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2944 return selectPtrAuthGlobalValue(
I, MRI);
2946 case TargetOpcode::G_ZEXTLOAD:
2947 case TargetOpcode::G_LOAD:
2948 case TargetOpcode::G_STORE: {
2950 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2965 assert(MemSizeInBytes <= 8 &&
2966 "128-bit atomics should already be custom-legalized");
2969 static constexpr unsigned LDAPROpcodes[] = {
2970 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2971 static constexpr unsigned LDAROpcodes[] = {
2972 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2973 ArrayRef<unsigned> Opcodes =
2974 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2977 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2979 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2980 AArch64::STLRW, AArch64::STLRX};
2985 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2986 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2987 I.getOperand(0).setReg(NewVal);
2989 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2997 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
3000 "Load/Store pointer operand isn't a GPR");
3002 "Load/Store pointer operand isn't a pointer");
3007 LLT ValTy = MRI.
getType(ValReg);
3012 RB.
getID() == AArch64::FPRRegBankID) {
3015 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3021 .addReg(ValReg, {}, SubReg)
3028 if (RB.
getID() == AArch64::FPRRegBankID) {
3031 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3041 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3044 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3053 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3055 const unsigned NewOpc =
3057 if (NewOpc ==
I.getOpcode())
3061 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3064 I.setDesc(
TII.get(NewOpc));
3070 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3071 Register CurValReg =
I.getOperand(0).getReg();
3072 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3073 NewInst.cloneMemRefs(
I);
3074 for (
auto &Fn : *AddrModeFns)
3076 I.eraseFromParent();
3080 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3085 if (Opcode == TargetOpcode::G_STORE) {
3087 LoadStore->getOperand(0).getReg(), MRI);
3088 if (CVal && CVal->Value == 0) {
3090 case AArch64::STRWui:
3091 case AArch64::STRHHui:
3092 case AArch64::STRBBui:
3093 LoadStore->getOperand(0).setReg(AArch64::WZR);
3095 case AArch64::STRXui:
3096 LoadStore->getOperand(0).setReg(AArch64::XZR);
3102 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3103 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3115 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3117 .
addImm(AArch64::sub_32);
3126 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3127 case TargetOpcode::G_INDEXED_SEXTLOAD:
3128 return selectIndexedExtLoad(
I, MRI);
3129 case TargetOpcode::G_INDEXED_LOAD:
3130 return selectIndexedLoad(
I, MRI);
3131 case TargetOpcode::G_INDEXED_STORE:
3134 case TargetOpcode::G_LSHR:
3135 case TargetOpcode::G_ASHR:
3137 return selectVectorAshrLshr(
I, MRI);
3139 case TargetOpcode::G_SHL: {
3140 if (Opcode == TargetOpcode::G_SHL &&
3142 return selectVectorSHL(
I, MRI);
3149 Register SrcReg =
I.getOperand(1).getReg();
3150 Register ShiftReg =
I.getOperand(2).getReg();
3151 const LLT ShiftTy = MRI.
getType(ShiftReg);
3152 const LLT SrcTy = MRI.
getType(SrcReg);
3157 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3158 .addReg(ShiftReg, {}, AArch64::sub_32);
3160 I.getOperand(2).setReg(Trunc.getReg(0));
3165 const Register DefReg =
I.getOperand(0).getReg();
3169 if (NewOpc ==
I.getOpcode())
3172 I.setDesc(
TII.get(NewOpc));
3180 case TargetOpcode::G_PTR_ADD: {
3181 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3182 I.eraseFromParent();
3186 case TargetOpcode::G_SADDE:
3187 case TargetOpcode::G_UADDE:
3188 case TargetOpcode::G_SSUBE:
3189 case TargetOpcode::G_USUBE:
3190 case TargetOpcode::G_SADDO:
3191 case TargetOpcode::G_UADDO:
3192 case TargetOpcode::G_SSUBO:
3193 case TargetOpcode::G_USUBO:
3194 return selectOverflowOp(
I, MRI);
3196 case TargetOpcode::G_PTRMASK: {
3197 Register MaskReg =
I.getOperand(2).getReg();
3204 I.setDesc(
TII.get(AArch64::ANDXri));
3205 I.getOperand(2).ChangeToImmediate(
3211 case TargetOpcode::G_PTRTOINT:
3212 case TargetOpcode::G_TRUNC: {
3213 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3214 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3216 const Register DstReg =
I.getOperand(0).getReg();
3217 const Register SrcReg =
I.getOperand(1).getReg();
3219 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3220 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3224 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3228 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3239 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3243 if (DstRC == SrcRC) {
3245 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3249 }
else if (DstRC == &AArch64::GPR32RegClass &&
3250 SrcRC == &AArch64::GPR64RegClass) {
3251 I.getOperand(1).setSubReg(AArch64::sub_32);
3254 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3258 I.setDesc(
TII.get(TargetOpcode::COPY));
3260 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3263 I.setDesc(
TII.get(AArch64::XTNv4i16));
3269 MachineInstr *Extract = emitExtractVectorElt(
3273 I.eraseFromParent();
3278 if (Opcode == TargetOpcode::G_PTRTOINT) {
3279 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3280 I.setDesc(
TII.get(TargetOpcode::COPY));
3288 case TargetOpcode::G_ANYEXT: {
3289 if (selectUSMovFromExtend(
I, MRI))
3292 const Register DstReg =
I.getOperand(0).getReg();
3293 const Register SrcReg =
I.getOperand(1).getReg();
3295 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3296 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3298 <<
", expected: GPR\n");
3302 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3303 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3305 <<
", expected: GPR\n");
3312 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3316 if (DstSize != 64 && DstSize > 32) {
3318 <<
", expected: 32 or 64\n");
3328 .
addImm(AArch64::sub_32);
3329 I.getOperand(1).setReg(ExtSrc);
3334 case TargetOpcode::G_ZEXT:
3335 case TargetOpcode::G_SEXT_INREG:
3336 case TargetOpcode::G_SEXT: {
3337 if (selectUSMovFromExtend(
I, MRI))
3340 unsigned Opcode =
I.getOpcode();
3341 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3342 const Register DefReg =
I.getOperand(0).getReg();
3343 Register SrcReg =
I.getOperand(1).getReg();
3344 const LLT DstTy = MRI.
getType(DefReg);
3345 const LLT SrcTy = MRI.
getType(SrcReg);
3351 if (Opcode == TargetOpcode::G_SEXT_INREG)
3352 SrcSize =
I.getOperand(2).getImm();
3358 AArch64::GPRRegBankID &&
3359 "Unexpected ext regbank");
3370 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3373 if (LoadMI && IsGPR) {
3374 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3375 unsigned BytesLoaded = MemOp->getSize().getValue();
3382 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3385 const Register ZReg = AArch64::WZR;
3386 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3389 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3390 .addUse(SubregToRegSrc)
3391 .
addImm(AArch64::sub_32);
3395 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3405 I.eraseFromParent();
3410 if (DstSize == 64) {
3411 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3419 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3420 {&AArch64::GPR64RegClass}, {})
3426 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3430 }
else if (DstSize <= 32) {
3431 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3440 I.eraseFromParent();
3444 case TargetOpcode::G_FREEZE:
3447 case TargetOpcode::G_INTTOPTR:
3452 case TargetOpcode::G_BITCAST:
3460 case TargetOpcode::G_SELECT: {
3462 const Register CondReg = Sel.getCondReg();
3464 const Register FReg = Sel.getFalseReg();
3466 if (tryOptSelect(Sel))
3472 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3477 Sel.eraseFromParent();
3480 case TargetOpcode::G_ICMP: {
3490 auto &PredOp =
I.getOperand(1);
3491 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3495 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3496 AArch64::WZR, InvCC, MIB);
3497 I.eraseFromParent();
3501 case TargetOpcode::G_FCMP: {
3504 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3506 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3508 I.eraseFromParent();
3511 case TargetOpcode::G_VASTART:
3513 : selectVaStartAAPCS(
I, MF, MRI);
3514 case TargetOpcode::G_INTRINSIC:
3515 return selectIntrinsic(
I, MRI);
3516 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3517 return selectIntrinsicWithSideEffects(
I, MRI);
3518 case TargetOpcode::G_IMPLICIT_DEF: {
3519 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3520 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3521 const Register DstReg =
I.getOperand(0).getReg();
3522 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3527 case TargetOpcode::G_BLOCK_ADDR: {
3528 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3529 if (std::optional<uint16_t> BADisc =
3531 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3532 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3541 AArch64::GPR64RegClass, MRI);
3542 I.eraseFromParent();
3546 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3547 I.eraseFromParent();
3550 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3551 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3552 I.getOperand(0).getReg())
3556 I.getOperand(1).getBlockAddress(), 0,
3558 I.eraseFromParent();
3563 case AArch64::G_DUP: {
3570 AArch64::GPRRegBankID)
3572 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3574 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3576 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3578 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3580 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3586 case TargetOpcode::G_BUILD_VECTOR:
3587 return selectBuildVector(
I, MRI);
3588 case TargetOpcode::G_MERGE_VALUES:
3590 case TargetOpcode::G_UNMERGE_VALUES:
3592 case TargetOpcode::G_SHUFFLE_VECTOR:
3593 return selectShuffleVector(
I, MRI);
3594 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3595 return selectExtractElt(
I, MRI);
3596 case TargetOpcode::G_CONCAT_VECTORS:
3597 return selectConcatVectors(
I, MRI);
3598 case TargetOpcode::G_JUMP_TABLE:
3599 return selectJumpTable(
I, MRI);
3600 case TargetOpcode::G_MEMCPY:
3601 case TargetOpcode::G_MEMCPY_INLINE:
3602 case TargetOpcode::G_MEMMOVE:
3603 case TargetOpcode::G_MEMSET:
3604 case TargetOpcode::G_MEMSET_INLINE:
3605 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3606 return selectMOPS(
I, MRI);
3612bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3613 MachineIRBuilderState OldMIBState = MIB.
getState();
3619bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3620 MachineRegisterInfo &MRI) {
3623 case TargetOpcode::G_MEMCPY:
3624 case TargetOpcode::G_MEMCPY_INLINE:
3625 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3627 case TargetOpcode::G_MEMMOVE:
3628 Mopcode = AArch64::MOPSMemoryMovePseudo;
3630 case TargetOpcode::G_MEMSET:
3631 case TargetOpcode::G_MEMSET_INLINE:
3633 Mopcode = AArch64::MOPSMemorySetPseudo;
3646 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3647 const auto &SrcValRegClass =
3648 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3666 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3667 {DstPtrCopy, SizeCopy, SrcValCopy});
3670 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3671 {DstPtrCopy, SrcValCopy, SizeCopy});
3678bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3679 MachineRegisterInfo &MRI) {
3680 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3681 Register JTAddr =
I.getOperand(0).getReg();
3682 unsigned JTI =
I.getOperand(1).getIndex();
3685 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3697 "jump table hardening only supported on MachO/ELF");
3705 I.eraseFromParent();
3712 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3713 {TargetReg, ScratchReg}, {JTAddr,
Index})
3714 .addJumpTableIndex(JTI);
3716 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3717 {
static_cast<int64_t
>(JTI)});
3719 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3720 I.eraseFromParent();
3725bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3726 MachineRegisterInfo &MRI) {
3727 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3728 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3730 Register DstReg =
I.getOperand(0).getReg();
3731 unsigned JTI =
I.getOperand(1).getIndex();
3734 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3737 I.eraseFromParent();
3742bool AArch64InstructionSelector::selectTLSLocalExecELF(
3743 const GlobalValue *GV, MachineInstr &
I, MachineRegisterInfo &MRI) {
3744 auto ConstrainRegOps = [&](MachineInstrBuilder MIB) {
3748 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {}));
3756 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()},
3767 MIB.
buildInstr(AArch64::ADDXri, {Addr}, {ThreadBase})
3771 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()}, {Addr})
3788 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3793 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3794 {ThreadBase, Addr2}));
3808 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3814 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr3}, {Addr2})
3819 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3820 {ThreadBase, Addr3}));
3824 I.eraseFromParent();
3830bool AArch64InstructionSelector::selectTLSGlobalValueELF(
3831 MachineInstr &
I, MachineRegisterInfo &MRI) {
3832 const GlobalValue *GV =
I.
getOperand(1).getGlobal();
3833 auto *FuncInfo = MF->
getInfo<AArch64FunctionInfo>();
3840 return selectTLSLocalExecELF(GV,
I, MRI);
3842 MIB.
buildInstr(AArch64::LOADgot, {TPOff}, {})
3848 SMEAttrs
Attrs = MF->
getInfo<AArch64FunctionInfo>()->getSMEFnAttrs();
3850 !
Attrs.hasStreamingCompatibleInterface() &&
3851 "unsupported SME features reached GlobalISel TLS lowering");
3854 ? AArch64::TLSDESC_AUTH_CALLSEQ
3855 : AArch64::TLSDESC_CALLSEQ;
3874 MIB.
buildInstr(AArch64::ADDXri, {TPOff}, {Add1.getReg(0)})
3875 .addGlobalAddress(GV, 0,
3884 MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {});
3885 auto Add = MIB.
buildInstr(AArch64::ADDXrr, {
I.getOperand(0).getReg()},
3886 {ThreadBase, TPOff});
3889 I.eraseFromParent();
3893bool AArch64InstructionSelector::selectTLSGlobalValueMachO(
3894 MachineInstr &
I, MachineRegisterInfo &MRI) {
3895 const auto &GlobalOp =
I.getOperand(1);
3896 assert(GlobalOp.getOffset() == 0 &&
3897 "Shouldn't have an offset on TLS globals!");
3899 const GlobalValue &GV = *GlobalOp.getGlobal();
3902 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3905 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3906 {LoadGOT.getReg(0)})
3917 assert(Opcode == AArch64::BLR);
3918 Opcode = AArch64::BLRAAZ;
3922 .addUse(AArch64::X0, RegState::Implicit)
3923 .
addDef(AArch64::X0, RegState::Implicit)
3929 I.eraseFromParent();
3933bool AArch64InstructionSelector::selectTLSGlobalValue(
3934 MachineInstr &
I, MachineRegisterInfo &MRI) {
3940 return selectTLSGlobalValueELF(
I, MRI);
3943 return selectTLSGlobalValueMachO(
I, MRI);
3948MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3950 MachineIRBuilder &MIRBuilder)
const {
3951 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3953 auto BuildFn = [&](
unsigned SubregIndex) {
3957 .addImm(SubregIndex);
3965 return BuildFn(AArch64::bsub);
3967 return BuildFn(AArch64::hsub);
3969 return BuildFn(AArch64::ssub);
3971 return BuildFn(AArch64::dsub);
3978AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3979 MachineIRBuilder &MIB,
3980 MachineRegisterInfo &MRI)
const {
3981 LLT DstTy = MRI.
getType(DstReg);
3983 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3984 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3988 unsigned SubReg = 0;
3991 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3997 .addReg(SrcReg, {}, SubReg);
4002bool AArch64InstructionSelector::selectMergeValues(
4003 MachineInstr &
I, MachineRegisterInfo &MRI) {
4004 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
4005 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
4006 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
4008 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
4010 if (
I.getNumOperands() != 3)
4017 Register DstReg =
I.getOperand(0).getReg();
4018 Register Src1Reg =
I.getOperand(1).getReg();
4019 Register Src2Reg =
I.getOperand(2).getReg();
4020 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
4021 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
4025 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
4026 Src2Reg, 1, RB, MIB);
4031 I.eraseFromParent();
4035 if (RB.
getID() != AArch64::GPRRegBankID)
4041 auto *DstRC = &AArch64::GPR64RegClass;
4043 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4044 TII.get(TargetOpcode::SUBREG_TO_REG))
4046 .
addUse(
I.getOperand(1).getReg())
4047 .
addImm(AArch64::sub_32);
4050 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4051 TII.get(TargetOpcode::SUBREG_TO_REG))
4053 .
addUse(
I.getOperand(2).getReg())
4054 .
addImm(AArch64::sub_32);
4056 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
4057 .
addDef(
I.getOperand(0).getReg())
4065 I.eraseFromParent();
4070 const unsigned EltSize) {
4075 CopyOpc = AArch64::DUPi8;
4076 ExtractSubReg = AArch64::bsub;
4079 CopyOpc = AArch64::DUPi16;
4080 ExtractSubReg = AArch64::hsub;
4083 CopyOpc = AArch64::DUPi32;
4084 ExtractSubReg = AArch64::ssub;
4087 CopyOpc = AArch64::DUPi64;
4088 ExtractSubReg = AArch64::dsub;
4092 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
4098MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
4099 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
4100 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
4101 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4102 unsigned CopyOpc = 0;
4103 unsigned ExtractSubReg = 0;
4106 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
4111 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
4113 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
4117 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
4118 const LLT &VecTy = MRI.
getType(VecReg);
4120 getRegClassForTypeOnBank(VecTy, VecRB,
true);
4122 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4132 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4133 .addReg(VecReg, {}, ExtractSubReg);
4142 MachineInstr *ScalarToVector = emitScalarToVector(
4143 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4144 if (!ScalarToVector)
4149 MachineInstr *LaneCopyMI =
4150 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4158bool AArch64InstructionSelector::selectExtractElt(
4159 MachineInstr &
I, MachineRegisterInfo &MRI) {
4160 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4161 "unexpected opcode!");
4162 Register DstReg =
I.getOperand(0).getReg();
4163 const LLT NarrowTy = MRI.
getType(DstReg);
4164 const Register SrcReg =
I.getOperand(1).getReg();
4165 const LLT WideTy = MRI.
getType(SrcReg);
4167 "source register size too small!");
4168 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4171 MachineOperand &LaneIdxOp =
I.getOperand(2);
4172 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4178 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4180 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4181 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4185 Opcode = AArch64::UMOVvi8;
4188 Opcode = AArch64::UMOVvi16;
4191 Opcode = AArch64::UMOVvi32;
4198 MachineInstr *ScalarToVector = emitScalarToVector(
4199 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4200 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4204 I.setDesc(
TII.get(Opcode));
4205 I.getOperand(2).ChangeToImmediate(LaneIdx);
4210 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4215 I.eraseFromParent();
4219bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4220 MachineInstr &
I, MachineRegisterInfo &MRI) {
4221 unsigned NumElts =
I.getNumOperands() - 1;
4222 Register SrcReg =
I.getOperand(NumElts).getReg();
4223 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4224 const LLT SrcTy = MRI.
getType(SrcReg);
4226 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4228 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4234 const RegisterBank &DstRB =
4236 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4237 Register Dst =
I.getOperand(OpIdx).getReg();
4238 MachineInstr *Extract =
4239 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4243 I.eraseFromParent();
4247bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4248 MachineRegisterInfo &MRI) {
4249 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4250 "unexpected opcode");
4254 unsigned NumElts =
I.getNumOperands() - 1;
4255 Register SrcReg =
I.getOperand(NumElts).getReg();
4256 Register LoReg =
I.getOperand(0).getReg();
4257 Register HiReg =
I.getOperand(1).getReg();
4258 const LLT NarrowTy = MRI.
getType(LoReg);
4259 const LLT WideTy = MRI.
getType(SrcReg);
4260 const RegisterBank &LoRB = *RBI.
getRegBank(LoReg, MRI,
TRI);
4261 const RegisterBank &HiRB = *RBI.
getRegBank(HiReg, MRI,
TRI);
4262 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
4266 LoRB.
getID() == AArch64::GPRRegBankID &&
4267 HiRB.
getID() == AArch64::GPRRegBankID &&
4268 SrcRB.
getID() == AArch64::FPRRegBankID) {
4269 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4270 TII.get(AArch64::UMOVvi64), LoReg)
4273 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4274 TII.get(AArch64::UMOVvi64), HiReg)
4279 I.eraseFromParent();
4284 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4285 HiRB.
getID() != AArch64::FPRRegBankID) {
4286 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4287 "currently unsupported.\n");
4292 "source register size too small!");
4295 return selectSplitVectorUnmerge(
I, MRI);
4299 unsigned CopyOpc = 0;
4300 unsigned ExtractSubReg = 0;
4311 unsigned NumInsertRegs = NumElts - 1;
4317 InsertRegs.
assign(NumInsertRegs, SrcReg);
4326 unsigned SubReg = 0;
4329 assert(Found &&
"expected to find last operand's subeg idx");
4330 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4332 MachineInstr &ImpDefMI =
4333 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4338 MachineInstr &InsMI =
4340 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4357 Register CopyTo =
I.getOperand(0).getReg();
4358 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4359 .addReg(InsertRegs[0], {}, ExtractSubReg);
4363 unsigned LaneIdx = 1;
4364 for (
Register InsReg : InsertRegs) {
4365 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4366 MachineInstr &CopyInst =
4385 I.eraseFromParent();
4389bool AArch64InstructionSelector::selectConcatVectors(
4390 MachineInstr &
I, MachineRegisterInfo &MRI) {
4391 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4392 "Unexpected opcode");
4393 Register Dst =
I.getOperand(0).getReg();
4394 Register Op1 =
I.getOperand(1).getReg();
4395 Register Op2 =
I.getOperand(2).getReg();
4396 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4399 I.eraseFromParent();
4404AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4413MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4414 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4421 RC = &AArch64::FPR128RegClass;
4422 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4425 RC = &AArch64::FPR64RegClass;
4426 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4429 RC = &AArch64::FPR32RegClass;
4430 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4433 RC = &AArch64::FPR16RegClass;
4434 Opc = AArch64::LDRHui;
4437 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4442 MachineInstr *LoadMI =
nullptr;
4443 auto &MF = MIRBuilder.
getMF();
4444 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4445 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4447 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4450 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4454 .addConstantPoolIndex(
4470static std::pair<unsigned, unsigned>
4472 unsigned Opc, SubregIdx;
4473 if (RB.
getID() == AArch64::GPRRegBankID) {
4475 Opc = AArch64::INSvi8gpr;
4476 SubregIdx = AArch64::bsub;
4477 }
else if (EltSize == 16) {
4478 Opc = AArch64::INSvi16gpr;
4479 SubregIdx = AArch64::ssub;
4480 }
else if (EltSize == 32) {
4481 Opc = AArch64::INSvi32gpr;
4482 SubregIdx = AArch64::ssub;
4483 }
else if (EltSize == 64) {
4484 Opc = AArch64::INSvi64gpr;
4485 SubregIdx = AArch64::dsub;
4491 Opc = AArch64::INSvi8lane;
4492 SubregIdx = AArch64::bsub;
4493 }
else if (EltSize == 16) {
4494 Opc = AArch64::INSvi16lane;
4495 SubregIdx = AArch64::hsub;
4496 }
else if (EltSize == 32) {
4497 Opc = AArch64::INSvi32lane;
4498 SubregIdx = AArch64::ssub;
4499 }
else if (EltSize == 64) {
4500 Opc = AArch64::INSvi64lane;
4501 SubregIdx = AArch64::dsub;
4506 return std::make_pair(
Opc, SubregIdx);
4509MachineInstr *AArch64InstructionSelector::emitInstr(
4510 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4511 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4512 const ComplexRendererFns &RenderFns)
const {
4513 assert(Opcode &&
"Expected an opcode?");
4515 "Function should only be used to produce selected instructions!");
4516 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4518 for (
auto &Fn : *RenderFns)
4524MachineInstr *AArch64InstructionSelector::emitAddSub(
4525 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4527 MachineIRBuilder &MIRBuilder)
const {
4529 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4533 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4534 bool Is32Bit =
Size == 32;
4537 if (
auto Fns = selectArithImmed(
RHS))
4538 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4542 if (
auto Fns = selectNegArithImmed(
RHS))
4543 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4547 if (
auto Fns = selectArithExtendedRegister(
RHS))
4548 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4552 if (
auto Fns = selectShiftedRegister(
RHS))
4553 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4555 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4560AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4561 MachineOperand &
RHS,
4562 MachineIRBuilder &MIRBuilder)
const {
4563 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4564 {{AArch64::ADDXri, AArch64::ADDWri},
4565 {AArch64::ADDXrs, AArch64::ADDWrs},
4566 {AArch64::ADDXrr, AArch64::ADDWrr},
4567 {AArch64::SUBXri, AArch64::SUBWri},
4568 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4569 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4573AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4574 MachineOperand &
RHS,
4575 MachineIRBuilder &MIRBuilder)
const {
4576 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4577 {{AArch64::ADDSXri, AArch64::ADDSWri},
4578 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4579 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4580 {AArch64::SUBSXri, AArch64::SUBSWri},
4581 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4582 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4586AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4587 MachineOperand &
RHS,
4588 MachineIRBuilder &MIRBuilder)
const {
4589 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4590 {{AArch64::SUBSXri, AArch64::SUBSWri},
4591 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4592 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4593 {AArch64::ADDSXri, AArch64::ADDSWri},
4594 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4595 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4599AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4600 MachineOperand &
RHS,
4601 MachineIRBuilder &MIRBuilder)
const {
4602 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4603 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4605 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4606 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4610AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4611 MachineOperand &
RHS,
4612 MachineIRBuilder &MIRBuilder)
const {
4613 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4614 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4616 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4617 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4621AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4622 MachineIRBuilder &MIRBuilder)
const {
4625 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4630AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4631 MachineIRBuilder &MIRBuilder)
const {
4634 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4639AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4640 MachineIRBuilder &MIRBuilder)
const {
4641 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4645 bool Is32Bit = (
RegSize == 32);
4646 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4647 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4648 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4652 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4655 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4662 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4663 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4664 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4667MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4668 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4669 MachineIRBuilder &MIRBuilder)
const {
4670 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4677 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4679 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4681 return emitCMP(
LHS,
RHS, MIRBuilder);
4684MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4686 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4690 "Expected a 32-bit scalar register?");
4692 const Register ZReg = AArch64::WZR;
4697 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4703 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4704 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4705 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4710MachineInstr *AArch64InstructionSelector::emitFPCompare(
4712 std::optional<CmpInst::Predicate> Pred)
const {
4713 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4718 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4728 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4731 ShouldUseImm =
true;
4735 unsigned CmpOpcTbl[2][3] = {
4736 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4737 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4739 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4751MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4753 MachineIRBuilder &MIRBuilder)
const {
4760 const LLT Op1Ty = MRI.
getType(Op1);
4761 const LLT Op2Ty = MRI.
getType(Op2);
4763 if (Op1Ty != Op2Ty) {
4764 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4767 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4770 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4781 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4785 MachineInstr *WidenedOp1 =
4786 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4787 MachineInstr *WidenedOp2 =
4788 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4789 if (!WidenedOp1 || !WidenedOp2) {
4790 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4795 unsigned InsertOpc, InsSubRegIdx;
4796 std::tie(InsertOpc, InsSubRegIdx) =
4814 MachineIRBuilder &MIRBuilder)
const {
4815 auto &MRI = *MIRBuilder.
getMRI();
4821 Size =
TRI.getRegSizeInBits(*RC);
4825 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4826 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4827 unsigned Opc = OpcTable[
Size == 64];
4828 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4833MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4835 MachineRegisterInfo *MRI = MIB.
getMRI();
4836 unsigned Opcode =
I.getOpcode();
4840 bool NeedsNegatedCarry =
4841 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4850 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4851 if (SrcMI ==
I.getPrevNode()) {
4853 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4854 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4855 CarrySrcMI->isUnsigned() &&
4856 CarrySrcMI->getCarryOutReg() == CarryReg &&
4857 selectAndRestoreState(*SrcMI))
4864 if (NeedsNegatedCarry) {
4867 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4871 auto Fns = select12BitValueWithLeftShift(1);
4872 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4875bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4876 MachineRegisterInfo &MRI) {
4881 emitCarryIn(
I, CarryInMI->getCarryInReg());
4885 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4886 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4888 Register CarryOutReg = CarryMI.getCarryOutReg();
4897 emitCSINC(CarryOutReg, ZReg, ZReg,
4898 getInvertedCondCode(OpAndCC.second), MIB);
4901 I.eraseFromParent();
4905std::pair<MachineInstr *, AArch64CC::CondCode>
4906AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4907 MachineOperand &
LHS,
4908 MachineOperand &
RHS,
4909 MachineIRBuilder &MIRBuilder)
const {
4913 case TargetOpcode::G_SADDO:
4915 case TargetOpcode::G_UADDO:
4917 case TargetOpcode::G_SSUBO:
4919 case TargetOpcode::G_USUBO:
4921 case TargetOpcode::G_SADDE:
4923 case TargetOpcode::G_UADDE:
4925 case TargetOpcode::G_SSUBE:
4927 case TargetOpcode::G_USUBE:
4948 unsigned Depth = 0) {
4955 MustBeFirst =
false;
4961 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4962 bool IsOR = Opcode == TargetOpcode::G_OR;
4974 if (MustBeFirstL && MustBeFirstR)
4980 if (!CanNegateL && !CanNegateR)
4984 CanNegate = WillNegate && CanNegateL && CanNegateR;
4987 MustBeFirst = !CanNegate;
4989 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4992 MustBeFirst = MustBeFirstL || MustBeFirstR;
4999MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
5002 MachineIRBuilder &MIB)
const {
5003 auto &MRI = *MIB.
getMRI();
5006 std::optional<ValueAndVReg>
C;
5010 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
5011 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
5012 else if (
C->Value.ule(31))
5013 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
5015 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
5021 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
5022 CCmpOpc = AArch64::FCCMPHrr;
5025 CCmpOpc = AArch64::FCCMPSrr;
5028 CCmpOpc = AArch64::FCCMPDrr;
5038 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
5039 CCmp.
addImm(
C->Value.getZExtValue());
5040 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
5041 CCmp.
addImm(
C->Value.abs().getZExtValue());
5049MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
5053 auto &MRI = *MIB.
getMRI();
5071 MachineInstr *ExtraCmp;
5073 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
5085 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
5086 return emitFPCompare(
Cmp->getOperand(2).getReg(),
5087 Cmp->getOperand(3).getReg(), MIB);
5094 bool IsOR = Opcode == TargetOpcode::G_OR;
5100 assert(ValidL &&
"Valid conjunction/disjunction tree");
5107 assert(ValidR &&
"Valid conjunction/disjunction tree");
5112 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
5121 bool NegateAfterAll;
5122 if (Opcode == TargetOpcode::G_OR) {
5125 assert(CanNegateR &&
"at least one side must be negatable");
5126 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
5130 NegateAfterR =
true;
5133 NegateR = CanNegateR;
5134 NegateAfterR = !CanNegateR;
5137 NegateAfterAll = !Negate;
5139 assert(Opcode == TargetOpcode::G_AND &&
5140 "Valid conjunction/disjunction tree");
5141 assert(!Negate &&
"Valid conjunction/disjunction tree");
5145 NegateAfterR =
false;
5146 NegateAfterAll =
false;
5151 MachineInstr *CmpR =
5162MachineInstr *AArch64InstructionSelector::emitConjunction(
5164 bool DummyCanNegate;
5165 bool DummyMustBeFirst;
5172bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5173 MachineInstr &CondMI) {
5184bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5185 MachineRegisterInfo &MRI = *MIB.
getMRI();
5204 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5213 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5219 unsigned CondOpc = CondDef->
getOpcode();
5220 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5221 if (tryOptSelectConjunction(
I, *CondDef))
5227 if (CondOpc == TargetOpcode::G_ICMP) {
5256 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5257 I.getOperand(3).getReg(), CondCode, MIB);
5258 I.eraseFromParent();
5262MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5263 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5264 MachineIRBuilder &MIRBuilder)
const {
5266 "Unexpected MachineOperand");
5267 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5290 if (
isCMN(RHSDef,
P, MRI))
5305 if (
isCMN(LHSDef,
P, MRI)) {
5322 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5325 if (!ValAndVReg || ValAndVReg->Value != 0)
5335bool AArch64InstructionSelector::selectShuffleVector(
5336 MachineInstr &
I, MachineRegisterInfo &MRI) {
5337 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5338 Register Src1Reg =
I.getOperand(1).getReg();
5339 Register Src2Reg =
I.getOperand(2).getReg();
5340 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5342 "Expected equal shuffle types during selection");
5351 SmallVector<int> NewMask;
5352 bool FirstUsed =
false;
5353 bool SecondUsed =
false;
5354 for (
int M : Mask) {
5356 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5359 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5364 FirstUsed |=
M < NumElts;
5365 SecondUsed |=
M >= NumElts;
5366 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5375 for (
int &M : NewMask) {
5377 assert(M >= ByteLanes && M < 2 * ByteLanes);
5387 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5388 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5401 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5408 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5412 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5417 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5418 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5420 I.eraseFromParent();
5425 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5428 I.eraseFromParent();
5436 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5439 I.eraseFromParent();
5443MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5445 unsigned LaneIdx,
const RegisterBank &RB,
5446 MachineIRBuilder &MIRBuilder)
const {
5447 MachineInstr *InsElt =
nullptr;
5449 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5458 if (RB.
getID() == AArch64::FPRRegBankID) {
5459 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5462 .
addUse(InsSub->getOperand(0).getReg())
5474bool AArch64InstructionSelector::selectUSMovFromExtend(
5475 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5476 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5477 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5478 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5480 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5481 const Register DefReg =
MI.getOperand(0).getReg();
5482 const LLT DstTy = MRI.
getType(DefReg);
5485 if (DstSize != 32 && DstSize != 64)
5488 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5489 MI.getOperand(1).getReg(), MRI);
5495 const LLT VecTy = MRI.
getType(Src0);
5500 const MachineInstr *ScalarToVector = emitScalarToVector(
5501 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5502 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5508 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5510 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5512 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5514 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5516 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5524 MachineInstr *ExtI =
nullptr;
5525 if (DstSize == 64 && !IsSigned) {
5527 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5528 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5530 .
addImm(AArch64::sub_32);
5533 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5536 MI.eraseFromParent();
5540MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5541 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5543 if (DstSize == 128) {
5544 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5546 Op = AArch64::MOVIv16b_ns;
5548 Op = AArch64::MOVIv8b_ns;
5555 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5562MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5563 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5567 if (DstSize == 128) {
5568 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5570 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5572 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5592MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5593 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5597 if (DstSize == 128) {
5598 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5600 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5602 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5628MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5629 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5632 if (DstSize == 128) {
5633 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5635 Op = AArch64::MOVIv2d_ns;
5637 Op = AArch64::MOVID;
5643 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5650MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5651 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5655 if (DstSize == 128) {
5656 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5658 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5660 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5680MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5681 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5684 bool IsWide =
false;
5685 if (DstSize == 128) {
5686 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5688 Op = AArch64::FMOVv4f32_ns;
5691 Op = AArch64::FMOVv2f32_ns;
5700 Op = AArch64::FMOVv2f64_ns;
5704 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5709bool AArch64InstructionSelector::selectIndexedExtLoad(
5710 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5713 Register WriteBack = ExtLd.getWritebackReg();
5718 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5719 bool IsPre = ExtLd.isPre();
5721 unsigned InsertIntoSubReg = 0;
5727 if ((IsSExt && IsFPR) || Ty.
isVector())
5735 if (MemSizeBits == 8) {
5738 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5740 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5741 NewLdDstTy = IsDst64 ? s64 : s32;
5743 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5744 InsertIntoSubReg = AArch64::bsub;
5747 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5748 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5751 }
else if (MemSizeBits == 16) {
5754 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5756 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5757 NewLdDstTy = IsDst64 ? s64 : s32;
5759 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5760 InsertIntoSubReg = AArch64::hsub;
5763 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5764 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5767 }
else if (MemSizeBits == 32) {
5769 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5772 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5773 InsertIntoSubReg = AArch64::ssub;
5776 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5777 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5789 .addImm(Cst->getSExtValue());
5794 if (InsertIntoSubReg) {
5796 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5797 .addUse(LdMI.getReg(1))
5798 .
addImm(InsertIntoSubReg);
5801 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5808 MI.eraseFromParent();
5813bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5814 MachineRegisterInfo &MRI) {
5817 Register WriteBack = Ld.getWritebackReg();
5821 "Unexpected type for indexed load");
5822 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5825 return selectIndexedExtLoad(
MI, MRI);
5829 static constexpr unsigned GPROpcodes[] = {
5830 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5832 static constexpr unsigned FPROpcodes[] = {
5833 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5836 ? FPROpcodes[
Log2_32(MemSize)]
5837 : GPROpcodes[
Log2_32(MemSize)];
5840 static constexpr unsigned GPROpcodes[] = {
5841 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5843 static constexpr unsigned FPROpcodes[] = {
5844 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5845 AArch64::LDRDpost, AArch64::LDRQpost};
5847 ? FPROpcodes[
Log2_32(MemSize)]
5848 : GPROpcodes[
Log2_32(MemSize)];
5858 MI.eraseFromParent();
5862bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5863 MachineRegisterInfo &MRI) {
5869 "Unexpected type for indexed store");
5871 LocationSize MemSize =
I.getMMO().getSize();
5872 unsigned MemSizeInBytes = MemSize.
getValue();
5874 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5875 "Unexpected indexed store size");
5876 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5880 static constexpr unsigned GPROpcodes[] = {
5881 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5883 static constexpr unsigned FPROpcodes[] = {
5884 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5888 Opc = FPROpcodes[MemSizeLog2];
5890 Opc = GPROpcodes[MemSizeLog2];
5892 static constexpr unsigned GPROpcodes[] = {
5893 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5895 static constexpr unsigned FPROpcodes[] = {
5896 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5897 AArch64::STRDpost, AArch64::STRQpost};
5900 Opc = FPROpcodes[MemSizeLog2];
5902 Opc = GPROpcodes[MemSizeLog2];
5910 Str.cloneMemRefs(
I);
5912 I.eraseFromParent();
5917AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5918 MachineIRBuilder &MIRBuilder,
5919 MachineRegisterInfo &MRI) {
5922 assert((DstSize == 64 || DstSize == 128) &&
5923 "Unexpected vector constant size");
5926 if (DstSize == 128) {
5928 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5933 if (DstSize == 64) {
5936 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5939 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5946 APInt SplatValueAsInt =
5949 : SplatValue->getUniqueInteger();
5952 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5953 MachineInstr *NewOp;
5977 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5981 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5982 unsigned NegOpc) -> MachineInstr * {
5985 APInt NegBits(DstSize, 0);
5986 unsigned NumElts = DstSize / NumBits;
5987 for (
unsigned i = 0; i < NumElts; i++)
5988 NegBits |= Neg << (NumBits * i);
5989 NegBits = DefBits ^ NegBits;
5993 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5995 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5997 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
6002 if ((R = TryWithFNeg(DefBits, 32,
6003 DstSize == 64 ? AArch64::FNEGv2f32
6004 : AArch64::FNEGv4f32)) ||
6005 (R = TryWithFNeg(DefBits, 64,
6006 DstSize == 64 ? AArch64::FNEGDr
6007 : AArch64::FNEGv2f64)) ||
6008 (STI.hasFullFP16() &&
6009 (R = TryWithFNeg(DefBits, 16,
6010 DstSize == 64 ? AArch64::FNEGv4f16
6011 : AArch64::FNEGv8f16))))
6017 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
6021 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
6023 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
6027bool AArch64InstructionSelector::tryOptConstantBuildVec(
6028 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
6029 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
6031 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
6037 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
6038 Register OpReg =
I.getOperand(Idx).getReg();
6047 std::move(AnyConst->Value)));
6060 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
6062 I.eraseFromParent();
6066bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
6067 MachineInstr &
I, MachineRegisterInfo &MRI) {
6072 Register Dst =
I.getOperand(0).getReg();
6073 Register EltReg =
I.getOperand(1).getReg();
6074 LLT EltTy = MRI.
getType(EltReg);
6077 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
6082 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
6090 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
6095 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
6098 I.eraseFromParent();
6103bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
6104 MachineRegisterInfo &MRI) {
6105 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
6108 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
6109 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
6112 if (tryOptConstantBuildVec(
I, DstTy, MRI))
6114 if (tryOptBuildVecToSubregToReg(
I, MRI))
6117 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
6119 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
6122 MachineInstr *ScalarToVec =
6124 I.getOperand(1).getReg(), MIB);
6133 MachineInstr *PrevMI = ScalarToVec;
6134 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
6137 Register OpReg =
I.getOperand(i).getReg();
6140 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
6147 if (DstSize < 128) {
6150 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6153 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
6158 unsigned SubReg = 0;
6161 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
6162 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
6168 Register DstReg =
I.getOperand(0).getReg();
6170 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
6171 MachineOperand &RegOp =
I.getOperand(1);
6191 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6193 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6202bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6205 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6207 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6208 auto &MRI = *MIB.
getMRI();
6209 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6212 "Destination must be 64 bits or 128 bits?");
6213 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6214 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6219 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6220 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6221 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6222 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6231bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6232 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6233 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6235 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6236 auto &MRI = *MIB.
getMRI();
6237 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6240 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6242 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6243 [](
auto MO) { return MO.getReg(); });
6247 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6262 .
addImm(LaneNo->getZExtValue())
6266 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6267 unsigned SubReg = AArch64::qsub0;
6268 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6269 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6270 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6271 : DstOp(
I.getOperand(Idx).
getReg())},
6273 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6278 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6284void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6287 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6288 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6289 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6292 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6293 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6302bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6303 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6304 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6305 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6309 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6310 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6314 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6324 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6327 .
addImm(LaneNo->getZExtValue())
6334bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6335 MachineInstr &
I, MachineRegisterInfo &MRI) {
6348 case Intrinsic::aarch64_ldxp:
6349 case Intrinsic::aarch64_ldaxp: {
6351 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6352 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6358 case Intrinsic::aarch64_neon_ld1x2: {
6359 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6362 Opc = AArch64::LD1Twov8b;
6364 Opc = AArch64::LD1Twov16b;
6366 Opc = AArch64::LD1Twov4h;
6368 Opc = AArch64::LD1Twov8h;
6370 Opc = AArch64::LD1Twov2s;
6372 Opc = AArch64::LD1Twov4s;
6374 Opc = AArch64::LD1Twov2d;
6375 else if (Ty ==
S64 || Ty == P0)
6376 Opc = AArch64::LD1Twov1d;
6379 selectVectorLoadIntrinsic(
Opc, 2,
I);
6382 case Intrinsic::aarch64_neon_ld1x3: {
6383 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6386 Opc = AArch64::LD1Threev8b;
6388 Opc = AArch64::LD1Threev16b;
6390 Opc = AArch64::LD1Threev4h;
6392 Opc = AArch64::LD1Threev8h;
6394 Opc = AArch64::LD1Threev2s;
6396 Opc = AArch64::LD1Threev4s;
6398 Opc = AArch64::LD1Threev2d;
6399 else if (Ty ==
S64 || Ty == P0)
6400 Opc = AArch64::LD1Threev1d;
6403 selectVectorLoadIntrinsic(
Opc, 3,
I);
6406 case Intrinsic::aarch64_neon_ld1x4: {
6407 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6410 Opc = AArch64::LD1Fourv8b;
6412 Opc = AArch64::LD1Fourv16b;
6414 Opc = AArch64::LD1Fourv4h;
6416 Opc = AArch64::LD1Fourv8h;
6418 Opc = AArch64::LD1Fourv2s;
6420 Opc = AArch64::LD1Fourv4s;
6422 Opc = AArch64::LD1Fourv2d;
6423 else if (Ty ==
S64 || Ty == P0)
6424 Opc = AArch64::LD1Fourv1d;
6427 selectVectorLoadIntrinsic(
Opc, 4,
I);
6430 case Intrinsic::aarch64_neon_ld2: {
6431 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6434 Opc = AArch64::LD2Twov8b;
6436 Opc = AArch64::LD2Twov16b;
6438 Opc = AArch64::LD2Twov4h;
6440 Opc = AArch64::LD2Twov8h;
6442 Opc = AArch64::LD2Twov2s;
6444 Opc = AArch64::LD2Twov4s;
6446 Opc = AArch64::LD2Twov2d;
6447 else if (Ty ==
S64 || Ty == P0)
6448 Opc = AArch64::LD1Twov1d;
6451 selectVectorLoadIntrinsic(
Opc, 2,
I);
6454 case Intrinsic::aarch64_neon_ld2lane: {
6455 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6458 Opc = AArch64::LD2i8;
6460 Opc = AArch64::LD2i16;
6462 Opc = AArch64::LD2i32;
6465 Opc = AArch64::LD2i64;
6468 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6472 case Intrinsic::aarch64_neon_ld2r: {
6473 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6476 Opc = AArch64::LD2Rv8b;
6478 Opc = AArch64::LD2Rv16b;
6480 Opc = AArch64::LD2Rv4h;
6482 Opc = AArch64::LD2Rv8h;
6484 Opc = AArch64::LD2Rv2s;
6486 Opc = AArch64::LD2Rv4s;
6488 Opc = AArch64::LD2Rv2d;
6489 else if (Ty ==
S64 || Ty == P0)
6490 Opc = AArch64::LD2Rv1d;
6493 selectVectorLoadIntrinsic(
Opc, 2,
I);
6496 case Intrinsic::aarch64_neon_ld3: {
6497 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6500 Opc = AArch64::LD3Threev8b;
6502 Opc = AArch64::LD3Threev16b;
6504 Opc = AArch64::LD3Threev4h;
6506 Opc = AArch64::LD3Threev8h;
6508 Opc = AArch64::LD3Threev2s;
6510 Opc = AArch64::LD3Threev4s;
6512 Opc = AArch64::LD3Threev2d;
6513 else if (Ty ==
S64 || Ty == P0)
6514 Opc = AArch64::LD1Threev1d;
6517 selectVectorLoadIntrinsic(
Opc, 3,
I);
6520 case Intrinsic::aarch64_neon_ld3lane: {
6521 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6524 Opc = AArch64::LD3i8;
6526 Opc = AArch64::LD3i16;
6528 Opc = AArch64::LD3i32;
6531 Opc = AArch64::LD3i64;
6534 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6538 case Intrinsic::aarch64_neon_ld3r: {
6539 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6542 Opc = AArch64::LD3Rv8b;
6544 Opc = AArch64::LD3Rv16b;
6546 Opc = AArch64::LD3Rv4h;
6548 Opc = AArch64::LD3Rv8h;
6550 Opc = AArch64::LD3Rv2s;
6552 Opc = AArch64::LD3Rv4s;
6554 Opc = AArch64::LD3Rv2d;
6555 else if (Ty ==
S64 || Ty == P0)
6556 Opc = AArch64::LD3Rv1d;
6559 selectVectorLoadIntrinsic(
Opc, 3,
I);
6562 case Intrinsic::aarch64_neon_ld4: {
6563 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6566 Opc = AArch64::LD4Fourv8b;
6568 Opc = AArch64::LD4Fourv16b;
6570 Opc = AArch64::LD4Fourv4h;
6572 Opc = AArch64::LD4Fourv8h;
6574 Opc = AArch64::LD4Fourv2s;
6576 Opc = AArch64::LD4Fourv4s;
6578 Opc = AArch64::LD4Fourv2d;
6579 else if (Ty ==
S64 || Ty == P0)
6580 Opc = AArch64::LD1Fourv1d;
6583 selectVectorLoadIntrinsic(
Opc, 4,
I);
6586 case Intrinsic::aarch64_neon_ld4lane: {
6587 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6590 Opc = AArch64::LD4i8;
6592 Opc = AArch64::LD4i16;
6594 Opc = AArch64::LD4i32;
6597 Opc = AArch64::LD4i64;
6600 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6604 case Intrinsic::aarch64_neon_ld4r: {
6605 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6608 Opc = AArch64::LD4Rv8b;
6610 Opc = AArch64::LD4Rv16b;
6612 Opc = AArch64::LD4Rv4h;
6614 Opc = AArch64::LD4Rv8h;
6616 Opc = AArch64::LD4Rv2s;
6618 Opc = AArch64::LD4Rv4s;
6620 Opc = AArch64::LD4Rv2d;
6621 else if (Ty ==
S64 || Ty == P0)
6622 Opc = AArch64::LD4Rv1d;
6625 selectVectorLoadIntrinsic(
Opc, 4,
I);
6628 case Intrinsic::aarch64_neon_st1x2: {
6629 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6632 Opc = AArch64::ST1Twov8b;
6634 Opc = AArch64::ST1Twov16b;
6636 Opc = AArch64::ST1Twov4h;
6638 Opc = AArch64::ST1Twov8h;
6640 Opc = AArch64::ST1Twov2s;
6642 Opc = AArch64::ST1Twov4s;
6644 Opc = AArch64::ST1Twov2d;
6645 else if (Ty ==
S64 || Ty == P0)
6646 Opc = AArch64::ST1Twov1d;
6649 selectVectorStoreIntrinsic(
I, 2,
Opc);
6652 case Intrinsic::aarch64_neon_st1x3: {
6653 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6656 Opc = AArch64::ST1Threev8b;
6658 Opc = AArch64::ST1Threev16b;
6660 Opc = AArch64::ST1Threev4h;
6662 Opc = AArch64::ST1Threev8h;
6664 Opc = AArch64::ST1Threev2s;
6666 Opc = AArch64::ST1Threev4s;
6668 Opc = AArch64::ST1Threev2d;
6669 else if (Ty ==
S64 || Ty == P0)
6670 Opc = AArch64::ST1Threev1d;
6673 selectVectorStoreIntrinsic(
I, 3,
Opc);
6676 case Intrinsic::aarch64_neon_st1x4: {
6677 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6680 Opc = AArch64::ST1Fourv8b;
6682 Opc = AArch64::ST1Fourv16b;
6684 Opc = AArch64::ST1Fourv4h;
6686 Opc = AArch64::ST1Fourv8h;
6688 Opc = AArch64::ST1Fourv2s;
6690 Opc = AArch64::ST1Fourv4s;
6692 Opc = AArch64::ST1Fourv2d;
6693 else if (Ty ==
S64 || Ty == P0)
6694 Opc = AArch64::ST1Fourv1d;
6697 selectVectorStoreIntrinsic(
I, 4,
Opc);
6700 case Intrinsic::aarch64_neon_st2: {
6701 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6704 Opc = AArch64::ST2Twov8b;
6706 Opc = AArch64::ST2Twov16b;
6708 Opc = AArch64::ST2Twov4h;
6710 Opc = AArch64::ST2Twov8h;
6712 Opc = AArch64::ST2Twov2s;
6714 Opc = AArch64::ST2Twov4s;
6716 Opc = AArch64::ST2Twov2d;
6717 else if (Ty ==
S64 || Ty == P0)
6718 Opc = AArch64::ST1Twov1d;
6721 selectVectorStoreIntrinsic(
I, 2,
Opc);
6724 case Intrinsic::aarch64_neon_st3: {
6725 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6728 Opc = AArch64::ST3Threev8b;
6730 Opc = AArch64::ST3Threev16b;
6732 Opc = AArch64::ST3Threev4h;
6734 Opc = AArch64::ST3Threev8h;
6736 Opc = AArch64::ST3Threev2s;
6738 Opc = AArch64::ST3Threev4s;
6740 Opc = AArch64::ST3Threev2d;
6741 else if (Ty ==
S64 || Ty == P0)
6742 Opc = AArch64::ST1Threev1d;
6745 selectVectorStoreIntrinsic(
I, 3,
Opc);
6748 case Intrinsic::aarch64_neon_st4: {
6749 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6752 Opc = AArch64::ST4Fourv8b;
6754 Opc = AArch64::ST4Fourv16b;
6756 Opc = AArch64::ST4Fourv4h;
6758 Opc = AArch64::ST4Fourv8h;
6760 Opc = AArch64::ST4Fourv2s;
6762 Opc = AArch64::ST4Fourv4s;
6764 Opc = AArch64::ST4Fourv2d;
6765 else if (Ty ==
S64 || Ty == P0)
6766 Opc = AArch64::ST1Fourv1d;
6769 selectVectorStoreIntrinsic(
I, 4,
Opc);
6772 case Intrinsic::aarch64_neon_st2lane: {
6773 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6776 Opc = AArch64::ST2i8;
6778 Opc = AArch64::ST2i16;
6780 Opc = AArch64::ST2i32;
6783 Opc = AArch64::ST2i64;
6786 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6790 case Intrinsic::aarch64_neon_st3lane: {
6791 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6794 Opc = AArch64::ST3i8;
6796 Opc = AArch64::ST3i16;
6798 Opc = AArch64::ST3i32;
6801 Opc = AArch64::ST3i64;
6804 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6808 case Intrinsic::aarch64_neon_st4lane: {
6809 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6812 Opc = AArch64::ST4i8;
6814 Opc = AArch64::ST4i16;
6816 Opc = AArch64::ST4i32;
6819 Opc = AArch64::ST4i64;
6822 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6826 case Intrinsic::aarch64_mops_memset_tag: {
6839 Register DstDef =
I.getOperand(0).getReg();
6841 Register DstUse =
I.getOperand(2).getReg();
6842 Register ValUse =
I.getOperand(3).getReg();
6843 Register SizeUse =
I.getOperand(4).getReg();
6850 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6851 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6856 case Intrinsic::ptrauth_resign_load_relative: {
6857 Register DstReg =
I.getOperand(0).getReg();
6858 Register ValReg =
I.getOperand(2).getReg();
6859 uint64_t AUTKey =
I.getOperand(3).getImm();
6860 Register AUTDisc =
I.getOperand(4).getReg();
6861 uint64_t PACKey =
I.getOperand(5).getImm();
6862 Register PACDisc =
I.getOperand(6).getReg();
6863 int64_t Addend =
I.getOperand(7).getImm();
6866 uint16_t AUTConstDiscC = 0;
6867 std::tie(AUTConstDiscC, AUTAddrDisc) =
6871 uint16_t PACConstDiscC = 0;
6872 std::tie(PACConstDiscC, PACAddrDisc) =
6875 MIB.
buildCopy({AArch64::X16}, {ValReg});
6889 I.eraseFromParent();
6894 I.eraseFromParent();
6898bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6899 MachineRegisterInfo &MRI) {
6905 case Intrinsic::ptrauth_resign: {
6906 Register DstReg =
I.getOperand(0).getReg();
6907 Register ValReg =
I.getOperand(2).getReg();
6908 uint64_t AUTKey =
I.getOperand(3).getImm();
6909 Register AUTDisc =
I.getOperand(4).getReg();
6910 uint64_t PACKey =
I.getOperand(5).getImm();
6911 Register PACDisc =
I.getOperand(6).getReg();
6914 uint16_t AUTConstDiscC = 0;
6915 std::tie(AUTConstDiscC, AUTAddrDisc) =
6919 uint16_t PACConstDiscC = 0;
6920 std::tie(PACConstDiscC, PACAddrDisc) =
6923 MIB.
buildCopy({AArch64::X16}, {ValReg});
6924 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6936 I.eraseFromParent();
6939 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6940 Register DstReg =
I.getOperand(0).getReg();
6941 Register ValReg =
I.getOperand(2).getReg();
6942 uint64_t AUTKey =
I.getOperand(3).getImm();
6943 Register AUTDisc =
I.getOperand(4).getReg();
6944 Register AUTPC =
I.getOperand(5).getReg();
6945 uint64_t PACKey =
I.getOperand(6).getImm();
6946 Register PACDisc =
I.getOperand(7).getReg();
6949 "auth_with_pc_and_resign only supports IA and IB keys");
6951 uint16_t PACConstDiscC = 0;
6953 std::tie(PACConstDiscC, PACAddrDisc) =
6957 PACAddrDisc = AArch64::XZR;
6959 MIB.
buildCopy({AArch64::X17}, {ValReg});
6960 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6972 I.eraseFromParent();
6975 case Intrinsic::ptrauth_auth: {
6976 Register DstReg =
I.getOperand(0).getReg();
6977 Register ValReg =
I.getOperand(2).getReg();
6978 uint64_t AUTKey =
I.getOperand(3).getImm();
6979 Register AUTDisc =
I.getOperand(4).getReg();
6982 uint16_t AUTConstDiscC = 0;
6983 std::tie(AUTConstDiscC, AUTAddrDisc) =
6987 MIB.
buildCopy({AArch64::X16}, {ValReg});
6988 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7009 I.eraseFromParent();
7012 case Intrinsic::frameaddress:
7013 case Intrinsic::returnaddress: {
7017 unsigned Depth =
I.getOperand(2).getImm();
7018 Register DstReg =
I.getOperand(0).getReg();
7021 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
7022 if (!MFReturnAddr) {
7027 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
7030 if (STI.hasPAuth()) {
7031 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
7038 I.eraseFromParent();
7047 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
7049 FrameAddr = NextFrame;
7052 if (IntrinID == Intrinsic::frameaddress)
7057 if (STI.hasPAuth()) {
7059 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
7060 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
7069 I.eraseFromParent();
7072 case Intrinsic::aarch64_neon_tbl2:
7073 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
7075 case Intrinsic::aarch64_neon_tbl3:
7076 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
7079 case Intrinsic::aarch64_neon_tbl4:
7080 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
7082 case Intrinsic::aarch64_neon_tbx2:
7083 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
7085 case Intrinsic::aarch64_neon_tbx3:
7086 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
7088 case Intrinsic::aarch64_neon_tbx4:
7089 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
7091 case Intrinsic::swift_async_context_addr:
7092 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
7099 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
7100 I.eraseFromParent();
7135bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
7136 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
7137 Register DefReg =
I.getOperand(0).getReg();
7138 Register Addr =
I.getOperand(1).getReg();
7140 Register AddrDisc =
I.getOperand(3).getReg();
7141 uint64_t Disc =
I.getOperand(4).getImm();
7151 "constant discriminator in ptrauth global out of range [0, 0xffff]");
7167 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
7179 const GlobalValue *GV;
7190 MachineIRBuilder MIB(
I);
7196 "unsupported non-GOT op flags on ptrauth global reference");
7198 "unsupported non-GOT reference to weak ptrauth global");
7201 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7208 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7209 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7210 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7213 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7218 I.eraseFromParent();
7230 "unsupported non-zero offset in weak ptrauth global reference");
7235 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7236 .addGlobalAddress(GV,
Offset)
7241 I.eraseFromParent();
7245void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7246 MachineRegisterInfo &MRI,
7247 unsigned NumVec,
unsigned Opc1,
7248 unsigned Opc2,
bool isExt) {
7249 Register DstReg =
I.getOperand(0).getReg();
7254 for (
unsigned i = 0; i < NumVec; i++)
7255 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7258 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7259 MachineInstrBuilder
Instr;
7266 I.eraseFromParent();
7269InstructionSelector::ComplexRendererFns
7270AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7272 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7273 return std::nullopt;
7274 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7275 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7278InstructionSelector::ComplexRendererFns
7279AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7281 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7282 return std::nullopt;
7284 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7287InstructionSelector::ComplexRendererFns
7288AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7290 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7291 return std::nullopt;
7292 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7293 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7296InstructionSelector::ComplexRendererFns
7297AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7299 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7300 return std::nullopt;
7302 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7310InstructionSelector::ComplexRendererFns
7311AArch64InstructionSelector::select12BitValueWithLeftShift(
7314 if (Immed >> 12 == 0) {
7316 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7318 Immed = Immed >> 12;
7320 return std::nullopt;
7324 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7325 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7332InstructionSelector::ComplexRendererFns
7333AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7340 if (MaybeImmed == std::nullopt)
7341 return std::nullopt;
7342 return select12BitValueWithLeftShift(*MaybeImmed);
7347InstructionSelector::ComplexRendererFns
7348AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7352 return std::nullopt;
7354 if (MaybeImmed == std::nullopt)
7355 return std::nullopt;
7362 return std::nullopt;
7368 Immed = ~((uint32_t)Immed) + 1;
7370 Immed = ~Immed + 1ULL;
7372 if (Immed & 0xFFFFFFFFFF000000ULL)
7373 return std::nullopt;
7375 Immed &= 0xFFFFFFULL;
7376 return select12BitValueWithLeftShift(Immed);
7393std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7394 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7395 if (
MI.getOpcode() == AArch64::G_SHL) {
7399 MI.getOperand(2).getReg(), MRI)) {
7400 const APInt ShiftVal = ValAndVeg->Value;
7403 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7406 return std::nullopt;
7414bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7415 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7416 bool IsAddrOperand)
const {
7421 MI.getParent()->getParent()->getFunction().hasOptSize())
7424 if (IsAddrOperand) {
7426 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7430 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7431 MachineInstr *OffsetInst =
7437 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7448 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7451InstructionSelector::ComplexRendererFns
7452AArch64InstructionSelector::selectExtendedSHL(
7453 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7454 unsigned SizeInBytes,
bool WantsExt)
const {
7455 assert(
Base.isReg() &&
"Expected base to be a register operand");
7456 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7461 unsigned OffsetOpc = OffsetInst->
getOpcode();
7462 bool LookedThroughZExt =
false;
7463 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7465 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7466 return std::nullopt;
7470 LookedThroughZExt =
true;
7472 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7473 return std::nullopt;
7476 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7477 if (LegalShiftVal == 0)
7478 return std::nullopt;
7479 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7480 return std::nullopt;
7491 if (OffsetOpc == TargetOpcode::G_SHL)
7492 return std::nullopt;
7498 return std::nullopt;
7503 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7507 if (OffsetOpc == TargetOpcode::G_MUL) {
7509 return std::nullopt;
7515 if ((ImmVal & 0x7) != ImmVal)
7516 return std::nullopt;
7520 if (ImmVal != LegalShiftVal)
7521 return std::nullopt;
7523 unsigned SignExtend = 0;
7527 if (!LookedThroughZExt) {
7529 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7531 return std::nullopt;
7536 return std::nullopt;
7542 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7547 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7548 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7549 [=](MachineInstrBuilder &MIB) {
7552 MIB.addImm(SignExtend);
7565InstructionSelector::ComplexRendererFns
7566AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7567 MachineOperand &Root,
unsigned SizeInBytes)
const {
7569 return std::nullopt;
7584 MachineInstr *PtrAdd =
7586 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7587 return std::nullopt;
7591 MachineInstr *OffsetInst =
7593 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7606InstructionSelector::ComplexRendererFns
7607AArch64InstructionSelector::selectAddrModeRegisterOffset(
7608 MachineOperand &Root)
const {
7614 return std::nullopt;
7620 return std::nullopt;
7623 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7624 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7625 [=](MachineInstrBuilder &MIB) {
7635InstructionSelector::ComplexRendererFns
7636AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7637 unsigned SizeInBytes)
const {
7640 return std::nullopt;
7641 MachineInstr *PtrAdd =
7644 return std::nullopt;
7662 unsigned Scale =
Log2_32(SizeInBytes);
7663 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7667 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7668 ImmOff < (0x1000 << Scale))
7669 return std::nullopt;
7674 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7678 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7684 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7685 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7690 return std::nullopt;
7694 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7700 return selectAddrModeRegisterOffset(Root);
7709InstructionSelector::ComplexRendererFns
7710AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7711 unsigned SizeInBytes)
const {
7714 MachineInstr *PtrAdd =
7716 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7717 return std::nullopt;
7738 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7747 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7748 return std::nullopt;
7752 getExtendTypeForInst(*OffsetInst, MRI,
true);
7754 return std::nullopt;
7757 MachineIRBuilder MIB(*PtrAdd);
7759 AArch64::GPR32RegClass, MIB);
7763 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7764 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7765 [=](MachineInstrBuilder &MIB) {
7766 MIB.addImm(SignExtend);
7776InstructionSelector::ComplexRendererFns
7777AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7778 unsigned Size)
const {
7779 MachineRegisterInfo &MRI =
7783 return std::nullopt;
7785 if (!isBaseWithConstantOffset(Root, MRI))
7786 return std::nullopt;
7790 MachineOperand &OffImm = RootDef->
getOperand(2);
7791 if (!OffImm.
isReg())
7792 return std::nullopt;
7794 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7795 return std::nullopt;
7797 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7799 return std::nullopt;
7802 if (RHSC >= -256 && RHSC < 256) {
7805 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7806 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7809 return std::nullopt;
7812InstructionSelector::ComplexRendererFns
7813AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7815 MachineRegisterInfo &MRI)
const {
7816 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7817 return std::nullopt;
7820 return std::nullopt;
7825 return std::nullopt;
7829 return std::nullopt;
7833 return std::nullopt;
7836 MachineIRBuilder MIRBuilder(RootDef);
7838 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7839 [=](MachineInstrBuilder &MIB) {
7840 MIB.addGlobalAddress(GV,
Offset,
7849InstructionSelector::ComplexRendererFns
7850AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7851 unsigned Size)
const {
7856 return std::nullopt;
7859 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7861 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7862 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7870 MachineInstr *RootParent = Root.
getParent();
7872 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7874 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7879 if (isBaseWithConstantOffset(Root, MRI)) {
7887 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7888 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7890 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7891 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7895 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7896 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7903 if (selectAddrModeUnscaled(Root,
Size))
7904 return std::nullopt;
7907 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7908 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7915 switch (
MI.getOpcode()) {
7918 case TargetOpcode::G_SHL:
7920 case TargetOpcode::G_LSHR:
7922 case TargetOpcode::G_ASHR:
7924 case TargetOpcode::G_ROTR:
7931InstructionSelector::ComplexRendererFns
7932AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7933 bool AllowROR)
const {
7935 return std::nullopt;
7936 MachineRegisterInfo &MRI =
7944 return std::nullopt;
7946 return std::nullopt;
7947 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7948 return std::nullopt;
7951 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7954 return std::nullopt;
7958 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7962 unsigned Val = *Immed & (NumBits - 1);
7965 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7966 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7970 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7971 unsigned Opc =
MI.getOpcode();
7974 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7976 if (
Opc == TargetOpcode::G_SEXT)
7979 Size =
MI.getOperand(2).getImm();
7980 assert(
Size != 64 &&
"Extend from 64 bits?");
7993 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7995 assert(
Size != 64 &&
"Extend from 64 bits?");
8010 if (
Opc != TargetOpcode::G_AND)
8029Register AArch64InstructionSelector::moveScalarRegClass(
8031 MachineRegisterInfo &MRI = *MIB.
getMRI();
8041 return Copy.getReg(0);
8046InstructionSelector::ComplexRendererFns
8047AArch64InstructionSelector::selectArithExtendedRegister(
8048 MachineOperand &Root)
const {
8050 return std::nullopt;
8051 MachineRegisterInfo &MRI =
8059 return std::nullopt;
8061 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
8062 return std::nullopt;
8065 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
8070 return std::nullopt;
8071 ShiftVal = *MaybeShiftVal;
8073 return std::nullopt;
8078 return std::nullopt;
8079 Ext = getExtendTypeForInst(*ExtDef, MRI);
8081 return std::nullopt;
8085 Ext = getExtendTypeForInst(*RootDef, MRI);
8087 return std::nullopt;
8095 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
8096 if (isDef32(*ExtInst))
8097 return std::nullopt;
8103 MachineIRBuilder MIB(*RootDef);
8104 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
8106 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
8107 [=](MachineInstrBuilder &MIB) {
8108 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
8112InstructionSelector::ComplexRendererFns
8113AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
8115 return std::nullopt;
8116 MachineRegisterInfo &MRI =
8120 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
8125 return std::nullopt;
8128 if (Unmerge->getNumDefs() == 2 &&
8130 Register ExtReg = Unmerge->getSourceReg();
8131 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8135 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
8139 LaneIdx->Value.getSExtValue() == 1) {
8140 Register ExtReg = ExtElt->getVectorReg();
8141 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8145 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
8146 auto LaneIdx = Subvec->getIndexImm();
8148 Register ExtReg = Subvec->getSrcVec();
8149 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8153 return std::nullopt;
8156InstructionSelector::ComplexRendererFns
8157AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
8158 unsigned DstElemWidth,
8159 bool isReciprocal)
const {
8161 return std::nullopt;
8162 const MachineRegisterInfo &MRI =
8168 if (Dup && Dup->
getOpcode() == AArch64::G_DUP)
8171 std::optional<ValueAndVReg> CstVal =
8175 return std::nullopt;
8179 switch (CstElemWidth) {
8181 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
8184 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8187 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8190 return std::nullopt;
8192 if (
unsigned FBits =
8194 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8196 return std::nullopt;
8199unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8200 const MachineOperand &Root)
const {
8208template <
unsigned W
idth>
8209InstructionSelector::ComplexRendererFns
8210AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8211 return selectCVTFixedPointBase(Root, Width,
false);
8214InstructionSelector::ComplexRendererFns
8215AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8216 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8220InstructionSelector::ComplexRendererFns
8221AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8222 MachineOperand &Root)
const {
8223 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8227void AArch64InstructionSelector::renderFixedPointScalarXForm(
8228 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8229 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8230 "Expected vecshift immediate operand");
8231 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8234void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8235 const MachineOperand &Root,
8237 bool isReciprocal)
const {
8241 InstructionSelector::ComplexRendererFns Renderer =
8242 selectCVTFixedPointBase(Root, Width, isReciprocal);
8243 assert((Renderer && Renderer->size() == 1) &&
8244 "Expected selectCVTFixedPointBase to provide a function\n");
8245 (Renderer->front())(MIB);
8248void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8249 const MachineInstr &
MI,
8251 const MachineOperand &Root =
MI.getOperand(OpIdx);
8252 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8256void AArch64InstructionSelector::renderFixedPointRecipXForm(
8257 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8258 const MachineOperand &Root =
MI.getOperand(OpIdx);
8259 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8263void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8264 const MachineInstr &
MI,
8266 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8267 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8268 "Expected G_CONSTANT");
8269 std::optional<int64_t> CstVal =
8271 assert(CstVal &&
"Expected constant value");
8275void AArch64InstructionSelector::renderLogicalImm32(
8276 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8277 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8278 "Expected G_CONSTANT");
8279 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8284void AArch64InstructionSelector::renderLogicalImm64(
8285 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8286 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8287 "Expected G_CONSTANT");
8288 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8293void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8294 const MachineInstr &
MI,
8296 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8297 "Expected G_UBSANTRAP");
8298 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8301void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8302 const MachineInstr &
MI,
8304 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8305 "Expected G_FCONSTANT");
8310void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8311 const MachineInstr &
MI,
8313 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8314 "Expected G_FCONSTANT");
8319void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8320 const MachineInstr &
MI,
8322 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8323 "Expected G_FCONSTANT");
8328void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8329 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8330 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8331 "Expected G_FCONSTANT");
8339bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8340 const MachineInstr &
MI,
unsigned NumBytes)
const {
8341 if (!
MI.mayLoadOrStore())
8344 "Expected load/store to have only one mem op!");
8345 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8348bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8349 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8357 switch (
MI.getOpcode()) {
8360 case TargetOpcode::COPY:
8361 case TargetOpcode::G_BITCAST:
8362 case TargetOpcode::G_TRUNC:
8363 case TargetOpcode::G_PHI:
8373 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8376 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8394 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8399 MO.setReg(Copy.getReg(0));
8408 for (
auto &BB : MF) {
8409 for (
auto &
MI : BB) {
8410 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8415 for (
auto *
MI : Phis) {
8437 bool HasGPROp =
false, HasFPROp =
false;
8441 const LLT &Ty = MRI.
getType(MO.getReg());
8451 if (RB->
getID() == AArch64::GPRRegBankID)
8457 if (HasGPROp && HasFPROp)
8463InstructionSelector *
8467 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc, 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 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 std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< 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.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
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 & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI 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.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
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.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_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 uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
TLSModel::Model getELFTLSModel(const GlobalValue *GV, const TargetMachine &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.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
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 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.