45#include "llvm/IR/IntrinsicsAArch64.h"
52#define DEBUG_TYPE "aarch64-isel"
65#define GET_GLOBALISEL_PREDICATE_BITSET
66#include "AArch64GenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATE_BITSET
87 ProduceNonFlagSettingCondBr =
135 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
213 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
215 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
217 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
219 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
233 unsigned Opc1,
unsigned Opc2,
bool isExt);
239 unsigned emitConstantPoolEntry(
const Constant *CPVal,
258 std::optional<CmpInst::Predicate> = std::nullopt)
const;
261 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
262 std::initializer_list<llvm::SrcOp> SrcOps,
264 const ComplexRendererFns &RenderFns = std::nullopt)
const;
299 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
322 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
344 std::pair<MachineInstr *, AArch64CC::CondCode>
379 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
380 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
381 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
382 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
384 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
386 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
389 unsigned Size)
const;
391 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
392 return selectAddrModeUnscaled(Root, 1);
394 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
395 return selectAddrModeUnscaled(Root, 2);
397 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
398 return selectAddrModeUnscaled(Root, 4);
400 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
401 return selectAddrModeUnscaled(Root, 8);
403 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
404 return selectAddrModeUnscaled(Root, 16);
409 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
413 unsigned Size)
const;
415 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
416 return selectAddrModeIndexed(Root, Width / 8);
425 bool IsAddrOperand)
const;
428 unsigned SizeInBytes)
const;
436 bool WantsExt)
const;
437 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
439 unsigned SizeInBytes)
const;
441 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
442 return selectAddrModeXRO(Root, Width / 8);
446 unsigned SizeInBytes)
const;
448 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
449 return selectAddrModeWRO(Root, Width / 8);
453 bool AllowROR =
false)
const;
455 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
456 return selectShiftedRegister(Root);
459 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
460 return selectShiftedRegister(Root,
true);
470 bool IsLoadStore =
false)
const;
481 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
484 template <
unsigned W
idth>
485 ComplexRendererFns selectCVTFixedPoint(
MachineOperand &Root)
const;
486 ComplexRendererFns selectCVTFixedPointBase(
const MachineOperand &Root,
488 bool isReciprocal =
false)
const;
489 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
494 unsigned getFixedPointWidthFromOperand(
const MachineOperand &Root)
const;
496 int OpIdx = -1)
const;
500 unsigned Width,
bool isReciprocal)
const;
502 int OpIdx = -1)
const;
504 int OpIdx = -1)
const;
506 int OpIdx = -1)
const;
510 int OpIdx = -1)
const;
512 int OpIdx = -1)
const;
514 int OpIdx = -1)
const;
517 int OpIdx = -1)
const;
523 bool tryOptSelect(
GSelect &Sel);
530 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
543 bool ProduceNonFlagSettingCondBr =
false;
552#define GET_GLOBALISEL_PREDICATES_DECL
553#include "AArch64GenGlobalISel.inc"
554#undef GET_GLOBALISEL_PREDICATES_DECL
558#define GET_GLOBALISEL_TEMPORARIES_DECL
559#include "AArch64GenGlobalISel.inc"
560#undef GET_GLOBALISEL_TEMPORARIES_DECL
565#define GET_GLOBALISEL_IMPL
566#include "AArch64GenGlobalISel.inc"
567#undef GET_GLOBALISEL_IMPL
569AArch64InstructionSelector::AArch64InstructionSelector(
572 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
575#include
"AArch64GenGlobalISel.inc"
578#include
"AArch64GenGlobalISel.inc"
590 bool GetAllRegSet =
false) {
591 if (RB.
getID() == AArch64::GPRRegBankID) {
592 if (Ty.getSizeInBits() <= 32)
593 return GetAllRegSet ? &AArch64::GPR32allRegClass
594 : &AArch64::GPR32RegClass;
595 if (Ty.getSizeInBits() == 64)
596 return GetAllRegSet ? &AArch64::GPR64allRegClass
597 : &AArch64::GPR64RegClass;
598 if (Ty.getSizeInBits() == 128)
599 return &AArch64::XSeqPairsClassRegClass;
603 if (RB.
getID() == AArch64::FPRRegBankID) {
604 switch (Ty.getSizeInBits()) {
606 return &AArch64::FPR8RegClass;
608 return &AArch64::FPR16RegClass;
610 return &AArch64::FPR32RegClass;
612 return &AArch64::FPR64RegClass;
614 return &AArch64::FPR128RegClass;
626 bool GetAllRegSet =
false) {
629 "Expected FPR regbank for scalable type size");
630 return &AArch64::ZPRRegClass;
633 unsigned RegBankID = RB.
getID();
635 if (RegBankID == AArch64::GPRRegBankID) {
637 if (SizeInBits <= 32)
638 return GetAllRegSet ? &AArch64::GPR32allRegClass
639 : &AArch64::GPR32RegClass;
640 if (SizeInBits == 64)
641 return GetAllRegSet ? &AArch64::GPR64allRegClass
642 : &AArch64::GPR64RegClass;
643 if (SizeInBits == 128)
644 return &AArch64::XSeqPairsClassRegClass;
647 if (RegBankID == AArch64::FPRRegBankID) {
650 "Unexpected scalable register size");
651 return &AArch64::ZPRRegClass;
654 switch (SizeInBits) {
658 return &AArch64::FPR8RegClass;
660 return &AArch64::FPR16RegClass;
662 return &AArch64::FPR32RegClass;
664 return &AArch64::FPR64RegClass;
666 return &AArch64::FPR128RegClass;
676 switch (
TRI.getRegSizeInBits(*RC)) {
678 SubReg = AArch64::bsub;
681 SubReg = AArch64::hsub;
684 if (RC != &AArch64::FPR32RegClass)
685 SubReg = AArch64::sub_32;
687 SubReg = AArch64::ssub;
690 SubReg = AArch64::dsub;
694 dbgs() <<
"Couldn't find appropriate subregister for register class.");
703 switch (RB.
getID()) {
704 case AArch64::GPRRegBankID:
706 case AArch64::FPRRegBankID:
729 const unsigned RegClassIDs[],
731 unsigned NumRegs = Regs.
size();
734 assert(NumRegs >= 2 && NumRegs <= 4 &&
735 "Only support between two and 4 registers in a tuple!");
737 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
739 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
740 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
741 RegSequence.addUse(Regs[
I]);
742 RegSequence.addImm(SubRegs[
I]);
744 return RegSequence.getReg(0);
749 static const unsigned RegClassIDs[] = {
750 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
751 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
752 AArch64::dsub2, AArch64::dsub3};
753 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
758 static const unsigned RegClassIDs[] = {
759 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
760 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
761 AArch64::qsub2, AArch64::qsub3};
762 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
767 auto &
MBB = *
MI.getParent();
768 auto &MF = *
MBB.getParent();
769 auto &MRI = MF.getRegInfo();
775 else if (Root.
isReg()) {
780 Immed = ValAndVReg->Value.getSExtValue();
791 if (RegBankID == AArch64::GPRRegBankID) {
793 switch (GenericOpc) {
794 case TargetOpcode::G_SHL:
795 return AArch64::LSLVWr;
796 case TargetOpcode::G_LSHR:
797 return AArch64::LSRVWr;
798 case TargetOpcode::G_ASHR:
799 return AArch64::ASRVWr;
803 }
else if (OpSize == 64) {
804 switch (GenericOpc) {
805 case TargetOpcode::G_SHL:
806 return AArch64::LSLVXr;
807 case TargetOpcode::G_LSHR:
808 return AArch64::LSRVXr;
809 case TargetOpcode::G_ASHR:
810 return AArch64::ASRVXr;
826 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
828 case AArch64::GPRRegBankID:
831 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
833 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
835 return isStore ? AArch64::STRWui : AArch64::LDRWui;
837 return isStore ? AArch64::STRXui : AArch64::LDRXui;
840 case AArch64::FPRRegBankID:
843 return isStore ? AArch64::STRBui : AArch64::LDRBui;
845 return isStore ? AArch64::STRHui : AArch64::LDRHui;
847 return isStore ? AArch64::STRSui : AArch64::LDRSui;
849 return isStore ? AArch64::STRDui : AArch64::LDRDui;
851 return isStore ? AArch64::STRQui : AArch64::LDRQui;
865 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
866 assert(To &&
"Destination register class cannot be null");
867 assert(SubReg &&
"Expected a valid subregister");
871 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
873 RegOp.
setReg(SubRegCopy.getReg(0));
877 if (!
I.getOperand(0).getReg().isPhysical())
887static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
891 Register DstReg =
I.getOperand(0).getReg();
892 Register SrcReg =
I.getOperand(1).getReg();
907 if (SrcRegBank != DstRegBank &&
926 if (
Reg.isPhysical())
934 RC = getRegClassForTypeOnBank(Ty, RB);
937 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
950 Register DstReg =
I.getOperand(0).getReg();
951 Register SrcReg =
I.getOperand(1).getReg();
970 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
974 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
975 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
976 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
990 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
991 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
992 }
else if (SrcSize > DstSize) {
999 }
else if (DstSize > SrcSize) {
1008 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1012 RegOp.
setReg(PromoteReg);
1031 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1032 I.setDesc(
TII.get(AArch64::COPY));
1033 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1037 I.setDesc(
TII.get(AArch64::COPY));
1045 MachineRegisterInfo &MRI = *MIB.
getMRI();
1048 "Expected both select operands to have the same regbank?");
1054 "Expected 32 bit or 64 bit select only?");
1055 const bool Is32Bit =
Size == 32;
1057 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1058 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1064 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1066 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1081 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1098 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1117 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1133 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1139 if (!TrueCst && !FalseCst)
1142 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1143 if (TrueCst && FalseCst) {
1144 int64_t
T = TrueCst->Value.getSExtValue();
1145 int64_t
F = FalseCst->Value.getSExtValue();
1147 if (
T == 0 &&
F == 1) {
1149 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1155 if (
T == 0 &&
F == -1) {
1157 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1165 int64_t
T = TrueCst->Value.getSExtValue();
1168 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1177 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1186 int64_t
F = FalseCst->Value.getSExtValue();
1189 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1196 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1204 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1205 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1207 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1209 return &*SelectInst;
1214 MachineRegisterInfo *MRI =
nullptr) {
1227 if (ValAndVReg && ValAndVReg->Value == 0)
1234 if (ValAndVReg && ValAndVReg->Value == 0)
1338 assert(
Reg.isValid() &&
"Expected valid register!");
1339 bool HasZext =
false;
1341 unsigned Opc =
MI->getOpcode();
1343 if (!
MI->getOperand(0).isReg() ||
1352 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1353 Opc == TargetOpcode::G_TRUNC) {
1354 if (
Opc == TargetOpcode::G_ZEXT)
1357 Register NextReg =
MI->getOperand(1).getReg();
1371 std::optional<uint64_t>
C;
1376 case TargetOpcode::G_AND:
1377 case TargetOpcode::G_XOR: {
1378 TestReg =
MI->getOperand(1).getReg();
1379 Register ConstantReg =
MI->getOperand(2).getReg();
1390 C = VRegAndVal->Value.getZExtValue();
1392 C = VRegAndVal->Value.getSExtValue();
1396 case TargetOpcode::G_ASHR:
1397 case TargetOpcode::G_LSHR:
1398 case TargetOpcode::G_SHL: {
1399 TestReg =
MI->getOperand(1).getReg();
1403 C = VRegAndVal->Value.getSExtValue();
1419 case TargetOpcode::G_AND:
1421 if ((*
C >> Bit) & 1)
1424 case TargetOpcode::G_SHL:
1427 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1432 case TargetOpcode::G_ASHR:
1437 if (Bit >= TestRegSize)
1438 Bit = TestRegSize - 1;
1440 case TargetOpcode::G_LSHR:
1442 if ((Bit + *
C) < TestRegSize) {
1447 case TargetOpcode::G_XOR:
1456 if ((*
C >> Bit) & 1)
1471MachineInstr *AArch64InstructionSelector::emitTestBit(
1472 Register TestReg,
uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1473 MachineIRBuilder &MIB)
const {
1475 assert(ProduceNonFlagSettingCondBr &&
1476 "Cannot emit TB(N)Z with speculation tracking!");
1477 MachineRegisterInfo &MRI = *MIB.
getMRI();
1481 LLT Ty = MRI.
getType(TestReg);
1484 assert(Bit < 64 &&
"Bit is too large!");
1488 bool UseWReg =
Bit < 32;
1489 unsigned NecessarySize = UseWReg ? 32 : 64;
1490 if (
Size != NecessarySize)
1491 TestReg = moveScalarRegClass(
1492 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1495 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1496 {AArch64::TBZW, AArch64::TBNZW}};
1497 unsigned Opc = OpcTable[UseWReg][IsNegative];
1504bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1505 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1506 MachineIRBuilder &MIB)
const {
1507 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1534 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1541 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1545MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1547 MachineBasicBlock *DestMBB,
1548 MachineIRBuilder &MIB)
const {
1549 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1550 MachineRegisterInfo &MRI = *MIB.
getMRI();
1552 AArch64::GPRRegBankID &&
1553 "Expected GPRs only?");
1554 auto Ty = MRI.
getType(CompareReg);
1557 assert(Width <= 64 &&
"Expected width to be at most 64?");
1558 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1559 {AArch64::CBNZW, AArch64::CBNZX}};
1560 unsigned Opc = OpcTable[IsNegative][Width == 64];
1561 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1566bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1567 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1569 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1577 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1581 I.eraseFromParent();
1585bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1586 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1588 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1594 if (!ProduceNonFlagSettingCondBr)
1597 MachineRegisterInfo &MRI = *MIB.
getMRI();
1598 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1613 if (VRegAndVal && !AndInst) {
1614 int64_t
C = VRegAndVal->Value.getSExtValue();
1620 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1621 I.eraseFromParent();
1629 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1630 I.eraseFromParent();
1638 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1639 I.eraseFromParent();
1653 if (VRegAndVal && VRegAndVal->Value == 0) {
1661 tryOptAndIntoCompareBranch(
1663 I.eraseFromParent();
1669 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1671 I.eraseFromParent();
1680bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1681 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1683 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1684 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1688 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1695 I.eraseFromParent();
1699bool AArch64InstructionSelector::selectCompareBranch(
1701 Register CondReg =
I.getOperand(0).getReg();
1702 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1706 if (CCMIOpc == TargetOpcode::G_FCMP)
1707 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1708 if (CCMIOpc == TargetOpcode::G_ICMP)
1709 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1714 if (ProduceNonFlagSettingCondBr) {
1715 emitTestBit(CondReg, 0,
true,
1716 I.getOperand(1).getMBB(), MIB);
1717 I.eraseFromParent();
1727 .
addMBB(
I.getOperand(1).getMBB());
1728 I.eraseFromParent();
1748 return std::nullopt;
1750 int64_t
Imm = *ShiftImm;
1752 return std::nullopt;
1753 switch (SrcTy.getElementType().getSizeInBits()) {
1756 return std::nullopt;
1759 return std::nullopt;
1763 return std::nullopt;
1767 return std::nullopt;
1771 return std::nullopt;
1777bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1778 MachineRegisterInfo &MRI) {
1779 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1780 Register DstReg =
I.getOperand(0).getReg();
1781 const LLT Ty = MRI.
getType(DstReg);
1782 Register Src1Reg =
I.getOperand(1).getReg();
1783 Register Src2Reg =
I.getOperand(2).getReg();
1794 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1796 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1798 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1800 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1802 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1804 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1806 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1818 I.eraseFromParent();
1822bool AArch64InstructionSelector::selectVectorAshrLshr(
1823 MachineInstr &
I, MachineRegisterInfo &MRI) {
1824 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1825 I.getOpcode() == TargetOpcode::G_LSHR);
1826 Register DstReg =
I.getOperand(0).getReg();
1827 const LLT Ty = MRI.
getType(DstReg);
1828 Register Src1Reg =
I.getOperand(1).getReg();
1829 Register Src2Reg =
I.getOperand(2).getReg();
1834 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1844 unsigned NegOpc = 0;
1846 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1848 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1849 NegOpc = AArch64::NEGv2i64;
1851 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1852 NegOpc = AArch64::NEGv4i32;
1854 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1855 NegOpc = AArch64::NEGv2i32;
1857 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1858 NegOpc = AArch64::NEGv4i16;
1860 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1861 NegOpc = AArch64::NEGv8i16;
1863 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1864 NegOpc = AArch64::NEGv16i8;
1866 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1867 NegOpc = AArch64::NEGv8i8;
1873 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1877 I.eraseFromParent();
1881bool AArch64InstructionSelector::selectVaStartAAPCS(
1891 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1893 const auto *PtrRegClass =
1894 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1896 const MCInstrDesc &MCIDAddAddr =
1898 const MCInstrDesc &MCIDStoreAddr =
1910 const auto VAList =
I.getOperand(0).getReg();
1913 unsigned OffsetBytes = 0;
1917 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1919 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1926 const auto *MMO = *
I.memoperands_begin();
1927 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1930 .
addImm(OffsetBytes / PtrSize)
1932 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1936 OffsetBytes += PtrSize;
1952 const auto PushIntConstant = [&](
const int32_t
Value) {
1953 constexpr int IntSize = 4;
1956 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
1961 const auto *MMO = *
I.memoperands_begin();
1962 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
1965 .
addImm(OffsetBytes / IntSize)
1967 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1970 OffsetBytes += IntSize;
1974 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
1977 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
1981 I.eraseFromParent();
1985bool AArch64InstructionSelector::selectVaStartDarwin(
1987 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1988 Register ListReg =
I.getOperand(0).getReg();
1993 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2001 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2009 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2016 I.eraseFromParent();
2020void AArch64InstructionSelector::materializeLargeCMVal(
2021 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2026 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2041 GV, MovZ->getOperand(1).getOffset(), Flags));
2045 MovZ->getOperand(1).getOffset(), Flags));
2051 Register DstReg = BuildMovK(MovZ.getReg(0),
2057bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2062 switch (
I.getOpcode()) {
2063 case TargetOpcode::G_CONSTANT: {
2064 Register DefReg =
I.getOperand(0).getReg();
2065 const LLT DefTy = MRI.
getType(DefReg);
2071 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2072 I.getOperand(1).setCImm(
2077 I.getOperand(0).setReg(WideReg);
2086 if (PtrSize != 32 && PtrSize != 64)
2092 case TargetOpcode::G_STORE: {
2093 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2094 MachineOperand &SrcOp =
I.getOperand(0);
2107 case TargetOpcode::G_PTR_ADD: {
2111 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2113 return convertPtrAddToAdd(
I, MRI);
2115 case TargetOpcode::G_LOAD: {
2120 Register DstReg =
I.getOperand(0).getReg();
2121 const LLT DstTy = MRI.
getType(DstReg);
2127 case TargetOpcode::G_VECREDUCE_ADD:
2128 case TargetOpcode::G_VECREDUCE_SMAX:
2129 case TargetOpcode::G_VECREDUCE_SMIN:
2130 case TargetOpcode::G_VECREDUCE_UMAX:
2131 case TargetOpcode::G_VECREDUCE_UMIN: {
2134 Register DstReg =
I.getOperand(0).getReg();
2135 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2136 if (DstRB.
getID() != AArch64::GPRRegBankID)
2139 LLT DstTy = MRI.
getType(DstReg);
2141 getRegClassForTypeOnBank(DstTy, DstRB,
true);
2147 I.getOperand(0).setReg(FPRDst);
2149 BuildMI(
MBB, std::next(
I.getIterator()), MIMetadata(
I),
2150 TII.get(TargetOpcode::COPY), DstReg)
2154 case AArch64::G_DUP: {
2156 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2160 MRI.
setType(
I.getOperand(0).getReg(),
2162 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2163 I.getOperand(1).setReg(NewSrc.getReg(0));
2166 case AArch64::G_INSERT_VECTOR_ELT: {
2167 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2168 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2172 MRI.
setType(
I.getOperand(1).getReg(),
2174 MRI.
setType(
I.getOperand(0).getReg(),
2176 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2177 I.getOperand(2).setReg(NewSrc.getReg(0));
2181 Register EltReg =
I.getOperand(2).getReg();
2182 LLT EltTy = MRI.
getType(EltReg);
2188 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2189 I.getOperand(2).setReg(NewElt.getReg(0));
2194 case TargetOpcode::G_UITOFP:
2195 case TargetOpcode::G_SITOFP: {
2200 Register SrcReg =
I.getOperand(1).getReg();
2201 LLT SrcTy = MRI.
getType(SrcReg);
2202 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2211 I.getOperand(1).setReg(
Copy.getReg(0));
2213 getRegClassForTypeOnBank(
2214 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2216 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2217 I.setDesc(
TII.get(AArch64::G_SITOF));
2219 I.setDesc(
TII.get(AArch64::G_UITOF));
2237bool AArch64InstructionSelector::convertPtrAddToAdd(
2238 MachineInstr &
I, MachineRegisterInfo &MRI) {
2239 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2240 Register DstReg =
I.getOperand(0).getReg();
2241 Register AddOp1Reg =
I.getOperand(1).getReg();
2242 const LLT PtrTy = MRI.
getType(DstReg);
2246 const LLT CastPtrTy = PtrTy.
isVector()
2258 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2259 MRI.
setType(DstReg, CastPtrTy);
2260 I.getOperand(1).setReg(PtrToInt.getReg(0));
2261 if (!select(*PtrToInt)) {
2262 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2271 I.getOperand(2).setReg(NegatedReg);
2272 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2276bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2277 MachineRegisterInfo &MRI) {
2281 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2282 const auto &MO =
I.getOperand(2);
2287 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2291 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2292 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2294 if (!Imm1Fn || !Imm2Fn)
2298 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2299 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2301 for (
auto &RenderFn : *Imm1Fn)
2303 for (
auto &RenderFn : *Imm2Fn)
2306 I.eraseFromParent();
2311bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2312 MachineInstr &
I, MachineRegisterInfo &MRI) {
2313 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2331 LLT DefDstTy = MRI.
getType(DefDstReg);
2332 Register StoreSrcReg =
I.getOperand(0).getReg();
2333 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2349 I.getOperand(0).setReg(DefDstReg);
2353bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2354 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2355 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2361 switch (
I.getOpcode()) {
2362 case AArch64::G_DUP: {
2365 Register Src =
I.getOperand(1).getReg();
2367 Src, MRI,
true,
true);
2371 Register Dst =
I.getOperand(0).getReg();
2377 if (!emitConstantVector(Dst, CV, MIB, MRI))
2379 I.eraseFromParent();
2382 case TargetOpcode::G_SEXT:
2385 if (selectUSMovFromExtend(
I, MRI))
2388 case TargetOpcode::G_BR:
2390 case TargetOpcode::G_SHL:
2391 return earlySelectSHL(
I, MRI);
2392 case TargetOpcode::G_CONSTANT: {
2393 bool IsZero =
false;
2394 if (
I.getOperand(1).isCImm())
2395 IsZero =
I.getOperand(1).getCImm()->isZero();
2396 else if (
I.getOperand(1).isImm())
2397 IsZero =
I.getOperand(1).getImm() == 0;
2402 Register DefReg =
I.getOperand(0).getReg();
2405 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2408 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2413 I.setDesc(
TII.get(TargetOpcode::COPY));
2417 case TargetOpcode::G_ADD: {
2426 Register AddDst =
I.getOperand(0).getReg();
2427 Register AddLHS =
I.getOperand(1).getReg();
2428 Register AddRHS =
I.getOperand(2).getReg();
2438 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2459 MachineInstr *
Cmp = MatchCmp(AddRHS);
2463 Cmp = MatchCmp(AddRHS);
2467 auto &PredOp =
Cmp->getOperand(1);
2469 emitIntegerCompare(
Cmp->getOperand(2),
2470 Cmp->getOperand(3), PredOp, MIB);
2474 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2475 I.eraseFromParent();
2478 case TargetOpcode::G_OR: {
2482 Register Dst =
I.getOperand(0).getReg();
2502 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2505 int64_t Immr =
Size - ShiftImm;
2506 int64_t Imms =
Size - ShiftImm - 1;
2507 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2508 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2509 I.eraseFromParent();
2512 case TargetOpcode::G_FENCE: {
2513 if (
I.getOperand(1).getImm() == 0)
2517 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2518 I.eraseFromParent();
2526bool AArch64InstructionSelector::select(MachineInstr &
I) {
2527 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2528 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2534 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2535 if (Subtarget->requiresStrictAlign()) {
2537 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2543 unsigned Opcode =
I.getOpcode();
2545 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2548 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2553 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2554 const Register DefReg =
I.getOperand(0).getReg();
2555 const LLT DefTy = MRI.
getType(DefReg);
2568 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2575 I.setDesc(
TII.get(TargetOpcode::PHI));
2583 if (
I.isDebugInstr())
2590 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2592 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2599 if (preISelLower(
I)) {
2600 Opcode =
I.getOpcode();
2611 if (selectImpl(
I, *CoverageInfo))
2615 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2618 case TargetOpcode::G_SBFX:
2619 case TargetOpcode::G_UBFX: {
2620 static const unsigned OpcTable[2][2] = {
2621 {AArch64::UBFMWri, AArch64::UBFMXri},
2622 {AArch64::SBFMWri, AArch64::SBFMXri}};
2623 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2625 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2628 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2631 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2632 auto LSB = Cst1->Value.getZExtValue();
2633 auto Width = Cst2->Value.getZExtValue();
2637 .
addImm(LSB + Width - 1);
2638 I.eraseFromParent();
2642 case TargetOpcode::G_BRCOND:
2643 return selectCompareBranch(
I, MF, MRI);
2645 case TargetOpcode::G_BRINDIRECT: {
2647 if (std::optional<uint16_t> BADisc =
2649 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2653 I.eraseFromParent();
2657 I.setDesc(
TII.get(AArch64::BR));
2662 case TargetOpcode::G_BRJT:
2663 return selectBrJT(
I, MRI);
2665 case AArch64::G_ADD_LOW: {
2670 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2671 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2672 I.setDesc(
TII.get(AArch64::ADDXri));
2678 "Expected small code model");
2680 auto Op2 =
I.getOperand(2);
2681 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2682 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2683 Op1.getTargetFlags())
2685 Op2.getTargetFlags());
2686 I.eraseFromParent();
2691 case TargetOpcode::G_FCONSTANT: {
2692 const Register DefReg =
I.getOperand(0).getReg();
2693 const LLT DefTy = MRI.
getType(DefReg);
2704 bool OptForSize = shouldOptForSize(&MF);
2708 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2715 auto *FPImm =
I.getOperand(1).getFPImm();
2718 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2721 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2722 I.eraseFromParent();
2727 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2730 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2731 MachineOperand &RegOp =
I.getOperand(0);
2737 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2741 MachineOperand &ImmOp =
I.getOperand(1);
2745 const unsigned MovOpc =
2746 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2747 I.setDesc(
TII.get(MovOpc));
2751 case TargetOpcode::G_EXTRACT: {
2752 Register DstReg =
I.getOperand(0).getReg();
2753 Register SrcReg =
I.getOperand(1).getReg();
2754 LLT SrcTy = MRI.
getType(SrcReg);
2755 LLT DstTy = MRI.
getType(DstReg);
2767 unsigned Offset =
I.getOperand(2).getImm();
2772 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2773 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2776 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2778 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2780 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2782 AArch64::GPR64RegClass, NewI->getOperand(0));
2783 I.eraseFromParent();
2789 unsigned LaneIdx =
Offset / 64;
2790 MachineInstr *Extract = emitExtractVectorElt(
2791 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2794 I.eraseFromParent();
2798 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2799 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2804 "unexpected G_EXTRACT types");
2811 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2812 .addReg(DstReg, {}, AArch64::sub_32);
2814 AArch64::GPR32RegClass, MRI);
2815 I.getOperand(0).setReg(DstReg);
2821 case TargetOpcode::G_INSERT: {
2822 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2823 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2830 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2831 unsigned LSB =
I.getOperand(3).getImm();
2833 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2834 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2838 "unexpected G_INSERT types");
2845 TII.get(AArch64::SUBREG_TO_REG))
2847 .
addUse(
I.getOperand(2).getReg())
2848 .
addImm(AArch64::sub_32);
2850 AArch64::GPR32RegClass, MRI);
2851 I.getOperand(2).setReg(SrcReg);
2856 case TargetOpcode::G_FRAME_INDEX: {
2863 I.setDesc(
TII.get(AArch64::ADDXri));
2873 case TargetOpcode::G_GLOBAL_VALUE: {
2874 const GlobalValue *GV =
nullptr;
2876 if (
I.getOperand(1).isSymbol()) {
2877 OpFlags =
I.getOperand(1).getTargetFlags();
2886 return selectTLSGlobalValue(
I, MRI);
2892 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2893 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2894 I.getOperand(1).setTargetFlags(OpFlags);
2895 I.addImplicitDefUseOperands(MF);
2899 materializeLargeCMVal(
I, GV, OpFlags);
2900 I.eraseFromParent();
2903 I.setDesc(
TII.get(AArch64::ADR));
2904 I.getOperand(1).setTargetFlags(OpFlags);
2906 I.setDesc(
TII.get(AArch64::MOVaddr));
2908 MachineInstrBuilder MIB(MF,
I);
2909 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2916 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2917 return selectPtrAuthGlobalValue(
I, MRI);
2919 case TargetOpcode::G_ZEXTLOAD:
2920 case TargetOpcode::G_LOAD:
2921 case TargetOpcode::G_STORE: {
2923 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2938 assert(MemSizeInBytes <= 8 &&
2939 "128-bit atomics should already be custom-legalized");
2942 static constexpr unsigned LDAPROpcodes[] = {
2943 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2944 static constexpr unsigned LDAROpcodes[] = {
2945 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2946 ArrayRef<unsigned> Opcodes =
2947 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2950 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2952 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2953 AArch64::STLRW, AArch64::STLRX};
2958 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2959 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2960 I.getOperand(0).setReg(NewVal);
2962 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2970 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2973 "Load/Store pointer operand isn't a GPR");
2975 "Load/Store pointer operand isn't a pointer");
2980 LLT ValTy = MRI.
getType(ValReg);
2985 RB.
getID() == AArch64::FPRRegBankID) {
2988 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2994 .addReg(ValReg, {}, SubReg)
3001 if (RB.
getID() == AArch64::FPRRegBankID) {
3004 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3014 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3017 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3026 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3028 const unsigned NewOpc =
3030 if (NewOpc ==
I.getOpcode())
3034 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3037 I.setDesc(
TII.get(NewOpc));
3043 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3044 Register CurValReg =
I.getOperand(0).getReg();
3045 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3046 NewInst.cloneMemRefs(
I);
3047 for (
auto &Fn : *AddrModeFns)
3049 I.eraseFromParent();
3053 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3058 if (Opcode == TargetOpcode::G_STORE) {
3060 LoadStore->getOperand(0).getReg(), MRI);
3061 if (CVal && CVal->Value == 0) {
3063 case AArch64::STRWui:
3064 case AArch64::STRHHui:
3065 case AArch64::STRBBui:
3066 LoadStore->getOperand(0).setReg(AArch64::WZR);
3068 case AArch64::STRXui:
3069 LoadStore->getOperand(0).setReg(AArch64::XZR);
3075 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3076 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3088 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3090 .
addImm(AArch64::sub_32);
3099 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3100 case TargetOpcode::G_INDEXED_SEXTLOAD:
3101 return selectIndexedExtLoad(
I, MRI);
3102 case TargetOpcode::G_INDEXED_LOAD:
3103 return selectIndexedLoad(
I, MRI);
3104 case TargetOpcode::G_INDEXED_STORE:
3107 case TargetOpcode::G_LSHR:
3108 case TargetOpcode::G_ASHR:
3110 return selectVectorAshrLshr(
I, MRI);
3112 case TargetOpcode::G_SHL: {
3113 if (Opcode == TargetOpcode::G_SHL &&
3115 return selectVectorSHL(
I, MRI);
3122 Register SrcReg =
I.getOperand(1).getReg();
3123 Register ShiftReg =
I.getOperand(2).getReg();
3124 const LLT ShiftTy = MRI.
getType(ShiftReg);
3125 const LLT SrcTy = MRI.
getType(SrcReg);
3130 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3131 .addReg(ShiftReg, {}, AArch64::sub_32);
3133 I.getOperand(2).setReg(Trunc.getReg(0));
3138 const Register DefReg =
I.getOperand(0).getReg();
3142 if (NewOpc ==
I.getOpcode())
3145 I.setDesc(
TII.get(NewOpc));
3153 case TargetOpcode::G_PTR_ADD: {
3154 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3155 I.eraseFromParent();
3159 case TargetOpcode::G_SADDE:
3160 case TargetOpcode::G_UADDE:
3161 case TargetOpcode::G_SSUBE:
3162 case TargetOpcode::G_USUBE:
3163 case TargetOpcode::G_SADDO:
3164 case TargetOpcode::G_UADDO:
3165 case TargetOpcode::G_SSUBO:
3166 case TargetOpcode::G_USUBO:
3167 return selectOverflowOp(
I, MRI);
3169 case TargetOpcode::G_PTRMASK: {
3170 Register MaskReg =
I.getOperand(2).getReg();
3177 I.setDesc(
TII.get(AArch64::ANDXri));
3178 I.getOperand(2).ChangeToImmediate(
3184 case TargetOpcode::G_PTRTOINT:
3185 case TargetOpcode::G_TRUNC: {
3186 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3187 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3189 const Register DstReg =
I.getOperand(0).getReg();
3190 const Register SrcReg =
I.getOperand(1).getReg();
3192 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3193 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3197 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3201 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3212 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3216 if (DstRC == SrcRC) {
3218 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3222 }
else if (DstRC == &AArch64::GPR32RegClass &&
3223 SrcRC == &AArch64::GPR64RegClass) {
3224 I.getOperand(1).setSubReg(AArch64::sub_32);
3227 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3231 I.setDesc(
TII.get(TargetOpcode::COPY));
3233 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3236 I.setDesc(
TII.get(AArch64::XTNv4i16));
3242 MachineInstr *Extract = emitExtractVectorElt(
3246 I.eraseFromParent();
3251 if (Opcode == TargetOpcode::G_PTRTOINT) {
3252 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3253 I.setDesc(
TII.get(TargetOpcode::COPY));
3261 case TargetOpcode::G_ANYEXT: {
3262 if (selectUSMovFromExtend(
I, MRI))
3265 const Register DstReg =
I.getOperand(0).getReg();
3266 const Register SrcReg =
I.getOperand(1).getReg();
3268 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3269 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3271 <<
", expected: GPR\n");
3275 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3276 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3278 <<
", expected: GPR\n");
3285 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3289 if (DstSize != 64 && DstSize > 32) {
3291 <<
", expected: 32 or 64\n");
3301 .
addImm(AArch64::sub_32);
3302 I.getOperand(1).setReg(ExtSrc);
3307 case TargetOpcode::G_ZEXT:
3308 case TargetOpcode::G_SEXT_INREG:
3309 case TargetOpcode::G_SEXT: {
3310 if (selectUSMovFromExtend(
I, MRI))
3313 unsigned Opcode =
I.getOpcode();
3314 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3315 const Register DefReg =
I.getOperand(0).getReg();
3316 Register SrcReg =
I.getOperand(1).getReg();
3317 const LLT DstTy = MRI.
getType(DefReg);
3318 const LLT SrcTy = MRI.
getType(SrcReg);
3324 if (Opcode == TargetOpcode::G_SEXT_INREG)
3325 SrcSize =
I.getOperand(2).getImm();
3331 AArch64::GPRRegBankID &&
3332 "Unexpected ext regbank");
3343 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3346 if (LoadMI && IsGPR) {
3347 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3348 unsigned BytesLoaded = MemOp->getSize().getValue();
3355 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3358 const Register ZReg = AArch64::WZR;
3359 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3362 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3363 .addUse(SubregToRegSrc)
3364 .
addImm(AArch64::sub_32);
3368 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3378 I.eraseFromParent();
3383 if (DstSize == 64) {
3384 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3392 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3393 {&AArch64::GPR64RegClass}, {})
3399 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3403 }
else if (DstSize <= 32) {
3404 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3413 I.eraseFromParent();
3417 case TargetOpcode::G_FREEZE:
3420 case TargetOpcode::G_INTTOPTR:
3425 case TargetOpcode::G_BITCAST:
3433 case TargetOpcode::G_SELECT: {
3435 const Register CondReg = Sel.getCondReg();
3437 const Register FReg = Sel.getFalseReg();
3439 if (tryOptSelect(Sel))
3445 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3450 Sel.eraseFromParent();
3453 case TargetOpcode::G_ICMP: {
3463 auto &PredOp =
I.getOperand(1);
3464 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3468 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3469 AArch64::WZR, InvCC, MIB);
3470 I.eraseFromParent();
3474 case TargetOpcode::G_FCMP: {
3477 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3479 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3481 I.eraseFromParent();
3484 case TargetOpcode::G_VASTART:
3486 : selectVaStartAAPCS(
I, MF, MRI);
3487 case TargetOpcode::G_INTRINSIC:
3488 return selectIntrinsic(
I, MRI);
3489 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3490 return selectIntrinsicWithSideEffects(
I, MRI);
3491 case TargetOpcode::G_IMPLICIT_DEF: {
3492 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3493 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3494 const Register DstReg =
I.getOperand(0).getReg();
3495 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3500 case TargetOpcode::G_BLOCK_ADDR: {
3501 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3502 if (std::optional<uint16_t> BADisc =
3504 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3505 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3514 AArch64::GPR64RegClass, MRI);
3515 I.eraseFromParent();
3519 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3520 I.eraseFromParent();
3523 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3524 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3525 I.getOperand(0).getReg())
3529 I.getOperand(1).getBlockAddress(), 0,
3531 I.eraseFromParent();
3536 case AArch64::G_DUP: {
3543 AArch64::GPRRegBankID)
3545 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3547 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3549 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3551 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3553 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3559 case TargetOpcode::G_BUILD_VECTOR:
3560 return selectBuildVector(
I, MRI);
3561 case TargetOpcode::G_MERGE_VALUES:
3563 case TargetOpcode::G_UNMERGE_VALUES:
3565 case TargetOpcode::G_SHUFFLE_VECTOR:
3566 return selectShuffleVector(
I, MRI);
3567 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3568 return selectExtractElt(
I, MRI);
3569 case TargetOpcode::G_CONCAT_VECTORS:
3570 return selectConcatVectors(
I, MRI);
3571 case TargetOpcode::G_JUMP_TABLE:
3572 return selectJumpTable(
I, MRI);
3573 case TargetOpcode::G_MEMCPY:
3574 case TargetOpcode::G_MEMCPY_INLINE:
3575 case TargetOpcode::G_MEMMOVE:
3576 case TargetOpcode::G_MEMSET:
3577 case TargetOpcode::G_MEMSET_INLINE:
3578 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3579 return selectMOPS(
I, MRI);
3585bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3586 MachineIRBuilderState OldMIBState = MIB.
getState();
3592bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3593 MachineRegisterInfo &MRI) {
3596 case TargetOpcode::G_MEMCPY:
3597 case TargetOpcode::G_MEMCPY_INLINE:
3598 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3600 case TargetOpcode::G_MEMMOVE:
3601 Mopcode = AArch64::MOPSMemoryMovePseudo;
3603 case TargetOpcode::G_MEMSET:
3604 case TargetOpcode::G_MEMSET_INLINE:
3606 Mopcode = AArch64::MOPSMemorySetPseudo;
3619 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3620 const auto &SrcValRegClass =
3621 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3639 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3640 {DstPtrCopy, SizeCopy, SrcValCopy});
3643 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3644 {DstPtrCopy, SrcValCopy, SizeCopy});
3651bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3652 MachineRegisterInfo &MRI) {
3653 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3654 Register JTAddr =
I.getOperand(0).getReg();
3655 unsigned JTI =
I.getOperand(1).getIndex();
3658 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3670 "jump table hardening only supported on MachO/ELF");
3678 I.eraseFromParent();
3685 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3686 {TargetReg, ScratchReg}, {JTAddr,
Index})
3687 .addJumpTableIndex(JTI);
3689 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3690 {
static_cast<int64_t
>(JTI)});
3692 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3693 I.eraseFromParent();
3698bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3699 MachineRegisterInfo &MRI) {
3700 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3701 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3703 Register DstReg =
I.getOperand(0).getReg();
3704 unsigned JTI =
I.getOperand(1).getIndex();
3707 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3710 I.eraseFromParent();
3715bool AArch64InstructionSelector::selectTLSGlobalValue(
3716 MachineInstr &
I, MachineRegisterInfo &MRI) {
3722 const auto &GlobalOp =
I.getOperand(1);
3723 assert(GlobalOp.getOffset() == 0 &&
3724 "Shouldn't have an offset on TLS globals!");
3725 const GlobalValue &GV = *GlobalOp.getGlobal();
3728 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3731 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3732 {LoadGOT.getReg(0)})
3743 assert(Opcode == AArch64::BLR);
3744 Opcode = AArch64::BLRAAZ;
3748 .addUse(AArch64::X0, RegState::Implicit)
3749 .
addDef(AArch64::X0, RegState::Implicit)
3755 I.eraseFromParent();
3759MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3761 MachineIRBuilder &MIRBuilder)
const {
3762 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3764 auto BuildFn = [&](
unsigned SubregIndex) {
3768 .addImm(SubregIndex);
3776 return BuildFn(AArch64::bsub);
3778 return BuildFn(AArch64::hsub);
3780 return BuildFn(AArch64::ssub);
3782 return BuildFn(AArch64::dsub);
3789AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3790 MachineIRBuilder &MIB,
3791 MachineRegisterInfo &MRI)
const {
3792 LLT DstTy = MRI.
getType(DstReg);
3794 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3795 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3799 unsigned SubReg = 0;
3802 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3808 .addReg(SrcReg, {}, SubReg);
3813bool AArch64InstructionSelector::selectMergeValues(
3814 MachineInstr &
I, MachineRegisterInfo &MRI) {
3815 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3816 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3817 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3819 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3821 if (
I.getNumOperands() != 3)
3828 Register DstReg =
I.getOperand(0).getReg();
3829 Register Src1Reg =
I.getOperand(1).getReg();
3830 Register Src2Reg =
I.getOperand(2).getReg();
3831 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3832 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3836 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3837 Src2Reg, 1, RB, MIB);
3842 I.eraseFromParent();
3846 if (RB.
getID() != AArch64::GPRRegBankID)
3852 auto *DstRC = &AArch64::GPR64RegClass;
3854 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3855 TII.get(TargetOpcode::SUBREG_TO_REG))
3857 .
addUse(
I.getOperand(1).getReg())
3858 .
addImm(AArch64::sub_32);
3861 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3862 TII.get(TargetOpcode::SUBREG_TO_REG))
3864 .
addUse(
I.getOperand(2).getReg())
3865 .
addImm(AArch64::sub_32);
3867 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3868 .
addDef(
I.getOperand(0).getReg())
3876 I.eraseFromParent();
3881 const unsigned EltSize) {
3886 CopyOpc = AArch64::DUPi8;
3887 ExtractSubReg = AArch64::bsub;
3890 CopyOpc = AArch64::DUPi16;
3891 ExtractSubReg = AArch64::hsub;
3894 CopyOpc = AArch64::DUPi32;
3895 ExtractSubReg = AArch64::ssub;
3898 CopyOpc = AArch64::DUPi64;
3899 ExtractSubReg = AArch64::dsub;
3903 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3909MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3910 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3911 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3912 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3913 unsigned CopyOpc = 0;
3914 unsigned ExtractSubReg = 0;
3917 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3922 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3924 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3928 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3929 const LLT &VecTy = MRI.
getType(VecReg);
3931 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3933 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3943 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3944 .addReg(VecReg, {}, ExtractSubReg);
3953 MachineInstr *ScalarToVector = emitScalarToVector(
3954 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3955 if (!ScalarToVector)
3960 MachineInstr *LaneCopyMI =
3961 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3969bool AArch64InstructionSelector::selectExtractElt(
3970 MachineInstr &
I, MachineRegisterInfo &MRI) {
3971 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3972 "unexpected opcode!");
3973 Register DstReg =
I.getOperand(0).getReg();
3974 const LLT NarrowTy = MRI.
getType(DstReg);
3975 const Register SrcReg =
I.getOperand(1).getReg();
3976 const LLT WideTy = MRI.
getType(SrcReg);
3978 "source register size too small!");
3979 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
3982 MachineOperand &LaneIdxOp =
I.getOperand(2);
3983 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
3989 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
3991 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3992 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3996 Opcode = AArch64::UMOVvi8;
3999 Opcode = AArch64::UMOVvi16;
4002 Opcode = AArch64::UMOVvi32;
4009 MachineInstr *ScalarToVector = emitScalarToVector(
4010 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4011 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4015 I.setDesc(
TII.get(Opcode));
4016 I.getOperand(2).ChangeToImmediate(LaneIdx);
4021 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4026 I.eraseFromParent();
4030bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4031 MachineInstr &
I, MachineRegisterInfo &MRI) {
4032 unsigned NumElts =
I.getNumOperands() - 1;
4033 Register SrcReg =
I.getOperand(NumElts).getReg();
4034 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4035 const LLT SrcTy = MRI.
getType(SrcReg);
4037 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4039 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4045 const RegisterBank &DstRB =
4047 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4048 Register Dst =
I.getOperand(OpIdx).getReg();
4049 MachineInstr *Extract =
4050 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4054 I.eraseFromParent();
4058bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4059 MachineRegisterInfo &MRI) {
4060 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4061 "unexpected opcode");
4065 unsigned NumElts =
I.getNumOperands() - 1;
4066 Register SrcReg =
I.getOperand(NumElts).getReg();
4067 Register LoReg =
I.getOperand(0).getReg();
4068 Register HiReg =
I.getOperand(1).getReg();
4069 const LLT NarrowTy = MRI.
getType(LoReg);
4070 const LLT WideTy = MRI.
getType(SrcReg);
4071 const RegisterBank &LoRB = *RBI.
getRegBank(LoReg, MRI,
TRI);
4072 const RegisterBank &HiRB = *RBI.
getRegBank(HiReg, MRI,
TRI);
4073 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
4077 LoRB.
getID() == AArch64::GPRRegBankID &&
4078 HiRB.
getID() == AArch64::GPRRegBankID &&
4079 SrcRB.
getID() == AArch64::FPRRegBankID) {
4080 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4081 TII.get(AArch64::UMOVvi64), LoReg)
4084 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4085 TII.get(AArch64::UMOVvi64), HiReg)
4090 I.eraseFromParent();
4095 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4096 HiRB.
getID() != AArch64::FPRRegBankID) {
4097 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4098 "currently unsupported.\n");
4103 "source register size too small!");
4106 return selectSplitVectorUnmerge(
I, MRI);
4110 unsigned CopyOpc = 0;
4111 unsigned ExtractSubReg = 0;
4122 unsigned NumInsertRegs = NumElts - 1;
4128 InsertRegs.
assign(NumInsertRegs, SrcReg);
4137 unsigned SubReg = 0;
4140 assert(Found &&
"expected to find last operand's subeg idx");
4141 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4143 MachineInstr &ImpDefMI =
4144 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4149 MachineInstr &InsMI =
4151 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4168 Register CopyTo =
I.getOperand(0).getReg();
4169 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4170 .addReg(InsertRegs[0], {}, ExtractSubReg);
4174 unsigned LaneIdx = 1;
4175 for (
Register InsReg : InsertRegs) {
4176 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4177 MachineInstr &CopyInst =
4196 I.eraseFromParent();
4200bool AArch64InstructionSelector::selectConcatVectors(
4201 MachineInstr &
I, MachineRegisterInfo &MRI) {
4202 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4203 "Unexpected opcode");
4204 Register Dst =
I.getOperand(0).getReg();
4205 Register Op1 =
I.getOperand(1).getReg();
4206 Register Op2 =
I.getOperand(2).getReg();
4207 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4210 I.eraseFromParent();
4215AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4224MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4225 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4232 RC = &AArch64::FPR128RegClass;
4233 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4236 RC = &AArch64::FPR64RegClass;
4237 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4240 RC = &AArch64::FPR32RegClass;
4241 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4244 RC = &AArch64::FPR16RegClass;
4245 Opc = AArch64::LDRHui;
4248 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4253 MachineInstr *LoadMI =
nullptr;
4254 auto &MF = MIRBuilder.
getMF();
4255 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4256 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4258 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4261 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4265 .addConstantPoolIndex(
4281static std::pair<unsigned, unsigned>
4283 unsigned Opc, SubregIdx;
4284 if (RB.
getID() == AArch64::GPRRegBankID) {
4286 Opc = AArch64::INSvi8gpr;
4287 SubregIdx = AArch64::bsub;
4288 }
else if (EltSize == 16) {
4289 Opc = AArch64::INSvi16gpr;
4290 SubregIdx = AArch64::ssub;
4291 }
else if (EltSize == 32) {
4292 Opc = AArch64::INSvi32gpr;
4293 SubregIdx = AArch64::ssub;
4294 }
else if (EltSize == 64) {
4295 Opc = AArch64::INSvi64gpr;
4296 SubregIdx = AArch64::dsub;
4302 Opc = AArch64::INSvi8lane;
4303 SubregIdx = AArch64::bsub;
4304 }
else if (EltSize == 16) {
4305 Opc = AArch64::INSvi16lane;
4306 SubregIdx = AArch64::hsub;
4307 }
else if (EltSize == 32) {
4308 Opc = AArch64::INSvi32lane;
4309 SubregIdx = AArch64::ssub;
4310 }
else if (EltSize == 64) {
4311 Opc = AArch64::INSvi64lane;
4312 SubregIdx = AArch64::dsub;
4317 return std::make_pair(
Opc, SubregIdx);
4320MachineInstr *AArch64InstructionSelector::emitInstr(
4321 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4322 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4323 const ComplexRendererFns &RenderFns)
const {
4324 assert(Opcode &&
"Expected an opcode?");
4326 "Function should only be used to produce selected instructions!");
4327 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4329 for (
auto &Fn : *RenderFns)
4335MachineInstr *AArch64InstructionSelector::emitAddSub(
4336 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4338 MachineIRBuilder &MIRBuilder)
const {
4340 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4344 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4345 bool Is32Bit =
Size == 32;
4348 if (
auto Fns = selectArithImmed(
RHS))
4349 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4353 if (
auto Fns = selectNegArithImmed(
RHS))
4354 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4358 if (
auto Fns = selectArithExtendedRegister(
RHS))
4359 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4363 if (
auto Fns = selectShiftedRegister(
RHS))
4364 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4366 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4371AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4372 MachineOperand &
RHS,
4373 MachineIRBuilder &MIRBuilder)
const {
4374 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4375 {{AArch64::ADDXri, AArch64::ADDWri},
4376 {AArch64::ADDXrs, AArch64::ADDWrs},
4377 {AArch64::ADDXrr, AArch64::ADDWrr},
4378 {AArch64::SUBXri, AArch64::SUBWri},
4379 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4380 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4384AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4385 MachineOperand &
RHS,
4386 MachineIRBuilder &MIRBuilder)
const {
4387 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4388 {{AArch64::ADDSXri, AArch64::ADDSWri},
4389 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4390 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4391 {AArch64::SUBSXri, AArch64::SUBSWri},
4392 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4393 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4397AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4398 MachineOperand &
RHS,
4399 MachineIRBuilder &MIRBuilder)
const {
4400 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4401 {{AArch64::SUBSXri, AArch64::SUBSWri},
4402 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4403 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4404 {AArch64::ADDSXri, AArch64::ADDSWri},
4405 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4406 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4410AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4411 MachineOperand &
RHS,
4412 MachineIRBuilder &MIRBuilder)
const {
4413 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4414 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4416 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4417 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4421AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4422 MachineOperand &
RHS,
4423 MachineIRBuilder &MIRBuilder)
const {
4424 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4425 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4427 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4428 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4432AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4433 MachineIRBuilder &MIRBuilder)
const {
4436 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4441AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4442 MachineIRBuilder &MIRBuilder)
const {
4445 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4450AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4451 MachineIRBuilder &MIRBuilder)
const {
4452 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4456 bool Is32Bit = (
RegSize == 32);
4457 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4458 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4459 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4463 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4466 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4473 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4474 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4475 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4478MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4479 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4480 MachineIRBuilder &MIRBuilder)
const {
4481 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4488 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4490 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4492 return emitCMP(
LHS,
RHS, MIRBuilder);
4495MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4497 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4501 "Expected a 32-bit scalar register?");
4503 const Register ZReg = AArch64::WZR;
4508 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4514 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4515 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4516 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4521MachineInstr *AArch64InstructionSelector::emitFPCompare(
4523 std::optional<CmpInst::Predicate> Pred)
const {
4524 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4529 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4539 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4542 ShouldUseImm =
true;
4546 unsigned CmpOpcTbl[2][3] = {
4547 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4548 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4550 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4562MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4564 MachineIRBuilder &MIRBuilder)
const {
4571 const LLT Op1Ty = MRI.
getType(Op1);
4572 const LLT Op2Ty = MRI.
getType(Op2);
4574 if (Op1Ty != Op2Ty) {
4575 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4578 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4581 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4592 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4596 MachineInstr *WidenedOp1 =
4597 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4598 MachineInstr *WidenedOp2 =
4599 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4600 if (!WidenedOp1 || !WidenedOp2) {
4601 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4606 unsigned InsertOpc, InsSubRegIdx;
4607 std::tie(InsertOpc, InsSubRegIdx) =
4625 MachineIRBuilder &MIRBuilder)
const {
4626 auto &MRI = *MIRBuilder.
getMRI();
4632 Size =
TRI.getRegSizeInBits(*RC);
4636 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4637 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4638 unsigned Opc = OpcTable[
Size == 64];
4639 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4644MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4646 MachineRegisterInfo *MRI = MIB.
getMRI();
4647 unsigned Opcode =
I.getOpcode();
4651 bool NeedsNegatedCarry =
4652 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4661 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4662 if (SrcMI ==
I.getPrevNode()) {
4664 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4665 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4666 CarrySrcMI->isUnsigned() &&
4667 CarrySrcMI->getCarryOutReg() == CarryReg &&
4668 selectAndRestoreState(*SrcMI))
4675 if (NeedsNegatedCarry) {
4678 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4682 auto Fns = select12BitValueWithLeftShift(1);
4683 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4686bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4687 MachineRegisterInfo &MRI) {
4692 emitCarryIn(
I, CarryInMI->getCarryInReg());
4696 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4697 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4699 Register CarryOutReg = CarryMI.getCarryOutReg();
4708 emitCSINC(CarryOutReg, ZReg, ZReg,
4709 getInvertedCondCode(OpAndCC.second), MIB);
4712 I.eraseFromParent();
4716std::pair<MachineInstr *, AArch64CC::CondCode>
4717AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4718 MachineOperand &
LHS,
4719 MachineOperand &
RHS,
4720 MachineIRBuilder &MIRBuilder)
const {
4724 case TargetOpcode::G_SADDO:
4726 case TargetOpcode::G_UADDO:
4728 case TargetOpcode::G_SSUBO:
4730 case TargetOpcode::G_USUBO:
4732 case TargetOpcode::G_SADDE:
4734 case TargetOpcode::G_UADDE:
4736 case TargetOpcode::G_SSUBE:
4738 case TargetOpcode::G_USUBE:
4759 unsigned Depth = 0) {
4766 MustBeFirst =
false;
4772 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4773 bool IsOR = Opcode == TargetOpcode::G_OR;
4785 if (MustBeFirstL && MustBeFirstR)
4791 if (!CanNegateL && !CanNegateR)
4795 CanNegate = WillNegate && CanNegateL && CanNegateR;
4798 MustBeFirst = !CanNegate;
4800 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4803 MustBeFirst = MustBeFirstL || MustBeFirstR;
4810MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4813 MachineIRBuilder &MIB)
const {
4814 auto &MRI = *MIB.
getMRI();
4817 std::optional<ValueAndVReg>
C;
4821 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4822 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4823 else if (
C->Value.ule(31))
4824 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4826 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4832 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4833 CCmpOpc = AArch64::FCCMPHrr;
4836 CCmpOpc = AArch64::FCCMPSrr;
4839 CCmpOpc = AArch64::FCCMPDrr;
4849 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4850 CCmp.
addImm(
C->Value.getZExtValue());
4851 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4852 CCmp.
addImm(
C->Value.abs().getZExtValue());
4860MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4864 auto &MRI = *MIB.
getMRI();
4882 MachineInstr *ExtraCmp;
4884 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4896 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4897 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4898 Cmp->getOperand(3).getReg(), MIB);
4905 bool IsOR = Opcode == TargetOpcode::G_OR;
4911 assert(ValidL &&
"Valid conjunction/disjunction tree");
4918 assert(ValidR &&
"Valid conjunction/disjunction tree");
4923 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4932 bool NegateAfterAll;
4933 if (Opcode == TargetOpcode::G_OR) {
4936 assert(CanNegateR &&
"at least one side must be negatable");
4937 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4941 NegateAfterR =
true;
4944 NegateR = CanNegateR;
4945 NegateAfterR = !CanNegateR;
4948 NegateAfterAll = !Negate;
4950 assert(Opcode == TargetOpcode::G_AND &&
4951 "Valid conjunction/disjunction tree");
4952 assert(!Negate &&
"Valid conjunction/disjunction tree");
4956 NegateAfterR =
false;
4957 NegateAfterAll =
false;
4962 MachineInstr *CmpR =
4973MachineInstr *AArch64InstructionSelector::emitConjunction(
4975 bool DummyCanNegate;
4976 bool DummyMustBeFirst;
4983bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4984 MachineInstr &CondMI) {
4995bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4996 MachineRegisterInfo &MRI = *MIB.
getMRI();
5015 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5024 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5030 unsigned CondOpc = CondDef->
getOpcode();
5031 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5032 if (tryOptSelectConjunction(
I, *CondDef))
5038 if (CondOpc == TargetOpcode::G_ICMP) {
5067 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5068 I.getOperand(3).getReg(), CondCode, MIB);
5069 I.eraseFromParent();
5073MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5074 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5075 MachineIRBuilder &MIRBuilder)
const {
5077 "Unexpected MachineOperand");
5078 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5101 if (
isCMN(RHSDef,
P, MRI))
5116 if (
isCMN(LHSDef,
P, MRI)) {
5133 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5136 if (!ValAndVReg || ValAndVReg->Value != 0)
5146bool AArch64InstructionSelector::selectShuffleVector(
5147 MachineInstr &
I, MachineRegisterInfo &MRI) {
5148 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5149 Register Src1Reg =
I.getOperand(1).getReg();
5150 Register Src2Reg =
I.getOperand(2).getReg();
5151 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5153 "Expected equal shuffle types during selection");
5162 SmallVector<int> NewMask;
5163 bool FirstUsed =
false;
5164 bool SecondUsed =
false;
5165 for (
int M : Mask) {
5167 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5170 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5175 FirstUsed |=
M < NumElts;
5176 SecondUsed |=
M >= NumElts;
5177 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5186 for (
int &M : NewMask) {
5188 assert(M >= ByteLanes && M < 2 * ByteLanes);
5198 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5199 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5212 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5219 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5223 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5228 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5229 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5231 I.eraseFromParent();
5236 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5239 I.eraseFromParent();
5247 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5250 I.eraseFromParent();
5254MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5256 unsigned LaneIdx,
const RegisterBank &RB,
5257 MachineIRBuilder &MIRBuilder)
const {
5258 MachineInstr *InsElt =
nullptr;
5260 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5269 if (RB.
getID() == AArch64::FPRRegBankID) {
5270 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5273 .
addUse(InsSub->getOperand(0).getReg())
5285bool AArch64InstructionSelector::selectUSMovFromExtend(
5286 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5287 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5288 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5289 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5291 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5292 const Register DefReg =
MI.getOperand(0).getReg();
5293 const LLT DstTy = MRI.
getType(DefReg);
5296 if (DstSize != 32 && DstSize != 64)
5299 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5300 MI.getOperand(1).getReg(), MRI);
5306 const LLT VecTy = MRI.
getType(Src0);
5311 const MachineInstr *ScalarToVector = emitScalarToVector(
5312 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5313 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5319 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5321 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5323 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5325 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5327 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5335 MachineInstr *ExtI =
nullptr;
5336 if (DstSize == 64 && !IsSigned) {
5338 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5339 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5341 .
addImm(AArch64::sub_32);
5344 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5347 MI.eraseFromParent();
5351MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5352 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5354 if (DstSize == 128) {
5355 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5357 Op = AArch64::MOVIv16b_ns;
5359 Op = AArch64::MOVIv8b_ns;
5366 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5373MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5374 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5378 if (DstSize == 128) {
5379 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5381 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5383 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5403MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5404 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5408 if (DstSize == 128) {
5409 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5411 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5413 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5439MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5440 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5443 if (DstSize == 128) {
5444 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5446 Op = AArch64::MOVIv2d_ns;
5448 Op = AArch64::MOVID;
5454 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5461MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5462 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5466 if (DstSize == 128) {
5467 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5469 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5471 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5491MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5492 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5495 bool IsWide =
false;
5496 if (DstSize == 128) {
5497 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5499 Op = AArch64::FMOVv4f32_ns;
5502 Op = AArch64::FMOVv2f32_ns;
5511 Op = AArch64::FMOVv2f64_ns;
5515 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5520bool AArch64InstructionSelector::selectIndexedExtLoad(
5521 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5524 Register WriteBack = ExtLd.getWritebackReg();
5529 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5530 bool IsPre = ExtLd.isPre();
5532 unsigned InsertIntoSubReg = 0;
5538 if ((IsSExt && IsFPR) || Ty.
isVector())
5546 if (MemSizeBits == 8) {
5549 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5551 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5552 NewLdDstTy = IsDst64 ? s64 : s32;
5554 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5555 InsertIntoSubReg = AArch64::bsub;
5558 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5559 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5562 }
else if (MemSizeBits == 16) {
5565 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5567 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5568 NewLdDstTy = IsDst64 ? s64 : s32;
5570 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5571 InsertIntoSubReg = AArch64::hsub;
5574 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5575 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5578 }
else if (MemSizeBits == 32) {
5580 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5583 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5584 InsertIntoSubReg = AArch64::ssub;
5587 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5588 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5600 .addImm(Cst->getSExtValue());
5605 if (InsertIntoSubReg) {
5607 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5608 .addUse(LdMI.getReg(1))
5609 .
addImm(InsertIntoSubReg);
5612 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5619 MI.eraseFromParent();
5624bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5625 MachineRegisterInfo &MRI) {
5628 Register WriteBack = Ld.getWritebackReg();
5632 "Unexpected type for indexed load");
5633 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5636 return selectIndexedExtLoad(
MI, MRI);
5640 static constexpr unsigned GPROpcodes[] = {
5641 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5643 static constexpr unsigned FPROpcodes[] = {
5644 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5647 ? FPROpcodes[
Log2_32(MemSize)]
5648 : GPROpcodes[
Log2_32(MemSize)];
5651 static constexpr unsigned GPROpcodes[] = {
5652 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5654 static constexpr unsigned FPROpcodes[] = {
5655 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5656 AArch64::LDRDpost, AArch64::LDRQpost};
5658 ? FPROpcodes[
Log2_32(MemSize)]
5659 : GPROpcodes[
Log2_32(MemSize)];
5669 MI.eraseFromParent();
5673bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5674 MachineRegisterInfo &MRI) {
5680 "Unexpected type for indexed store");
5682 LocationSize MemSize =
I.getMMO().getSize();
5683 unsigned MemSizeInBytes = MemSize.
getValue();
5685 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5686 "Unexpected indexed store size");
5687 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5691 static constexpr unsigned GPROpcodes[] = {
5692 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5694 static constexpr unsigned FPROpcodes[] = {
5695 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5699 Opc = FPROpcodes[MemSizeLog2];
5701 Opc = GPROpcodes[MemSizeLog2];
5703 static constexpr unsigned GPROpcodes[] = {
5704 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5706 static constexpr unsigned FPROpcodes[] = {
5707 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5708 AArch64::STRDpost, AArch64::STRQpost};
5711 Opc = FPROpcodes[MemSizeLog2];
5713 Opc = GPROpcodes[MemSizeLog2];
5721 Str.cloneMemRefs(
I);
5723 I.eraseFromParent();
5728AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5729 MachineIRBuilder &MIRBuilder,
5730 MachineRegisterInfo &MRI) {
5733 assert((DstSize == 64 || DstSize == 128) &&
5734 "Unexpected vector constant size");
5737 if (DstSize == 128) {
5739 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5744 if (DstSize == 64) {
5747 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5750 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5757 APInt SplatValueAsInt =
5760 : SplatValue->getUniqueInteger();
5763 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5764 MachineInstr *NewOp;
5788 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5792 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5793 unsigned NegOpc) -> MachineInstr * {
5796 APInt NegBits(DstSize, 0);
5797 unsigned NumElts = DstSize / NumBits;
5798 for (
unsigned i = 0; i < NumElts; i++)
5799 NegBits |= Neg << (NumBits * i);
5800 NegBits = DefBits ^ NegBits;
5804 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5806 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5808 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5813 if ((R = TryWithFNeg(DefBits, 32,
5814 DstSize == 64 ? AArch64::FNEGv2f32
5815 : AArch64::FNEGv4f32)) ||
5816 (R = TryWithFNeg(DefBits, 64,
5817 DstSize == 64 ? AArch64::FNEGDr
5818 : AArch64::FNEGv2f64)) ||
5819 (STI.hasFullFP16() &&
5820 (R = TryWithFNeg(DefBits, 16,
5821 DstSize == 64 ? AArch64::FNEGv4f16
5822 : AArch64::FNEGv8f16))))
5828 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5832 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5834 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5838bool AArch64InstructionSelector::tryOptConstantBuildVec(
5839 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5840 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5842 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5848 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5849 Register OpReg =
I.getOperand(Idx).getReg();
5858 std::move(AnyConst->Value)));
5871 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5873 I.eraseFromParent();
5877bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5878 MachineInstr &
I, MachineRegisterInfo &MRI) {
5883 Register Dst =
I.getOperand(0).getReg();
5884 Register EltReg =
I.getOperand(1).getReg();
5885 LLT EltTy = MRI.
getType(EltReg);
5888 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5893 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5901 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5906 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5909 I.eraseFromParent();
5914bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5915 MachineRegisterInfo &MRI) {
5916 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5919 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5920 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5923 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5925 if (tryOptBuildVecToSubregToReg(
I, MRI))
5928 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5930 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5933 MachineInstr *ScalarToVec =
5935 I.getOperand(1).getReg(), MIB);
5944 MachineInstr *PrevMI = ScalarToVec;
5945 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5948 Register OpReg =
I.getOperand(i).getReg();
5951 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5958 if (DstSize < 128) {
5961 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5964 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5969 unsigned SubReg = 0;
5972 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5973 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5979 Register DstReg =
I.getOperand(0).getReg();
5981 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5982 MachineOperand &RegOp =
I.getOperand(1);
6002 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6004 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6013bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6016 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6018 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6019 auto &MRI = *MIB.
getMRI();
6020 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6023 "Destination must be 64 bits or 128 bits?");
6024 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6025 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6030 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6031 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6032 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6033 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6042bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6043 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6044 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6046 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6047 auto &MRI = *MIB.
getMRI();
6048 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6051 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6053 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6054 [](
auto MO) { return MO.getReg(); });
6058 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6073 .
addImm(LaneNo->getZExtValue())
6077 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6078 unsigned SubReg = AArch64::qsub0;
6079 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6080 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6081 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6082 : DstOp(
I.getOperand(Idx).
getReg())},
6084 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6089 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6095void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6098 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6099 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6100 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6103 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6104 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6113bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6114 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6115 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6116 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6120 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6121 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6125 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6135 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6138 .
addImm(LaneNo->getZExtValue())
6145bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6146 MachineInstr &
I, MachineRegisterInfo &MRI) {
6159 case Intrinsic::aarch64_ldxp:
6160 case Intrinsic::aarch64_ldaxp: {
6162 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6163 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6169 case Intrinsic::aarch64_neon_ld1x2: {
6170 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6173 Opc = AArch64::LD1Twov8b;
6175 Opc = AArch64::LD1Twov16b;
6177 Opc = AArch64::LD1Twov4h;
6179 Opc = AArch64::LD1Twov8h;
6181 Opc = AArch64::LD1Twov2s;
6183 Opc = AArch64::LD1Twov4s;
6185 Opc = AArch64::LD1Twov2d;
6186 else if (Ty ==
S64 || Ty == P0)
6187 Opc = AArch64::LD1Twov1d;
6190 selectVectorLoadIntrinsic(
Opc, 2,
I);
6193 case Intrinsic::aarch64_neon_ld1x3: {
6194 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6197 Opc = AArch64::LD1Threev8b;
6199 Opc = AArch64::LD1Threev16b;
6201 Opc = AArch64::LD1Threev4h;
6203 Opc = AArch64::LD1Threev8h;
6205 Opc = AArch64::LD1Threev2s;
6207 Opc = AArch64::LD1Threev4s;
6209 Opc = AArch64::LD1Threev2d;
6210 else if (Ty ==
S64 || Ty == P0)
6211 Opc = AArch64::LD1Threev1d;
6214 selectVectorLoadIntrinsic(
Opc, 3,
I);
6217 case Intrinsic::aarch64_neon_ld1x4: {
6218 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6221 Opc = AArch64::LD1Fourv8b;
6223 Opc = AArch64::LD1Fourv16b;
6225 Opc = AArch64::LD1Fourv4h;
6227 Opc = AArch64::LD1Fourv8h;
6229 Opc = AArch64::LD1Fourv2s;
6231 Opc = AArch64::LD1Fourv4s;
6233 Opc = AArch64::LD1Fourv2d;
6234 else if (Ty ==
S64 || Ty == P0)
6235 Opc = AArch64::LD1Fourv1d;
6238 selectVectorLoadIntrinsic(
Opc, 4,
I);
6241 case Intrinsic::aarch64_neon_ld2: {
6242 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6245 Opc = AArch64::LD2Twov8b;
6247 Opc = AArch64::LD2Twov16b;
6249 Opc = AArch64::LD2Twov4h;
6251 Opc = AArch64::LD2Twov8h;
6253 Opc = AArch64::LD2Twov2s;
6255 Opc = AArch64::LD2Twov4s;
6257 Opc = AArch64::LD2Twov2d;
6258 else if (Ty ==
S64 || Ty == P0)
6259 Opc = AArch64::LD1Twov1d;
6262 selectVectorLoadIntrinsic(
Opc, 2,
I);
6265 case Intrinsic::aarch64_neon_ld2lane: {
6266 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6269 Opc = AArch64::LD2i8;
6271 Opc = AArch64::LD2i16;
6273 Opc = AArch64::LD2i32;
6276 Opc = AArch64::LD2i64;
6279 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6283 case Intrinsic::aarch64_neon_ld2r: {
6284 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6287 Opc = AArch64::LD2Rv8b;
6289 Opc = AArch64::LD2Rv16b;
6291 Opc = AArch64::LD2Rv4h;
6293 Opc = AArch64::LD2Rv8h;
6295 Opc = AArch64::LD2Rv2s;
6297 Opc = AArch64::LD2Rv4s;
6299 Opc = AArch64::LD2Rv2d;
6300 else if (Ty ==
S64 || Ty == P0)
6301 Opc = AArch64::LD2Rv1d;
6304 selectVectorLoadIntrinsic(
Opc, 2,
I);
6307 case Intrinsic::aarch64_neon_ld3: {
6308 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6311 Opc = AArch64::LD3Threev8b;
6313 Opc = AArch64::LD3Threev16b;
6315 Opc = AArch64::LD3Threev4h;
6317 Opc = AArch64::LD3Threev8h;
6319 Opc = AArch64::LD3Threev2s;
6321 Opc = AArch64::LD3Threev4s;
6323 Opc = AArch64::LD3Threev2d;
6324 else if (Ty ==
S64 || Ty == P0)
6325 Opc = AArch64::LD1Threev1d;
6328 selectVectorLoadIntrinsic(
Opc, 3,
I);
6331 case Intrinsic::aarch64_neon_ld3lane: {
6332 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6335 Opc = AArch64::LD3i8;
6337 Opc = AArch64::LD3i16;
6339 Opc = AArch64::LD3i32;
6342 Opc = AArch64::LD3i64;
6345 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6349 case Intrinsic::aarch64_neon_ld3r: {
6350 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6353 Opc = AArch64::LD3Rv8b;
6355 Opc = AArch64::LD3Rv16b;
6357 Opc = AArch64::LD3Rv4h;
6359 Opc = AArch64::LD3Rv8h;
6361 Opc = AArch64::LD3Rv2s;
6363 Opc = AArch64::LD3Rv4s;
6365 Opc = AArch64::LD3Rv2d;
6366 else if (Ty ==
S64 || Ty == P0)
6367 Opc = AArch64::LD3Rv1d;
6370 selectVectorLoadIntrinsic(
Opc, 3,
I);
6373 case Intrinsic::aarch64_neon_ld4: {
6374 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6377 Opc = AArch64::LD4Fourv8b;
6379 Opc = AArch64::LD4Fourv16b;
6381 Opc = AArch64::LD4Fourv4h;
6383 Opc = AArch64::LD4Fourv8h;
6385 Opc = AArch64::LD4Fourv2s;
6387 Opc = AArch64::LD4Fourv4s;
6389 Opc = AArch64::LD4Fourv2d;
6390 else if (Ty ==
S64 || Ty == P0)
6391 Opc = AArch64::LD1Fourv1d;
6394 selectVectorLoadIntrinsic(
Opc, 4,
I);
6397 case Intrinsic::aarch64_neon_ld4lane: {
6398 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6401 Opc = AArch64::LD4i8;
6403 Opc = AArch64::LD4i16;
6405 Opc = AArch64::LD4i32;
6408 Opc = AArch64::LD4i64;
6411 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6415 case Intrinsic::aarch64_neon_ld4r: {
6416 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6419 Opc = AArch64::LD4Rv8b;
6421 Opc = AArch64::LD4Rv16b;
6423 Opc = AArch64::LD4Rv4h;
6425 Opc = AArch64::LD4Rv8h;
6427 Opc = AArch64::LD4Rv2s;
6429 Opc = AArch64::LD4Rv4s;
6431 Opc = AArch64::LD4Rv2d;
6432 else if (Ty ==
S64 || Ty == P0)
6433 Opc = AArch64::LD4Rv1d;
6436 selectVectorLoadIntrinsic(
Opc, 4,
I);
6439 case Intrinsic::aarch64_neon_st1x2: {
6440 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6443 Opc = AArch64::ST1Twov8b;
6445 Opc = AArch64::ST1Twov16b;
6447 Opc = AArch64::ST1Twov4h;
6449 Opc = AArch64::ST1Twov8h;
6451 Opc = AArch64::ST1Twov2s;
6453 Opc = AArch64::ST1Twov4s;
6455 Opc = AArch64::ST1Twov2d;
6456 else if (Ty ==
S64 || Ty == P0)
6457 Opc = AArch64::ST1Twov1d;
6460 selectVectorStoreIntrinsic(
I, 2,
Opc);
6463 case Intrinsic::aarch64_neon_st1x3: {
6464 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6467 Opc = AArch64::ST1Threev8b;
6469 Opc = AArch64::ST1Threev16b;
6471 Opc = AArch64::ST1Threev4h;
6473 Opc = AArch64::ST1Threev8h;
6475 Opc = AArch64::ST1Threev2s;
6477 Opc = AArch64::ST1Threev4s;
6479 Opc = AArch64::ST1Threev2d;
6480 else if (Ty ==
S64 || Ty == P0)
6481 Opc = AArch64::ST1Threev1d;
6484 selectVectorStoreIntrinsic(
I, 3,
Opc);
6487 case Intrinsic::aarch64_neon_st1x4: {
6488 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6491 Opc = AArch64::ST1Fourv8b;
6493 Opc = AArch64::ST1Fourv16b;
6495 Opc = AArch64::ST1Fourv4h;
6497 Opc = AArch64::ST1Fourv8h;
6499 Opc = AArch64::ST1Fourv2s;
6501 Opc = AArch64::ST1Fourv4s;
6503 Opc = AArch64::ST1Fourv2d;
6504 else if (Ty ==
S64 || Ty == P0)
6505 Opc = AArch64::ST1Fourv1d;
6508 selectVectorStoreIntrinsic(
I, 4,
Opc);
6511 case Intrinsic::aarch64_neon_st2: {
6512 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6515 Opc = AArch64::ST2Twov8b;
6517 Opc = AArch64::ST2Twov16b;
6519 Opc = AArch64::ST2Twov4h;
6521 Opc = AArch64::ST2Twov8h;
6523 Opc = AArch64::ST2Twov2s;
6525 Opc = AArch64::ST2Twov4s;
6527 Opc = AArch64::ST2Twov2d;
6528 else if (Ty ==
S64 || Ty == P0)
6529 Opc = AArch64::ST1Twov1d;
6532 selectVectorStoreIntrinsic(
I, 2,
Opc);
6535 case Intrinsic::aarch64_neon_st3: {
6536 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6539 Opc = AArch64::ST3Threev8b;
6541 Opc = AArch64::ST3Threev16b;
6543 Opc = AArch64::ST3Threev4h;
6545 Opc = AArch64::ST3Threev8h;
6547 Opc = AArch64::ST3Threev2s;
6549 Opc = AArch64::ST3Threev4s;
6551 Opc = AArch64::ST3Threev2d;
6552 else if (Ty ==
S64 || Ty == P0)
6553 Opc = AArch64::ST1Threev1d;
6556 selectVectorStoreIntrinsic(
I, 3,
Opc);
6559 case Intrinsic::aarch64_neon_st4: {
6560 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6563 Opc = AArch64::ST4Fourv8b;
6565 Opc = AArch64::ST4Fourv16b;
6567 Opc = AArch64::ST4Fourv4h;
6569 Opc = AArch64::ST4Fourv8h;
6571 Opc = AArch64::ST4Fourv2s;
6573 Opc = AArch64::ST4Fourv4s;
6575 Opc = AArch64::ST4Fourv2d;
6576 else if (Ty ==
S64 || Ty == P0)
6577 Opc = AArch64::ST1Fourv1d;
6580 selectVectorStoreIntrinsic(
I, 4,
Opc);
6583 case Intrinsic::aarch64_neon_st2lane: {
6584 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6587 Opc = AArch64::ST2i8;
6589 Opc = AArch64::ST2i16;
6591 Opc = AArch64::ST2i32;
6594 Opc = AArch64::ST2i64;
6597 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6601 case Intrinsic::aarch64_neon_st3lane: {
6602 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6605 Opc = AArch64::ST3i8;
6607 Opc = AArch64::ST3i16;
6609 Opc = AArch64::ST3i32;
6612 Opc = AArch64::ST3i64;
6615 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6619 case Intrinsic::aarch64_neon_st4lane: {
6620 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6623 Opc = AArch64::ST4i8;
6625 Opc = AArch64::ST4i16;
6627 Opc = AArch64::ST4i32;
6630 Opc = AArch64::ST4i64;
6633 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6637 case Intrinsic::aarch64_mops_memset_tag: {
6650 Register DstDef =
I.getOperand(0).getReg();
6652 Register DstUse =
I.getOperand(2).getReg();
6653 Register ValUse =
I.getOperand(3).getReg();
6654 Register SizeUse =
I.getOperand(4).getReg();
6661 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6662 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6667 case Intrinsic::ptrauth_resign_load_relative: {
6668 Register DstReg =
I.getOperand(0).getReg();
6669 Register ValReg =
I.getOperand(2).getReg();
6670 uint64_t AUTKey =
I.getOperand(3).getImm();
6671 Register AUTDisc =
I.getOperand(4).getReg();
6672 uint64_t PACKey =
I.getOperand(5).getImm();
6673 Register PACDisc =
I.getOperand(6).getReg();
6674 int64_t Addend =
I.getOperand(7).getImm();
6677 uint16_t AUTConstDiscC = 0;
6678 std::tie(AUTConstDiscC, AUTAddrDisc) =
6682 uint16_t PACConstDiscC = 0;
6683 std::tie(PACConstDiscC, PACAddrDisc) =
6686 MIB.
buildCopy({AArch64::X16}, {ValReg});
6700 I.eraseFromParent();
6705 I.eraseFromParent();
6709bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6710 MachineRegisterInfo &MRI) {
6716 case Intrinsic::ptrauth_resign: {
6717 Register DstReg =
I.getOperand(0).getReg();
6718 Register ValReg =
I.getOperand(2).getReg();
6719 uint64_t AUTKey =
I.getOperand(3).getImm();
6720 Register AUTDisc =
I.getOperand(4).getReg();
6721 uint64_t PACKey =
I.getOperand(5).getImm();
6722 Register PACDisc =
I.getOperand(6).getReg();
6725 uint16_t AUTConstDiscC = 0;
6726 std::tie(AUTConstDiscC, AUTAddrDisc) =
6730 uint16_t PACConstDiscC = 0;
6731 std::tie(PACConstDiscC, PACAddrDisc) =
6734 MIB.
buildCopy({AArch64::X16}, {ValReg});
6735 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6747 I.eraseFromParent();
6750 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6751 Register DstReg =
I.getOperand(0).getReg();
6752 Register ValReg =
I.getOperand(2).getReg();
6753 uint64_t AUTKey =
I.getOperand(3).getImm();
6754 Register AUTDisc =
I.getOperand(4).getReg();
6755 Register AUTPC =
I.getOperand(5).getReg();
6756 uint64_t PACKey =
I.getOperand(6).getImm();
6757 Register PACDisc =
I.getOperand(7).getReg();
6760 "auth_with_pc_and_resign only supports IA and IB keys");
6762 uint16_t PACConstDiscC = 0;
6764 std::tie(PACConstDiscC, PACAddrDisc) =
6767 if (PACAddrDisc == AArch64::NoRegister)
6768 PACAddrDisc = AArch64::XZR;
6770 MIB.
buildCopy({AArch64::X17}, {ValReg});
6771 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6783 I.eraseFromParent();
6786 case Intrinsic::ptrauth_auth: {
6787 Register DstReg =
I.getOperand(0).getReg();
6788 Register ValReg =
I.getOperand(2).getReg();
6789 uint64_t AUTKey =
I.getOperand(3).getImm();
6790 Register AUTDisc =
I.getOperand(4).getReg();
6793 uint16_t AUTConstDiscC = 0;
6794 std::tie(AUTConstDiscC, AUTAddrDisc) =
6798 MIB.
buildCopy({AArch64::X16}, {ValReg});
6799 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6820 I.eraseFromParent();
6823 case Intrinsic::frameaddress:
6824 case Intrinsic::returnaddress: {
6828 unsigned Depth =
I.getOperand(2).getImm();
6829 Register DstReg =
I.getOperand(0).getReg();
6832 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6833 if (!MFReturnAddr) {
6838 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6841 if (STI.hasPAuth()) {
6842 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6849 I.eraseFromParent();
6858 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6860 FrameAddr = NextFrame;
6863 if (IntrinID == Intrinsic::frameaddress)
6868 if (STI.hasPAuth()) {
6870 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6871 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6880 I.eraseFromParent();
6883 case Intrinsic::aarch64_neon_tbl2:
6884 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6886 case Intrinsic::aarch64_neon_tbl3:
6887 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6890 case Intrinsic::aarch64_neon_tbl4:
6891 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6893 case Intrinsic::aarch64_neon_tbx2:
6894 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6896 case Intrinsic::aarch64_neon_tbx3:
6897 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6899 case Intrinsic::aarch64_neon_tbx4:
6900 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6902 case Intrinsic::swift_async_context_addr:
6903 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6910 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6911 I.eraseFromParent();
6946bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6947 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6948 Register DefReg =
I.getOperand(0).getReg();
6949 Register Addr =
I.getOperand(1).getReg();
6951 Register AddrDisc =
I.getOperand(3).getReg();
6952 uint64_t Disc =
I.getOperand(4).getImm();
6962 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6978 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6990 const GlobalValue *GV;
7001 MachineIRBuilder MIB(
I);
7007 "unsupported non-GOT op flags on ptrauth global reference");
7009 "unsupported non-GOT reference to weak ptrauth global");
7012 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7019 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7020 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7021 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7024 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7029 I.eraseFromParent();
7041 "unsupported non-zero offset in weak ptrauth global reference");
7046 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7047 .addGlobalAddress(GV,
Offset)
7052 I.eraseFromParent();
7056void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7057 MachineRegisterInfo &MRI,
7058 unsigned NumVec,
unsigned Opc1,
7059 unsigned Opc2,
bool isExt) {
7060 Register DstReg =
I.getOperand(0).getReg();
7065 for (
unsigned i = 0; i < NumVec; i++)
7066 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7069 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7070 MachineInstrBuilder
Instr;
7077 I.eraseFromParent();
7080InstructionSelector::ComplexRendererFns
7081AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7083 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7084 return std::nullopt;
7085 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7086 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7089InstructionSelector::ComplexRendererFns
7090AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7092 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7093 return std::nullopt;
7095 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7098InstructionSelector::ComplexRendererFns
7099AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7101 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7102 return std::nullopt;
7103 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7104 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7107InstructionSelector::ComplexRendererFns
7108AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7110 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7111 return std::nullopt;
7113 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7121InstructionSelector::ComplexRendererFns
7122AArch64InstructionSelector::select12BitValueWithLeftShift(
7125 if (Immed >> 12 == 0) {
7127 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7129 Immed = Immed >> 12;
7131 return std::nullopt;
7135 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7136 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7143InstructionSelector::ComplexRendererFns
7144AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7151 if (MaybeImmed == std::nullopt)
7152 return std::nullopt;
7153 return select12BitValueWithLeftShift(*MaybeImmed);
7158InstructionSelector::ComplexRendererFns
7159AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7163 return std::nullopt;
7165 if (MaybeImmed == std::nullopt)
7166 return std::nullopt;
7173 return std::nullopt;
7179 Immed = ~((uint32_t)Immed) + 1;
7181 Immed = ~Immed + 1ULL;
7183 if (Immed & 0xFFFFFFFFFF000000ULL)
7184 return std::nullopt;
7186 Immed &= 0xFFFFFFULL;
7187 return select12BitValueWithLeftShift(Immed);
7204std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7205 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7206 if (
MI.getOpcode() == AArch64::G_SHL) {
7210 MI.getOperand(2).getReg(), MRI)) {
7211 const APInt ShiftVal = ValAndVeg->Value;
7214 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7217 return std::nullopt;
7225bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7226 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7227 bool IsAddrOperand)
const {
7232 MI.getParent()->getParent()->getFunction().hasOptSize())
7235 if (IsAddrOperand) {
7237 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7241 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7242 MachineInstr *OffsetInst =
7248 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7259 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7262InstructionSelector::ComplexRendererFns
7263AArch64InstructionSelector::selectExtendedSHL(
7264 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7265 unsigned SizeInBytes,
bool WantsExt)
const {
7266 assert(
Base.isReg() &&
"Expected base to be a register operand");
7267 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7272 unsigned OffsetOpc = OffsetInst->
getOpcode();
7273 bool LookedThroughZExt =
false;
7274 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7276 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7277 return std::nullopt;
7281 LookedThroughZExt =
true;
7283 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7284 return std::nullopt;
7287 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7288 if (LegalShiftVal == 0)
7289 return std::nullopt;
7290 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7291 return std::nullopt;
7302 if (OffsetOpc == TargetOpcode::G_SHL)
7303 return std::nullopt;
7309 return std::nullopt;
7314 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7318 if (OffsetOpc == TargetOpcode::G_MUL) {
7320 return std::nullopt;
7326 if ((ImmVal & 0x7) != ImmVal)
7327 return std::nullopt;
7331 if (ImmVal != LegalShiftVal)
7332 return std::nullopt;
7334 unsigned SignExtend = 0;
7338 if (!LookedThroughZExt) {
7340 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7342 return std::nullopt;
7347 return std::nullopt;
7353 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7358 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7359 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7360 [=](MachineInstrBuilder &MIB) {
7363 MIB.addImm(SignExtend);
7376InstructionSelector::ComplexRendererFns
7377AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7378 MachineOperand &Root,
unsigned SizeInBytes)
const {
7380 return std::nullopt;
7395 MachineInstr *PtrAdd =
7397 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7398 return std::nullopt;
7402 MachineInstr *OffsetInst =
7404 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7417InstructionSelector::ComplexRendererFns
7418AArch64InstructionSelector::selectAddrModeRegisterOffset(
7419 MachineOperand &Root)
const {
7425 return std::nullopt;
7431 return std::nullopt;
7434 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7435 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7436 [=](MachineInstrBuilder &MIB) {
7446InstructionSelector::ComplexRendererFns
7447AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7448 unsigned SizeInBytes)
const {
7451 return std::nullopt;
7452 MachineInstr *PtrAdd =
7455 return std::nullopt;
7473 unsigned Scale =
Log2_32(SizeInBytes);
7474 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7478 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7479 ImmOff < (0x1000 << Scale))
7480 return std::nullopt;
7485 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7489 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7495 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7496 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7501 return std::nullopt;
7505 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7511 return selectAddrModeRegisterOffset(Root);
7520InstructionSelector::ComplexRendererFns
7521AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7522 unsigned SizeInBytes)
const {
7525 MachineInstr *PtrAdd =
7527 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7528 return std::nullopt;
7549 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7558 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7559 return std::nullopt;
7563 getExtendTypeForInst(*OffsetInst, MRI,
true);
7565 return std::nullopt;
7568 MachineIRBuilder MIB(*PtrAdd);
7570 AArch64::GPR32RegClass, MIB);
7574 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7575 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7576 [=](MachineInstrBuilder &MIB) {
7577 MIB.addImm(SignExtend);
7587InstructionSelector::ComplexRendererFns
7588AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7589 unsigned Size)
const {
7590 MachineRegisterInfo &MRI =
7594 return std::nullopt;
7596 if (!isBaseWithConstantOffset(Root, MRI))
7597 return std::nullopt;
7601 MachineOperand &OffImm = RootDef->
getOperand(2);
7602 if (!OffImm.
isReg())
7603 return std::nullopt;
7605 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7606 return std::nullopt;
7608 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7610 return std::nullopt;
7613 if (RHSC >= -256 && RHSC < 256) {
7616 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7617 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7620 return std::nullopt;
7623InstructionSelector::ComplexRendererFns
7624AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7626 MachineRegisterInfo &MRI)
const {
7627 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7628 return std::nullopt;
7631 return std::nullopt;
7636 return std::nullopt;
7640 return std::nullopt;
7644 return std::nullopt;
7647 MachineIRBuilder MIRBuilder(RootDef);
7649 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7650 [=](MachineInstrBuilder &MIB) {
7651 MIB.addGlobalAddress(GV,
Offset,
7660InstructionSelector::ComplexRendererFns
7661AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7662 unsigned Size)
const {
7667 return std::nullopt;
7670 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7672 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7673 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7681 MachineInstr *RootParent = Root.
getParent();
7683 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7685 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7690 if (isBaseWithConstantOffset(Root, MRI)) {
7698 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7699 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7701 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7702 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7706 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7707 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7714 if (selectAddrModeUnscaled(Root,
Size))
7715 return std::nullopt;
7718 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7719 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7726 switch (
MI.getOpcode()) {
7729 case TargetOpcode::G_SHL:
7731 case TargetOpcode::G_LSHR:
7733 case TargetOpcode::G_ASHR:
7735 case TargetOpcode::G_ROTR:
7742InstructionSelector::ComplexRendererFns
7743AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7744 bool AllowROR)
const {
7746 return std::nullopt;
7747 MachineRegisterInfo &MRI =
7755 return std::nullopt;
7757 return std::nullopt;
7758 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7759 return std::nullopt;
7762 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7765 return std::nullopt;
7769 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7773 unsigned Val = *Immed & (NumBits - 1);
7776 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7777 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7781 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7782 unsigned Opc =
MI.getOpcode();
7785 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7787 if (
Opc == TargetOpcode::G_SEXT)
7790 Size =
MI.getOperand(2).getImm();
7791 assert(
Size != 64 &&
"Extend from 64 bits?");
7804 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7806 assert(
Size != 64 &&
"Extend from 64 bits?");
7821 if (
Opc != TargetOpcode::G_AND)
7840Register AArch64InstructionSelector::moveScalarRegClass(
7842 MachineRegisterInfo &MRI = *MIB.
getMRI();
7852 return Copy.getReg(0);
7857InstructionSelector::ComplexRendererFns
7858AArch64InstructionSelector::selectArithExtendedRegister(
7859 MachineOperand &Root)
const {
7861 return std::nullopt;
7862 MachineRegisterInfo &MRI =
7870 return std::nullopt;
7872 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7873 return std::nullopt;
7876 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7881 return std::nullopt;
7882 ShiftVal = *MaybeShiftVal;
7884 return std::nullopt;
7889 return std::nullopt;
7890 Ext = getExtendTypeForInst(*ExtDef, MRI);
7892 return std::nullopt;
7896 Ext = getExtendTypeForInst(*RootDef, MRI);
7898 return std::nullopt;
7906 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7907 if (isDef32(*ExtInst))
7908 return std::nullopt;
7914 MachineIRBuilder MIB(*RootDef);
7915 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7917 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7918 [=](MachineInstrBuilder &MIB) {
7919 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7923InstructionSelector::ComplexRendererFns
7924AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7926 return std::nullopt;
7927 MachineRegisterInfo &MRI =
7931 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7936 return std::nullopt;
7939 if (Unmerge->getNumDefs() == 2 &&
7941 Register ExtReg = Unmerge->getSourceReg();
7942 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7946 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7950 LaneIdx->Value.getSExtValue() == 1) {
7951 Register ExtReg = ExtElt->getVectorReg();
7952 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7956 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7957 auto LaneIdx = Subvec->getIndexImm();
7959 Register ExtReg = Subvec->getSrcVec();
7960 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7964 return std::nullopt;
7967InstructionSelector::ComplexRendererFns
7968AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
7969 unsigned DstElemWidth,
7970 bool isReciprocal)
const {
7972 return std::nullopt;
7973 const MachineRegisterInfo &MRI =
7979 if (Dup && Dup->
getOpcode() == AArch64::G_DUP)
7982 std::optional<ValueAndVReg> CstVal =
7986 return std::nullopt;
7990 switch (CstElemWidth) {
7992 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7995 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7998 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8001 return std::nullopt;
8003 if (
unsigned FBits =
8005 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8007 return std::nullopt;
8010unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8011 const MachineOperand &Root)
const {
8019template <
unsigned W
idth>
8020InstructionSelector::ComplexRendererFns
8021AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8022 return selectCVTFixedPointBase(Root, Width,
false);
8025InstructionSelector::ComplexRendererFns
8026AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8027 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8031InstructionSelector::ComplexRendererFns
8032AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8033 MachineOperand &Root)
const {
8034 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8038void AArch64InstructionSelector::renderFixedPointScalarXForm(
8039 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8040 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8041 "Expected vecshift immediate operand");
8042 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8045void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8046 const MachineOperand &Root,
8048 bool isReciprocal)
const {
8052 InstructionSelector::ComplexRendererFns Renderer =
8053 selectCVTFixedPointBase(Root, Width, isReciprocal);
8054 assert((Renderer && Renderer->size() == 1) &&
8055 "Expected selectCVTFixedPointBase to provide a function\n");
8056 (Renderer->front())(MIB);
8059void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8060 const MachineInstr &
MI,
8062 const MachineOperand &Root =
MI.getOperand(OpIdx);
8063 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8067void AArch64InstructionSelector::renderFixedPointRecipXForm(
8068 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8069 const MachineOperand &Root =
MI.getOperand(OpIdx);
8070 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8074void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8075 const MachineInstr &
MI,
8077 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8078 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8079 "Expected G_CONSTANT");
8080 std::optional<int64_t> CstVal =
8082 assert(CstVal &&
"Expected constant value");
8086void AArch64InstructionSelector::renderLogicalImm32(
8087 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8088 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8089 "Expected G_CONSTANT");
8090 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8095void AArch64InstructionSelector::renderLogicalImm64(
8096 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8097 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8098 "Expected G_CONSTANT");
8099 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8104void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8105 const MachineInstr &
MI,
8107 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8108 "Expected G_UBSANTRAP");
8109 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8112void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8113 const MachineInstr &
MI,
8115 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8116 "Expected G_FCONSTANT");
8121void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8122 const MachineInstr &
MI,
8124 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8125 "Expected G_FCONSTANT");
8130void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8131 const MachineInstr &
MI,
8133 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8134 "Expected G_FCONSTANT");
8139void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8140 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8141 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8142 "Expected G_FCONSTANT");
8150bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8151 const MachineInstr &
MI,
unsigned NumBytes)
const {
8152 if (!
MI.mayLoadOrStore())
8155 "Expected load/store to have only one mem op!");
8156 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8159bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8160 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8168 switch (
MI.getOpcode()) {
8171 case TargetOpcode::COPY:
8172 case TargetOpcode::G_BITCAST:
8173 case TargetOpcode::G_TRUNC:
8174 case TargetOpcode::G_PHI:
8184 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8187 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8205 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8210 MO.setReg(Copy.getReg(0));
8219 for (
auto &BB : MF) {
8220 for (
auto &
MI : BB) {
8221 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8226 for (
auto *
MI : Phis) {
8248 bool HasGPROp =
false, HasFPROp =
false;
8252 const LLT &Ty = MRI.
getType(MO.getReg());
8262 if (RB->
getID() == AArch64::GPRRegBankID)
8268 if (HasGPROp && HasFPROp)
8274InstructionSelector *
8278 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
static std::pair< const TargetRegisterClass *, const TargetRegisterClass * > getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Helper function to get the source and destination register classes for a copy.
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc, 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
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
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.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
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.