45#include "llvm/IR/IntrinsicsAArch64.h"
52#define DEBUG_TYPE "aarch64-isel"
65#define GET_GLOBALISEL_PREDICATE_BITSET
66#include "AArch64GenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATE_BITSET
87 ProduceNonFlagSettingCondBr =
135 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
213 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
215 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
217 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
219 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
233 unsigned Opc1,
unsigned Opc2,
bool isExt);
239 unsigned emitConstantPoolEntry(
const Constant *CPVal,
258 std::optional<CmpInst::Predicate> = std::nullopt)
const;
261 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
262 std::initializer_list<llvm::SrcOp> SrcOps,
264 const ComplexRendererFns &RenderFns = std::nullopt)
const;
299 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
322 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
344 std::pair<MachineInstr *, AArch64CC::CondCode>
379 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
380 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
381 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
382 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
384 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
386 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
389 unsigned Size)
const;
391 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
392 return selectAddrModeUnscaled(Root, 1);
394 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
395 return selectAddrModeUnscaled(Root, 2);
397 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
398 return selectAddrModeUnscaled(Root, 4);
400 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
401 return selectAddrModeUnscaled(Root, 8);
403 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
404 return selectAddrModeUnscaled(Root, 16);
409 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
413 unsigned Size)
const;
415 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
416 return selectAddrModeIndexed(Root, Width / 8);
425 bool IsAddrOperand)
const;
428 unsigned SizeInBytes)
const;
436 bool WantsExt)
const;
437 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
439 unsigned SizeInBytes)
const;
441 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
442 return selectAddrModeXRO(Root, Width / 8);
446 unsigned SizeInBytes)
const;
448 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
449 return selectAddrModeWRO(Root, Width / 8);
453 bool AllowROR =
false)
const;
455 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
456 return selectShiftedRegister(Root);
459 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
460 return selectShiftedRegister(Root,
true);
470 bool IsLoadStore =
false)
const;
481 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
485 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
490 bool isReciprocal =
false)
const;
494 int OpIdx = -1)
const;
498 int OpIdx = -1)
const;
500 int OpIdx = -1)
const;
502 int OpIdx = -1)
const;
506 int OpIdx = -1)
const;
508 int OpIdx = -1)
const;
510 int OpIdx = -1)
const;
513 int OpIdx = -1)
const;
519 bool tryOptSelect(
GSelect &Sel);
526 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
539 bool ProduceNonFlagSettingCondBr =
false;
548#define GET_GLOBALISEL_PREDICATES_DECL
549#include "AArch64GenGlobalISel.inc"
550#undef GET_GLOBALISEL_PREDICATES_DECL
554#define GET_GLOBALISEL_TEMPORARIES_DECL
555#include "AArch64GenGlobalISel.inc"
556#undef GET_GLOBALISEL_TEMPORARIES_DECL
561#define GET_GLOBALISEL_IMPL
562#include "AArch64GenGlobalISel.inc"
563#undef GET_GLOBALISEL_IMPL
565AArch64InstructionSelector::AArch64InstructionSelector(
568 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
571#include
"AArch64GenGlobalISel.inc"
574#include
"AArch64GenGlobalISel.inc"
586 bool GetAllRegSet =
false) {
587 if (RB.
getID() == AArch64::GPRRegBankID) {
588 if (Ty.getSizeInBits() <= 32)
589 return GetAllRegSet ? &AArch64::GPR32allRegClass
590 : &AArch64::GPR32RegClass;
591 if (Ty.getSizeInBits() == 64)
592 return GetAllRegSet ? &AArch64::GPR64allRegClass
593 : &AArch64::GPR64RegClass;
594 if (Ty.getSizeInBits() == 128)
595 return &AArch64::XSeqPairsClassRegClass;
599 if (RB.
getID() == AArch64::FPRRegBankID) {
600 switch (Ty.getSizeInBits()) {
602 return &AArch64::FPR8RegClass;
604 return &AArch64::FPR16RegClass;
606 return &AArch64::FPR32RegClass;
608 return &AArch64::FPR64RegClass;
610 return &AArch64::FPR128RegClass;
622 bool GetAllRegSet =
false) {
625 "Expected FPR regbank for scalable type size");
626 return &AArch64::ZPRRegClass;
629 unsigned RegBankID = RB.
getID();
631 if (RegBankID == AArch64::GPRRegBankID) {
633 if (SizeInBits <= 32)
634 return GetAllRegSet ? &AArch64::GPR32allRegClass
635 : &AArch64::GPR32RegClass;
636 if (SizeInBits == 64)
637 return GetAllRegSet ? &AArch64::GPR64allRegClass
638 : &AArch64::GPR64RegClass;
639 if (SizeInBits == 128)
640 return &AArch64::XSeqPairsClassRegClass;
643 if (RegBankID == AArch64::FPRRegBankID) {
646 "Unexpected scalable register size");
647 return &AArch64::ZPRRegClass;
650 switch (SizeInBits) {
654 return &AArch64::FPR8RegClass;
656 return &AArch64::FPR16RegClass;
658 return &AArch64::FPR32RegClass;
660 return &AArch64::FPR64RegClass;
662 return &AArch64::FPR128RegClass;
672 switch (
TRI.getRegSizeInBits(*RC)) {
674 SubReg = AArch64::bsub;
677 SubReg = AArch64::hsub;
680 if (RC != &AArch64::FPR32RegClass)
681 SubReg = AArch64::sub_32;
683 SubReg = AArch64::ssub;
686 SubReg = AArch64::dsub;
690 dbgs() <<
"Couldn't find appropriate subregister for register class.");
699 switch (RB.
getID()) {
700 case AArch64::GPRRegBankID:
702 case AArch64::FPRRegBankID:
725 const unsigned RegClassIDs[],
727 unsigned NumRegs = Regs.
size();
730 assert(NumRegs >= 2 && NumRegs <= 4 &&
731 "Only support between two and 4 registers in a tuple!");
733 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
735 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
736 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
737 RegSequence.addUse(Regs[
I]);
738 RegSequence.addImm(SubRegs[
I]);
740 return RegSequence.getReg(0);
745 static const unsigned RegClassIDs[] = {
746 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
747 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
748 AArch64::dsub2, AArch64::dsub3};
749 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
754 static const unsigned RegClassIDs[] = {
755 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
756 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
757 AArch64::qsub2, AArch64::qsub3};
758 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
763 auto &
MBB = *
MI.getParent();
764 auto &MF = *
MBB.getParent();
765 auto &MRI = MF.getRegInfo();
771 else if (Root.
isReg()) {
776 Immed = ValAndVReg->Value.getSExtValue();
787 if (RegBankID == AArch64::GPRRegBankID) {
789 switch (GenericOpc) {
790 case TargetOpcode::G_SHL:
791 return AArch64::LSLVWr;
792 case TargetOpcode::G_LSHR:
793 return AArch64::LSRVWr;
794 case TargetOpcode::G_ASHR:
795 return AArch64::ASRVWr;
799 }
else if (OpSize == 64) {
800 switch (GenericOpc) {
801 case TargetOpcode::G_SHL:
802 return AArch64::LSLVXr;
803 case TargetOpcode::G_LSHR:
804 return AArch64::LSRVXr;
805 case TargetOpcode::G_ASHR:
806 return AArch64::ASRVXr;
822 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
824 case AArch64::GPRRegBankID:
827 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
829 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
831 return isStore ? AArch64::STRWui : AArch64::LDRWui;
833 return isStore ? AArch64::STRXui : AArch64::LDRXui;
836 case AArch64::FPRRegBankID:
839 return isStore ? AArch64::STRBui : AArch64::LDRBui;
841 return isStore ? AArch64::STRHui : AArch64::LDRHui;
843 return isStore ? AArch64::STRSui : AArch64::LDRSui;
845 return isStore ? AArch64::STRDui : AArch64::LDRDui;
847 return isStore ? AArch64::STRQui : AArch64::LDRQui;
861 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
862 assert(To &&
"Destination register class cannot be null");
863 assert(SubReg &&
"Expected a valid subregister");
867 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
869 RegOp.
setReg(SubRegCopy.getReg(0));
873 if (!
I.getOperand(0).getReg().isPhysical())
883static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
887 Register DstReg =
I.getOperand(0).getReg();
888 Register SrcReg =
I.getOperand(1).getReg();
903 if (SrcRegBank != DstRegBank &&
922 if (
Reg.isPhysical())
930 RC = getRegClassForTypeOnBank(Ty, RB);
933 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
946 Register DstReg =
I.getOperand(0).getReg();
947 Register SrcReg =
I.getOperand(1).getReg();
966 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
970 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
971 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
972 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
986 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
987 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
988 }
else if (SrcSize > DstSize) {
995 }
else if (DstSize > SrcSize) {
1004 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1008 RegOp.
setReg(PromoteReg);
1027 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1028 I.setDesc(
TII.get(AArch64::COPY));
1029 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1033 I.setDesc(
TII.get(AArch64::COPY));
1041 MachineRegisterInfo &MRI = *MIB.
getMRI();
1044 "Expected both select operands to have the same regbank?");
1050 "Expected 32 bit or 64 bit select only?");
1051 const bool Is32Bit =
Size == 32;
1053 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1054 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1060 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1062 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1077 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1094 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1113 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1129 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1135 if (!TrueCst && !FalseCst)
1138 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1139 if (TrueCst && FalseCst) {
1140 int64_t
T = TrueCst->Value.getSExtValue();
1141 int64_t
F = FalseCst->Value.getSExtValue();
1143 if (
T == 0 &&
F == 1) {
1145 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1151 if (
T == 0 &&
F == -1) {
1153 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1161 int64_t
T = TrueCst->Value.getSExtValue();
1164 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1173 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1182 int64_t
F = FalseCst->Value.getSExtValue();
1185 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1192 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1200 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1201 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1203 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1205 return &*SelectInst;
1210 MachineRegisterInfo *MRI =
nullptr) {
1223 if (ValAndVReg && ValAndVReg->Value == 0)
1230 if (ValAndVReg && ValAndVReg->Value == 0)
1334 assert(
Reg.isValid() &&
"Expected valid register!");
1335 bool HasZext =
false;
1337 unsigned Opc =
MI->getOpcode();
1339 if (!
MI->getOperand(0).isReg() ||
1348 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1349 Opc == TargetOpcode::G_TRUNC) {
1350 if (
Opc == TargetOpcode::G_ZEXT)
1353 Register NextReg =
MI->getOperand(1).getReg();
1367 std::optional<uint64_t>
C;
1372 case TargetOpcode::G_AND:
1373 case TargetOpcode::G_XOR: {
1374 TestReg =
MI->getOperand(1).getReg();
1375 Register ConstantReg =
MI->getOperand(2).getReg();
1386 C = VRegAndVal->Value.getZExtValue();
1388 C = VRegAndVal->Value.getSExtValue();
1392 case TargetOpcode::G_ASHR:
1393 case TargetOpcode::G_LSHR:
1394 case TargetOpcode::G_SHL: {
1395 TestReg =
MI->getOperand(1).getReg();
1399 C = VRegAndVal->Value.getSExtValue();
1415 case TargetOpcode::G_AND:
1417 if ((*
C >> Bit) & 1)
1420 case TargetOpcode::G_SHL:
1423 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1428 case TargetOpcode::G_ASHR:
1433 if (Bit >= TestRegSize)
1434 Bit = TestRegSize - 1;
1436 case TargetOpcode::G_LSHR:
1438 if ((Bit + *
C) < TestRegSize) {
1443 case TargetOpcode::G_XOR:
1452 if ((*
C >> Bit) & 1)
1467MachineInstr *AArch64InstructionSelector::emitTestBit(
1468 Register TestReg, uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1469 MachineIRBuilder &MIB)
const {
1471 assert(ProduceNonFlagSettingCondBr &&
1472 "Cannot emit TB(N)Z with speculation tracking!");
1473 MachineRegisterInfo &MRI = *MIB.
getMRI();
1477 LLT Ty = MRI.
getType(TestReg);
1480 assert(Bit < 64 &&
"Bit is too large!");
1484 bool UseWReg =
Bit < 32;
1485 unsigned NecessarySize = UseWReg ? 32 : 64;
1486 if (
Size != NecessarySize)
1487 TestReg = moveScalarRegClass(
1488 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1491 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1492 {AArch64::TBZW, AArch64::TBNZW}};
1493 unsigned Opc = OpcTable[UseWReg][IsNegative];
1500bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1501 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1502 MachineIRBuilder &MIB)
const {
1503 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1530 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1537 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1541MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1543 MachineBasicBlock *DestMBB,
1544 MachineIRBuilder &MIB)
const {
1545 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1546 MachineRegisterInfo &MRI = *MIB.
getMRI();
1548 AArch64::GPRRegBankID &&
1549 "Expected GPRs only?");
1550 auto Ty = MRI.
getType(CompareReg);
1553 assert(Width <= 64 &&
"Expected width to be at most 64?");
1554 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1555 {AArch64::CBNZW, AArch64::CBNZX}};
1556 unsigned Opc = OpcTable[IsNegative][Width == 64];
1557 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1562bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1563 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1565 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1573 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1577 I.eraseFromParent();
1581bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1582 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1584 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1590 if (!ProduceNonFlagSettingCondBr)
1593 MachineRegisterInfo &MRI = *MIB.
getMRI();
1594 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1609 if (VRegAndVal && !AndInst) {
1610 int64_t
C = VRegAndVal->Value.getSExtValue();
1616 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1617 I.eraseFromParent();
1625 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1626 I.eraseFromParent();
1634 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1635 I.eraseFromParent();
1649 if (VRegAndVal && VRegAndVal->Value == 0) {
1657 tryOptAndIntoCompareBranch(
1659 I.eraseFromParent();
1665 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1667 I.eraseFromParent();
1676bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1677 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1679 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1680 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1684 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1691 I.eraseFromParent();
1695bool AArch64InstructionSelector::selectCompareBranch(
1697 Register CondReg =
I.getOperand(0).getReg();
1698 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1702 if (CCMIOpc == TargetOpcode::G_FCMP)
1703 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1704 if (CCMIOpc == TargetOpcode::G_ICMP)
1705 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1710 if (ProduceNonFlagSettingCondBr) {
1711 emitTestBit(CondReg, 0,
true,
1712 I.getOperand(1).getMBB(), MIB);
1713 I.eraseFromParent();
1723 .
addMBB(
I.getOperand(1).getMBB());
1724 I.eraseFromParent();
1744 return std::nullopt;
1746 int64_t Imm = *ShiftImm;
1748 return std::nullopt;
1749 switch (SrcTy.getElementType().getSizeInBits()) {
1752 return std::nullopt;
1755 return std::nullopt;
1759 return std::nullopt;
1763 return std::nullopt;
1767 return std::nullopt;
1773bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1774 MachineRegisterInfo &MRI) {
1775 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1776 Register DstReg =
I.getOperand(0).getReg();
1777 const LLT Ty = MRI.
getType(DstReg);
1778 Register Src1Reg =
I.getOperand(1).getReg();
1779 Register Src2Reg =
I.getOperand(2).getReg();
1790 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1792 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1794 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1796 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1798 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1800 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1802 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1814 I.eraseFromParent();
1818bool AArch64InstructionSelector::selectVectorAshrLshr(
1819 MachineInstr &
I, MachineRegisterInfo &MRI) {
1820 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1821 I.getOpcode() == TargetOpcode::G_LSHR);
1822 Register DstReg =
I.getOperand(0).getReg();
1823 const LLT Ty = MRI.
getType(DstReg);
1824 Register Src1Reg =
I.getOperand(1).getReg();
1825 Register Src2Reg =
I.getOperand(2).getReg();
1830 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1840 unsigned NegOpc = 0;
1842 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1844 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1845 NegOpc = AArch64::NEGv2i64;
1847 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1848 NegOpc = AArch64::NEGv4i32;
1850 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1851 NegOpc = AArch64::NEGv2i32;
1853 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1854 NegOpc = AArch64::NEGv4i16;
1856 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1857 NegOpc = AArch64::NEGv8i16;
1859 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1860 NegOpc = AArch64::NEGv16i8;
1862 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1863 NegOpc = AArch64::NEGv8i8;
1869 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1873 I.eraseFromParent();
1877bool AArch64InstructionSelector::selectVaStartAAPCS(
1887 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1889 const auto *PtrRegClass =
1890 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1892 const MCInstrDesc &MCIDAddAddr =
1894 const MCInstrDesc &MCIDStoreAddr =
1906 const auto VAList =
I.getOperand(0).getReg();
1909 unsigned OffsetBytes = 0;
1913 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1915 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1922 const auto *MMO = *
I.memoperands_begin();
1923 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1926 .
addImm(OffsetBytes / PtrSize)
1928 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1932 OffsetBytes += PtrSize;
1948 const auto PushIntConstant = [&](
const int32_t
Value) {
1949 constexpr int IntSize = 4;
1952 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
1957 const auto *MMO = *
I.memoperands_begin();
1958 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
1961 .
addImm(OffsetBytes / IntSize)
1963 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1966 OffsetBytes += IntSize;
1970 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
1973 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
1977 I.eraseFromParent();
1981bool AArch64InstructionSelector::selectVaStartDarwin(
1983 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1984 Register ListReg =
I.getOperand(0).getReg();
1989 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
1997 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2005 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2012 I.eraseFromParent();
2016void AArch64InstructionSelector::materializeLargeCMVal(
2017 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2022 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2037 GV, MovZ->getOperand(1).getOffset(), Flags));
2041 MovZ->getOperand(1).getOffset(), Flags));
2047 Register DstReg = BuildMovK(MovZ.getReg(0),
2053bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2058 switch (
I.getOpcode()) {
2059 case TargetOpcode::G_CONSTANT: {
2060 Register DefReg =
I.getOperand(0).getReg();
2061 const LLT DefTy = MRI.
getType(DefReg);
2067 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2068 I.getOperand(1).setCImm(
2073 I.getOperand(0).setReg(WideReg);
2082 if (PtrSize != 32 && PtrSize != 64)
2088 case TargetOpcode::G_STORE: {
2089 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2090 MachineOperand &SrcOp =
I.getOperand(0);
2103 case TargetOpcode::G_PTR_ADD: {
2107 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2109 return convertPtrAddToAdd(
I, MRI);
2111 case TargetOpcode::G_LOAD: {
2116 Register DstReg =
I.getOperand(0).getReg();
2117 const LLT DstTy = MRI.
getType(DstReg);
2123 case AArch64::G_DUP: {
2125 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2129 MRI.
setType(
I.getOperand(0).getReg(),
2131 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2132 I.getOperand(1).setReg(NewSrc.getReg(0));
2135 case AArch64::G_INSERT_VECTOR_ELT: {
2136 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2137 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2141 MRI.
setType(
I.getOperand(1).getReg(),
2143 MRI.
setType(
I.getOperand(0).getReg(),
2145 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2146 I.getOperand(2).setReg(NewSrc.getReg(0));
2150 Register EltReg =
I.getOperand(2).getReg();
2151 LLT EltTy = MRI.
getType(EltReg);
2157 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2158 I.getOperand(2).setReg(NewElt.getReg(0));
2163 case TargetOpcode::G_UITOFP:
2164 case TargetOpcode::G_SITOFP: {
2169 Register SrcReg =
I.getOperand(1).getReg();
2170 LLT SrcTy = MRI.
getType(SrcReg);
2171 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2180 I.getOperand(1).setReg(
Copy.getReg(0));
2182 getRegClassForTypeOnBank(
2183 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2185 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2186 I.setDesc(
TII.get(AArch64::G_SITOF));
2188 I.setDesc(
TII.get(AArch64::G_UITOF));
2206bool AArch64InstructionSelector::convertPtrAddToAdd(
2207 MachineInstr &
I, MachineRegisterInfo &MRI) {
2208 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2209 Register DstReg =
I.getOperand(0).getReg();
2210 Register AddOp1Reg =
I.getOperand(1).getReg();
2211 const LLT PtrTy = MRI.
getType(DstReg);
2215 const LLT CastPtrTy = PtrTy.
isVector()
2227 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2228 MRI.
setType(DstReg, CastPtrTy);
2229 I.getOperand(1).setReg(PtrToInt.getReg(0));
2230 if (!select(*PtrToInt)) {
2231 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2240 I.getOperand(2).setReg(NegatedReg);
2241 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2245bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2246 MachineRegisterInfo &MRI) {
2250 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2251 const auto &MO =
I.getOperand(2);
2256 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2260 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2261 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2263 if (!Imm1Fn || !Imm2Fn)
2267 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2268 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2270 for (
auto &RenderFn : *Imm1Fn)
2272 for (
auto &RenderFn : *Imm2Fn)
2275 I.eraseFromParent();
2280bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2281 MachineInstr &
I, MachineRegisterInfo &MRI) {
2282 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2300 LLT DefDstTy = MRI.
getType(DefDstReg);
2301 Register StoreSrcReg =
I.getOperand(0).getReg();
2302 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2318 I.getOperand(0).setReg(DefDstReg);
2322bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2323 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2324 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2330 switch (
I.getOpcode()) {
2331 case AArch64::G_DUP: {
2334 Register Src =
I.getOperand(1).getReg();
2336 Src, MRI,
true,
true);
2340 Register Dst =
I.getOperand(0).getReg();
2346 if (!emitConstantVector(Dst, CV, MIB, MRI))
2348 I.eraseFromParent();
2351 case TargetOpcode::G_SEXT:
2354 if (selectUSMovFromExtend(
I, MRI))
2357 case TargetOpcode::G_BR:
2359 case TargetOpcode::G_SHL:
2360 return earlySelectSHL(
I, MRI);
2361 case TargetOpcode::G_CONSTANT: {
2362 bool IsZero =
false;
2363 if (
I.getOperand(1).isCImm())
2364 IsZero =
I.getOperand(1).getCImm()->isZero();
2365 else if (
I.getOperand(1).isImm())
2366 IsZero =
I.getOperand(1).getImm() == 0;
2371 Register DefReg =
I.getOperand(0).getReg();
2374 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2377 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2382 I.setDesc(
TII.get(TargetOpcode::COPY));
2386 case TargetOpcode::G_ADD: {
2395 Register AddDst =
I.getOperand(0).getReg();
2396 Register AddLHS =
I.getOperand(1).getReg();
2397 Register AddRHS =
I.getOperand(2).getReg();
2407 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2428 MachineInstr *
Cmp = MatchCmp(AddRHS);
2432 Cmp = MatchCmp(AddRHS);
2436 auto &PredOp =
Cmp->getOperand(1);
2438 emitIntegerCompare(
Cmp->getOperand(2),
2439 Cmp->getOperand(3), PredOp, MIB);
2443 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2444 I.eraseFromParent();
2447 case TargetOpcode::G_OR: {
2451 Register Dst =
I.getOperand(0).getReg();
2471 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2474 int64_t Immr =
Size - ShiftImm;
2475 int64_t Imms =
Size - ShiftImm - 1;
2476 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2477 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2478 I.eraseFromParent();
2481 case TargetOpcode::G_FENCE: {
2482 if (
I.getOperand(1).getImm() == 0)
2486 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2487 I.eraseFromParent();
2495bool AArch64InstructionSelector::select(MachineInstr &
I) {
2496 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2497 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2503 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2504 if (Subtarget->requiresStrictAlign()) {
2506 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2512 unsigned Opcode =
I.getOpcode();
2514 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2517 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2522 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2523 const Register DefReg =
I.getOperand(0).getReg();
2524 const LLT DefTy = MRI.
getType(DefReg);
2537 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2544 I.setDesc(
TII.get(TargetOpcode::PHI));
2552 if (
I.isDebugInstr())
2559 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2561 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2568 if (preISelLower(
I)) {
2569 Opcode =
I.getOpcode();
2580 if (selectImpl(
I, *CoverageInfo))
2584 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2587 case TargetOpcode::G_SBFX:
2588 case TargetOpcode::G_UBFX: {
2589 static const unsigned OpcTable[2][2] = {
2590 {AArch64::UBFMWri, AArch64::UBFMXri},
2591 {AArch64::SBFMWri, AArch64::SBFMXri}};
2592 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2594 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2597 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2600 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2601 auto LSB = Cst1->Value.getZExtValue();
2602 auto Width = Cst2->Value.getZExtValue();
2606 .
addImm(LSB + Width - 1);
2607 I.eraseFromParent();
2611 case TargetOpcode::G_BRCOND:
2612 return selectCompareBranch(
I, MF, MRI);
2614 case TargetOpcode::G_BRINDIRECT: {
2616 if (std::optional<uint16_t> BADisc =
2618 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2621 MI.addReg(AArch64::XZR);
2622 I.eraseFromParent();
2626 I.setDesc(
TII.get(AArch64::BR));
2631 case TargetOpcode::G_BRJT:
2632 return selectBrJT(
I, MRI);
2634 case AArch64::G_ADD_LOW: {
2639 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2640 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2641 I.setDesc(
TII.get(AArch64::ADDXri));
2647 "Expected small code model");
2649 auto Op2 =
I.getOperand(2);
2650 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2651 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2652 Op1.getTargetFlags())
2654 Op2.getTargetFlags());
2655 I.eraseFromParent();
2660 case TargetOpcode::G_FCONSTANT: {
2661 const Register DefReg =
I.getOperand(0).getReg();
2662 const LLT DefTy = MRI.
getType(DefReg);
2673 bool OptForSize = shouldOptForSize(&MF);
2677 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2684 auto *FPImm =
I.getOperand(1).getFPImm();
2687 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2690 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2691 I.eraseFromParent();
2696 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2699 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2700 MachineOperand &RegOp =
I.getOperand(0);
2706 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2710 MachineOperand &ImmOp =
I.getOperand(1);
2714 const unsigned MovOpc =
2715 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2716 I.setDesc(
TII.get(MovOpc));
2720 case TargetOpcode::G_EXTRACT: {
2721 Register DstReg =
I.getOperand(0).getReg();
2722 Register SrcReg =
I.getOperand(1).getReg();
2723 LLT SrcTy = MRI.
getType(SrcReg);
2724 LLT DstTy = MRI.
getType(DstReg);
2736 unsigned Offset =
I.getOperand(2).getImm();
2741 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2742 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2745 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2747 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2749 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2751 AArch64::GPR64RegClass, NewI->getOperand(0));
2752 I.eraseFromParent();
2758 unsigned LaneIdx =
Offset / 64;
2759 MachineInstr *Extract = emitExtractVectorElt(
2760 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2763 I.eraseFromParent();
2767 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2768 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2773 "unexpected G_EXTRACT types");
2780 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2781 .addReg(DstReg, {}, AArch64::sub_32);
2783 AArch64::GPR32RegClass, MRI);
2784 I.getOperand(0).setReg(DstReg);
2790 case TargetOpcode::G_INSERT: {
2791 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2792 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2799 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2800 unsigned LSB =
I.getOperand(3).getImm();
2802 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2803 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2807 "unexpected G_INSERT types");
2814 TII.get(AArch64::SUBREG_TO_REG))
2816 .
addUse(
I.getOperand(2).getReg())
2817 .
addImm(AArch64::sub_32);
2819 AArch64::GPR32RegClass, MRI);
2820 I.getOperand(2).setReg(SrcReg);
2825 case TargetOpcode::G_FRAME_INDEX: {
2832 I.setDesc(
TII.get(AArch64::ADDXri));
2842 case TargetOpcode::G_GLOBAL_VALUE: {
2843 const GlobalValue *GV =
nullptr;
2845 if (
I.getOperand(1).isSymbol()) {
2846 OpFlags =
I.getOperand(1).getTargetFlags();
2855 return selectTLSGlobalValue(
I, MRI);
2861 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2862 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2863 I.getOperand(1).setTargetFlags(OpFlags);
2864 I.addImplicitDefUseOperands(MF);
2868 materializeLargeCMVal(
I, GV, OpFlags);
2869 I.eraseFromParent();
2872 I.setDesc(
TII.get(AArch64::ADR));
2873 I.getOperand(1).setTargetFlags(OpFlags);
2875 I.setDesc(
TII.get(AArch64::MOVaddr));
2877 MachineInstrBuilder MIB(MF,
I);
2878 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2885 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2886 return selectPtrAuthGlobalValue(
I, MRI);
2888 case TargetOpcode::G_ZEXTLOAD:
2889 case TargetOpcode::G_LOAD:
2890 case TargetOpcode::G_STORE: {
2892 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2907 assert(MemSizeInBytes <= 8 &&
2908 "128-bit atomics should already be custom-legalized");
2911 static constexpr unsigned LDAPROpcodes[] = {
2912 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2913 static constexpr unsigned LDAROpcodes[] = {
2914 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2915 ArrayRef<unsigned> Opcodes =
2916 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2919 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2921 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2922 AArch64::STLRW, AArch64::STLRX};
2927 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2928 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2929 I.getOperand(0).setReg(NewVal);
2931 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2939 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2942 "Load/Store pointer operand isn't a GPR");
2944 "Load/Store pointer operand isn't a pointer");
2949 LLT ValTy = MRI.
getType(ValReg);
2954 RB.
getID() == AArch64::FPRRegBankID) {
2957 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2963 .addReg(ValReg, {}, SubReg)
2970 if (RB.
getID() == AArch64::FPRRegBankID) {
2973 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2983 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
2986 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
2995 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
2997 const unsigned NewOpc =
2999 if (NewOpc ==
I.getOpcode())
3003 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3006 I.setDesc(
TII.get(NewOpc));
3012 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3013 Register CurValReg =
I.getOperand(0).getReg();
3014 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3015 NewInst.cloneMemRefs(
I);
3016 for (
auto &Fn : *AddrModeFns)
3018 I.eraseFromParent();
3022 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3027 if (Opcode == TargetOpcode::G_STORE) {
3029 LoadStore->getOperand(0).getReg(), MRI);
3030 if (CVal && CVal->Value == 0) {
3032 case AArch64::STRWui:
3033 case AArch64::STRHHui:
3034 case AArch64::STRBBui:
3035 LoadStore->getOperand(0).setReg(AArch64::WZR);
3037 case AArch64::STRXui:
3038 LoadStore->getOperand(0).setReg(AArch64::XZR);
3044 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3045 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3057 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3059 .
addImm(AArch64::sub_32);
3068 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3069 case TargetOpcode::G_INDEXED_SEXTLOAD:
3070 return selectIndexedExtLoad(
I, MRI);
3071 case TargetOpcode::G_INDEXED_LOAD:
3072 return selectIndexedLoad(
I, MRI);
3073 case TargetOpcode::G_INDEXED_STORE:
3076 case TargetOpcode::G_LSHR:
3077 case TargetOpcode::G_ASHR:
3079 return selectVectorAshrLshr(
I, MRI);
3081 case TargetOpcode::G_SHL: {
3082 if (Opcode == TargetOpcode::G_SHL &&
3084 return selectVectorSHL(
I, MRI);
3091 Register SrcReg =
I.getOperand(1).getReg();
3092 Register ShiftReg =
I.getOperand(2).getReg();
3093 const LLT ShiftTy = MRI.
getType(ShiftReg);
3094 const LLT SrcTy = MRI.
getType(SrcReg);
3099 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3100 .addReg(ShiftReg, {}, AArch64::sub_32);
3102 I.getOperand(2).setReg(Trunc.getReg(0));
3107 const Register DefReg =
I.getOperand(0).getReg();
3111 if (NewOpc ==
I.getOpcode())
3114 I.setDesc(
TII.get(NewOpc));
3122 case TargetOpcode::G_PTR_ADD: {
3123 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3124 I.eraseFromParent();
3128 case TargetOpcode::G_SADDE:
3129 case TargetOpcode::G_UADDE:
3130 case TargetOpcode::G_SSUBE:
3131 case TargetOpcode::G_USUBE:
3132 case TargetOpcode::G_SADDO:
3133 case TargetOpcode::G_UADDO:
3134 case TargetOpcode::G_SSUBO:
3135 case TargetOpcode::G_USUBO:
3136 return selectOverflowOp(
I, MRI);
3138 case TargetOpcode::G_PTRMASK: {
3139 Register MaskReg =
I.getOperand(2).getReg();
3145 uint64_t
Mask = *MaskVal;
3146 I.setDesc(
TII.get(AArch64::ANDXri));
3147 I.getOperand(2).ChangeToImmediate(
3153 case TargetOpcode::G_PTRTOINT:
3154 case TargetOpcode::G_TRUNC: {
3155 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3156 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3158 const Register DstReg =
I.getOperand(0).getReg();
3159 const Register SrcReg =
I.getOperand(1).getReg();
3161 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3162 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3166 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3170 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3181 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3185 if (DstRC == SrcRC) {
3187 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3191 }
else if (DstRC == &AArch64::GPR32RegClass &&
3192 SrcRC == &AArch64::GPR64RegClass) {
3193 I.getOperand(1).setSubReg(AArch64::sub_32);
3196 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3200 I.setDesc(
TII.get(TargetOpcode::COPY));
3202 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3205 I.setDesc(
TII.get(AArch64::XTNv4i16));
3211 MachineInstr *Extract = emitExtractVectorElt(
3215 I.eraseFromParent();
3220 if (Opcode == TargetOpcode::G_PTRTOINT) {
3221 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3222 I.setDesc(
TII.get(TargetOpcode::COPY));
3230 case TargetOpcode::G_ANYEXT: {
3231 if (selectUSMovFromExtend(
I, MRI))
3234 const Register DstReg =
I.getOperand(0).getReg();
3235 const Register SrcReg =
I.getOperand(1).getReg();
3237 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3238 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3240 <<
", expected: GPR\n");
3244 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3245 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3247 <<
", expected: GPR\n");
3254 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3258 if (DstSize != 64 && DstSize > 32) {
3260 <<
", expected: 32 or 64\n");
3270 .
addImm(AArch64::sub_32);
3271 I.getOperand(1).setReg(ExtSrc);
3276 case TargetOpcode::G_ZEXT:
3277 case TargetOpcode::G_SEXT_INREG:
3278 case TargetOpcode::G_SEXT: {
3279 if (selectUSMovFromExtend(
I, MRI))
3282 unsigned Opcode =
I.getOpcode();
3283 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3284 const Register DefReg =
I.getOperand(0).getReg();
3285 Register SrcReg =
I.getOperand(1).getReg();
3286 const LLT DstTy = MRI.
getType(DefReg);
3287 const LLT SrcTy = MRI.
getType(SrcReg);
3293 if (Opcode == TargetOpcode::G_SEXT_INREG)
3294 SrcSize =
I.getOperand(2).getImm();
3300 AArch64::GPRRegBankID &&
3301 "Unexpected ext regbank");
3312 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3315 if (LoadMI && IsGPR) {
3316 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3317 unsigned BytesLoaded = MemOp->getSize().getValue();
3324 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3327 const Register ZReg = AArch64::WZR;
3328 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3331 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3332 .addUse(SubregToRegSrc)
3333 .
addImm(AArch64::sub_32);
3337 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3347 I.eraseFromParent();
3352 if (DstSize == 64) {
3353 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3361 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3362 {&AArch64::GPR64RegClass}, {})
3368 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3372 }
else if (DstSize <= 32) {
3373 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3382 I.eraseFromParent();
3386 case TargetOpcode::G_FREEZE:
3389 case TargetOpcode::G_INTTOPTR:
3394 case TargetOpcode::G_BITCAST:
3402 case TargetOpcode::G_SELECT: {
3404 const Register CondReg = Sel.getCondReg();
3406 const Register FReg = Sel.getFalseReg();
3408 if (tryOptSelect(Sel))
3414 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3419 Sel.eraseFromParent();
3422 case TargetOpcode::G_ICMP: {
3432 auto &PredOp =
I.getOperand(1);
3433 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3437 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3438 AArch64::WZR, InvCC, MIB);
3439 I.eraseFromParent();
3443 case TargetOpcode::G_FCMP: {
3446 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3448 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3450 I.eraseFromParent();
3453 case TargetOpcode::G_VASTART:
3455 : selectVaStartAAPCS(
I, MF, MRI);
3456 case TargetOpcode::G_INTRINSIC:
3457 return selectIntrinsic(
I, MRI);
3458 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3459 return selectIntrinsicWithSideEffects(
I, MRI);
3460 case TargetOpcode::G_IMPLICIT_DEF: {
3461 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3462 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3463 const Register DstReg =
I.getOperand(0).getReg();
3464 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3469 case TargetOpcode::G_BLOCK_ADDR: {
3470 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3471 if (std::optional<uint16_t> BADisc =
3473 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3474 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3483 AArch64::GPR64RegClass, MRI);
3484 I.eraseFromParent();
3488 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3489 I.eraseFromParent();
3492 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3493 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3494 I.getOperand(0).getReg())
3498 I.getOperand(1).getBlockAddress(), 0,
3500 I.eraseFromParent();
3505 case AArch64::G_DUP: {
3512 AArch64::GPRRegBankID)
3514 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3516 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3518 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3520 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3522 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3528 case TargetOpcode::G_BUILD_VECTOR:
3529 return selectBuildVector(
I, MRI);
3530 case TargetOpcode::G_MERGE_VALUES:
3532 case TargetOpcode::G_UNMERGE_VALUES:
3534 case TargetOpcode::G_SHUFFLE_VECTOR:
3535 return selectShuffleVector(
I, MRI);
3536 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3537 return selectExtractElt(
I, MRI);
3538 case TargetOpcode::G_CONCAT_VECTORS:
3539 return selectConcatVectors(
I, MRI);
3540 case TargetOpcode::G_JUMP_TABLE:
3541 return selectJumpTable(
I, MRI);
3542 case TargetOpcode::G_MEMCPY:
3543 case TargetOpcode::G_MEMCPY_INLINE:
3544 case TargetOpcode::G_MEMMOVE:
3545 case TargetOpcode::G_MEMSET:
3546 case TargetOpcode::G_MEMSET_INLINE:
3547 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3548 return selectMOPS(
I, MRI);
3554bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3555 MachineIRBuilderState OldMIBState = MIB.
getState();
3561bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3562 MachineRegisterInfo &MRI) {
3565 case TargetOpcode::G_MEMCPY:
3566 case TargetOpcode::G_MEMCPY_INLINE:
3567 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3569 case TargetOpcode::G_MEMMOVE:
3570 Mopcode = AArch64::MOPSMemoryMovePseudo;
3572 case TargetOpcode::G_MEMSET:
3573 case TargetOpcode::G_MEMSET_INLINE:
3575 Mopcode = AArch64::MOPSMemorySetPseudo;
3588 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3589 const auto &SrcValRegClass =
3590 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3608 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3609 {DstPtrCopy, SizeCopy, SrcValCopy});
3612 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3613 {DstPtrCopy, SrcValCopy, SizeCopy});
3620bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3621 MachineRegisterInfo &MRI) {
3622 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3623 Register JTAddr =
I.getOperand(0).getReg();
3624 unsigned JTI =
I.getOperand(1).getIndex();
3627 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3639 "jump table hardening only supported on MachO/ELF");
3647 I.eraseFromParent();
3654 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3655 {TargetReg, ScratchReg}, {JTAddr,
Index})
3656 .addJumpTableIndex(JTI);
3658 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3659 {
static_cast<int64_t
>(JTI)});
3661 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3662 I.eraseFromParent();
3667bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3668 MachineRegisterInfo &MRI) {
3669 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3670 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3672 Register DstReg =
I.getOperand(0).getReg();
3673 unsigned JTI =
I.getOperand(1).getIndex();
3676 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3679 I.eraseFromParent();
3684bool AArch64InstructionSelector::selectTLSGlobalValue(
3685 MachineInstr &
I, MachineRegisterInfo &MRI) {
3691 const auto &GlobalOp =
I.getOperand(1);
3692 assert(GlobalOp.getOffset() == 0 &&
3693 "Shouldn't have an offset on TLS globals!");
3694 const GlobalValue &GV = *GlobalOp.getGlobal();
3697 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3700 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3701 {LoadGOT.getReg(0)})
3712 assert(Opcode == AArch64::BLR);
3713 Opcode = AArch64::BLRAAZ;
3717 .addUse(AArch64::X0, RegState::Implicit)
3718 .
addDef(AArch64::X0, RegState::Implicit)
3724 I.eraseFromParent();
3728MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3730 MachineIRBuilder &MIRBuilder)
const {
3731 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3733 auto BuildFn = [&](
unsigned SubregIndex) {
3737 .addImm(SubregIndex);
3745 return BuildFn(AArch64::bsub);
3747 return BuildFn(AArch64::hsub);
3749 return BuildFn(AArch64::ssub);
3751 return BuildFn(AArch64::dsub);
3758AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3759 MachineIRBuilder &MIB,
3760 MachineRegisterInfo &MRI)
const {
3761 LLT DstTy = MRI.
getType(DstReg);
3763 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3764 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3768 unsigned SubReg = 0;
3771 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3777 .addReg(SrcReg, {}, SubReg);
3782bool AArch64InstructionSelector::selectMergeValues(
3783 MachineInstr &
I, MachineRegisterInfo &MRI) {
3784 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3785 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3786 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3788 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3790 if (
I.getNumOperands() != 3)
3797 Register DstReg =
I.getOperand(0).getReg();
3798 Register Src1Reg =
I.getOperand(1).getReg();
3799 Register Src2Reg =
I.getOperand(2).getReg();
3800 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3801 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3805 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3806 Src2Reg, 1, RB, MIB);
3811 I.eraseFromParent();
3815 if (RB.
getID() != AArch64::GPRRegBankID)
3821 auto *DstRC = &AArch64::GPR64RegClass;
3823 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3824 TII.get(TargetOpcode::SUBREG_TO_REG))
3826 .
addUse(
I.getOperand(1).getReg())
3827 .
addImm(AArch64::sub_32);
3830 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3831 TII.get(TargetOpcode::SUBREG_TO_REG))
3833 .
addUse(
I.getOperand(2).getReg())
3834 .
addImm(AArch64::sub_32);
3836 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3837 .
addDef(
I.getOperand(0).getReg())
3845 I.eraseFromParent();
3850 const unsigned EltSize) {
3855 CopyOpc = AArch64::DUPi8;
3856 ExtractSubReg = AArch64::bsub;
3859 CopyOpc = AArch64::DUPi16;
3860 ExtractSubReg = AArch64::hsub;
3863 CopyOpc = AArch64::DUPi32;
3864 ExtractSubReg = AArch64::ssub;
3867 CopyOpc = AArch64::DUPi64;
3868 ExtractSubReg = AArch64::dsub;
3872 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3878MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3879 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3880 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3881 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3882 unsigned CopyOpc = 0;
3883 unsigned ExtractSubReg = 0;
3886 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3891 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3893 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3897 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3898 const LLT &VecTy = MRI.
getType(VecReg);
3900 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3902 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3912 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3913 .addReg(VecReg, {}, ExtractSubReg);
3922 MachineInstr *ScalarToVector = emitScalarToVector(
3923 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3924 if (!ScalarToVector)
3929 MachineInstr *LaneCopyMI =
3930 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3938bool AArch64InstructionSelector::selectExtractElt(
3939 MachineInstr &
I, MachineRegisterInfo &MRI) {
3940 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3941 "unexpected opcode!");
3942 Register DstReg =
I.getOperand(0).getReg();
3943 const LLT NarrowTy = MRI.
getType(DstReg);
3944 const Register SrcReg =
I.getOperand(1).getReg();
3945 const LLT WideTy = MRI.
getType(SrcReg);
3947 "source register size too small!");
3948 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
3951 MachineOperand &LaneIdxOp =
I.getOperand(2);
3952 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
3958 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
3960 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3961 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3965 Opcode = AArch64::UMOVvi8;
3968 Opcode = AArch64::UMOVvi16;
3971 Opcode = AArch64::UMOVvi32;
3978 MachineInstr *ScalarToVector = emitScalarToVector(
3979 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
3980 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
3984 I.setDesc(
TII.get(Opcode));
3985 I.getOperand(2).ChangeToImmediate(LaneIdx);
3990 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
3995 I.eraseFromParent();
3999bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4000 MachineInstr &
I, MachineRegisterInfo &MRI) {
4001 unsigned NumElts =
I.getNumOperands() - 1;
4002 Register SrcReg =
I.getOperand(NumElts).getReg();
4003 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4004 const LLT SrcTy = MRI.
getType(SrcReg);
4006 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4008 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4014 const RegisterBank &DstRB =
4016 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4017 Register Dst =
I.getOperand(OpIdx).getReg();
4018 MachineInstr *Extract =
4019 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4023 I.eraseFromParent();
4027bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4028 MachineRegisterInfo &MRI) {
4029 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4030 "unexpected opcode");
4034 AArch64::FPRRegBankID ||
4036 AArch64::FPRRegBankID) {
4037 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4038 "currently unsupported.\n");
4044 unsigned NumElts =
I.getNumOperands() - 1;
4045 Register SrcReg =
I.getOperand(NumElts).getReg();
4046 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4047 const LLT WideTy = MRI.
getType(SrcReg);
4050 "source register size too small!");
4053 return selectSplitVectorUnmerge(
I, MRI);
4057 unsigned CopyOpc = 0;
4058 unsigned ExtractSubReg = 0;
4069 unsigned NumInsertRegs = NumElts - 1;
4075 InsertRegs.
assign(NumInsertRegs, SrcReg);
4084 unsigned SubReg = 0;
4087 assert(Found &&
"expected to find last operand's subeg idx");
4088 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4090 MachineInstr &ImpDefMI =
4091 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4096 MachineInstr &InsMI =
4098 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4115 Register CopyTo =
I.getOperand(0).getReg();
4116 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4117 .addReg(InsertRegs[0], {}, ExtractSubReg);
4121 unsigned LaneIdx = 1;
4122 for (
Register InsReg : InsertRegs) {
4123 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4124 MachineInstr &CopyInst =
4143 I.eraseFromParent();
4147bool AArch64InstructionSelector::selectConcatVectors(
4148 MachineInstr &
I, MachineRegisterInfo &MRI) {
4149 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4150 "Unexpected opcode");
4151 Register Dst =
I.getOperand(0).getReg();
4152 Register Op1 =
I.getOperand(1).getReg();
4153 Register Op2 =
I.getOperand(2).getReg();
4154 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4157 I.eraseFromParent();
4162AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4171MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4172 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4179 RC = &AArch64::FPR128RegClass;
4180 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4183 RC = &AArch64::FPR64RegClass;
4184 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4187 RC = &AArch64::FPR32RegClass;
4188 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4191 RC = &AArch64::FPR16RegClass;
4192 Opc = AArch64::LDRHui;
4195 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4200 MachineInstr *LoadMI =
nullptr;
4201 auto &MF = MIRBuilder.
getMF();
4202 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4203 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4205 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4208 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4212 .addConstantPoolIndex(
4228static std::pair<unsigned, unsigned>
4230 unsigned Opc, SubregIdx;
4231 if (RB.
getID() == AArch64::GPRRegBankID) {
4233 Opc = AArch64::INSvi8gpr;
4234 SubregIdx = AArch64::bsub;
4235 }
else if (EltSize == 16) {
4236 Opc = AArch64::INSvi16gpr;
4237 SubregIdx = AArch64::ssub;
4238 }
else if (EltSize == 32) {
4239 Opc = AArch64::INSvi32gpr;
4240 SubregIdx = AArch64::ssub;
4241 }
else if (EltSize == 64) {
4242 Opc = AArch64::INSvi64gpr;
4243 SubregIdx = AArch64::dsub;
4249 Opc = AArch64::INSvi8lane;
4250 SubregIdx = AArch64::bsub;
4251 }
else if (EltSize == 16) {
4252 Opc = AArch64::INSvi16lane;
4253 SubregIdx = AArch64::hsub;
4254 }
else if (EltSize == 32) {
4255 Opc = AArch64::INSvi32lane;
4256 SubregIdx = AArch64::ssub;
4257 }
else if (EltSize == 64) {
4258 Opc = AArch64::INSvi64lane;
4259 SubregIdx = AArch64::dsub;
4264 return std::make_pair(
Opc, SubregIdx);
4267MachineInstr *AArch64InstructionSelector::emitInstr(
4268 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4269 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4270 const ComplexRendererFns &RenderFns)
const {
4271 assert(Opcode &&
"Expected an opcode?");
4273 "Function should only be used to produce selected instructions!");
4274 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4276 for (
auto &Fn : *RenderFns)
4282MachineInstr *AArch64InstructionSelector::emitAddSub(
4283 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4285 MachineIRBuilder &MIRBuilder)
const {
4287 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4291 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4292 bool Is32Bit =
Size == 32;
4295 if (
auto Fns = selectArithImmed(
RHS))
4296 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4300 if (
auto Fns = selectNegArithImmed(
RHS))
4301 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4305 if (
auto Fns = selectArithExtendedRegister(
RHS))
4306 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4310 if (
auto Fns = selectShiftedRegister(
RHS))
4311 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4313 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4318AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4319 MachineOperand &
RHS,
4320 MachineIRBuilder &MIRBuilder)
const {
4321 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4322 {{AArch64::ADDXri, AArch64::ADDWri},
4323 {AArch64::ADDXrs, AArch64::ADDWrs},
4324 {AArch64::ADDXrr, AArch64::ADDWrr},
4325 {AArch64::SUBXri, AArch64::SUBWri},
4326 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4327 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4331AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4332 MachineOperand &
RHS,
4333 MachineIRBuilder &MIRBuilder)
const {
4334 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4335 {{AArch64::ADDSXri, AArch64::ADDSWri},
4336 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4337 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4338 {AArch64::SUBSXri, AArch64::SUBSWri},
4339 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4340 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4344AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4345 MachineOperand &
RHS,
4346 MachineIRBuilder &MIRBuilder)
const {
4347 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4348 {{AArch64::SUBSXri, AArch64::SUBSWri},
4349 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4350 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4351 {AArch64::ADDSXri, AArch64::ADDSWri},
4352 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4353 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4357AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4358 MachineOperand &
RHS,
4359 MachineIRBuilder &MIRBuilder)
const {
4360 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4361 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4363 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4364 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4368AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4369 MachineOperand &
RHS,
4370 MachineIRBuilder &MIRBuilder)
const {
4371 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4372 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4374 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4375 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4379AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4380 MachineIRBuilder &MIRBuilder)
const {
4383 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4388AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4389 MachineIRBuilder &MIRBuilder)
const {
4392 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4397AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4398 MachineIRBuilder &MIRBuilder)
const {
4399 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4403 bool Is32Bit = (
RegSize == 32);
4404 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4405 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4406 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4410 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4413 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4420 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4421 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4422 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4425MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4426 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4427 MachineIRBuilder &MIRBuilder)
const {
4428 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4435 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4437 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4439 return emitCMP(
LHS,
RHS, MIRBuilder);
4442MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4444 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4448 "Expected a 32-bit scalar register?");
4450 const Register ZReg = AArch64::WZR;
4455 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4461 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4462 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4463 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4468MachineInstr *AArch64InstructionSelector::emitFPCompare(
4470 std::optional<CmpInst::Predicate> Pred)
const {
4471 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4476 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4487 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4491 ShouldUseImm =
true;
4495 unsigned CmpOpcTbl[2][3] = {
4496 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4497 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4499 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4511MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4513 MachineIRBuilder &MIRBuilder)
const {
4520 const LLT Op1Ty = MRI.
getType(Op1);
4521 const LLT Op2Ty = MRI.
getType(Op2);
4523 if (Op1Ty != Op2Ty) {
4524 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4527 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4530 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4541 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4545 MachineInstr *WidenedOp1 =
4546 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4547 MachineInstr *WidenedOp2 =
4548 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4549 if (!WidenedOp1 || !WidenedOp2) {
4550 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4555 unsigned InsertOpc, InsSubRegIdx;
4556 std::tie(InsertOpc, InsSubRegIdx) =
4574 MachineIRBuilder &MIRBuilder)
const {
4575 auto &MRI = *MIRBuilder.
getMRI();
4581 Size =
TRI.getRegSizeInBits(*RC);
4585 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4586 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4587 unsigned Opc = OpcTable[
Size == 64];
4588 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4593MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4595 MachineRegisterInfo *MRI = MIB.
getMRI();
4596 unsigned Opcode =
I.getOpcode();
4600 bool NeedsNegatedCarry =
4601 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4610 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4611 if (SrcMI ==
I.getPrevNode()) {
4613 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4614 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4615 CarrySrcMI->isUnsigned() &&
4616 CarrySrcMI->getCarryOutReg() == CarryReg &&
4617 selectAndRestoreState(*SrcMI))
4624 if (NeedsNegatedCarry) {
4627 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4631 auto Fns = select12BitValueWithLeftShift(1);
4632 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4635bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4636 MachineRegisterInfo &MRI) {
4641 emitCarryIn(
I, CarryInMI->getCarryInReg());
4645 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4646 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4648 Register CarryOutReg = CarryMI.getCarryOutReg();
4657 emitCSINC(CarryOutReg, ZReg, ZReg,
4658 getInvertedCondCode(OpAndCC.second), MIB);
4661 I.eraseFromParent();
4665std::pair<MachineInstr *, AArch64CC::CondCode>
4666AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4667 MachineOperand &
LHS,
4668 MachineOperand &
RHS,
4669 MachineIRBuilder &MIRBuilder)
const {
4673 case TargetOpcode::G_SADDO:
4675 case TargetOpcode::G_UADDO:
4677 case TargetOpcode::G_SSUBO:
4679 case TargetOpcode::G_USUBO:
4681 case TargetOpcode::G_SADDE:
4683 case TargetOpcode::G_UADDE:
4685 case TargetOpcode::G_SSUBE:
4687 case TargetOpcode::G_USUBE:
4708 unsigned Depth = 0) {
4715 MustBeFirst =
false;
4721 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4722 bool IsOR = Opcode == TargetOpcode::G_OR;
4734 if (MustBeFirstL && MustBeFirstR)
4740 if (!CanNegateL && !CanNegateR)
4744 CanNegate = WillNegate && CanNegateL && CanNegateR;
4747 MustBeFirst = !CanNegate;
4749 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4752 MustBeFirst = MustBeFirstL || MustBeFirstR;
4759MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4762 MachineIRBuilder &MIB)
const {
4763 auto &MRI = *MIB.
getMRI();
4766 std::optional<ValueAndVReg>
C;
4770 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4771 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4772 else if (
C->Value.ule(31))
4773 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4775 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4781 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4782 CCmpOpc = AArch64::FCCMPHrr;
4785 CCmpOpc = AArch64::FCCMPSrr;
4788 CCmpOpc = AArch64::FCCMPDrr;
4798 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4799 CCmp.
addImm(
C->Value.getZExtValue());
4800 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4801 CCmp.
addImm(
C->Value.abs().getZExtValue());
4809MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4813 auto &MRI = *MIB.
getMRI();
4831 MachineInstr *ExtraCmp;
4833 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4845 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4846 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4847 Cmp->getOperand(3).getReg(), MIB);
4854 bool IsOR = Opcode == TargetOpcode::G_OR;
4860 assert(ValidL &&
"Valid conjunction/disjunction tree");
4867 assert(ValidR &&
"Valid conjunction/disjunction tree");
4872 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4881 bool NegateAfterAll;
4882 if (Opcode == TargetOpcode::G_OR) {
4885 assert(CanNegateR &&
"at least one side must be negatable");
4886 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4890 NegateAfterR =
true;
4893 NegateR = CanNegateR;
4894 NegateAfterR = !CanNegateR;
4897 NegateAfterAll = !Negate;
4899 assert(Opcode == TargetOpcode::G_AND &&
4900 "Valid conjunction/disjunction tree");
4901 assert(!Negate &&
"Valid conjunction/disjunction tree");
4905 NegateAfterR =
false;
4906 NegateAfterAll =
false;
4911 MachineInstr *CmpR =
4922MachineInstr *AArch64InstructionSelector::emitConjunction(
4924 bool DummyCanNegate;
4925 bool DummyMustBeFirst;
4932bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4933 MachineInstr &CondMI) {
4944bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4945 MachineRegisterInfo &MRI = *MIB.
getMRI();
4964 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
4973 if (UI.getOpcode() != TargetOpcode::G_SELECT)
4979 unsigned CondOpc = CondDef->
getOpcode();
4980 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
4981 if (tryOptSelectConjunction(
I, *CondDef))
4987 if (CondOpc == TargetOpcode::G_ICMP) {
5016 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5017 I.getOperand(3).getReg(), CondCode, MIB);
5018 I.eraseFromParent();
5022MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5023 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5024 MachineIRBuilder &MIRBuilder)
const {
5026 "Unexpected MachineOperand");
5027 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5050 if (
isCMN(RHSDef,
P, MRI))
5065 if (
isCMN(LHSDef,
P, MRI)) {
5082 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5085 if (!ValAndVReg || ValAndVReg->Value != 0)
5095bool AArch64InstructionSelector::selectShuffleVector(
5096 MachineInstr &
I, MachineRegisterInfo &MRI) {
5097 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5098 Register Src1Reg =
I.getOperand(1).getReg();
5099 Register Src2Reg =
I.getOperand(2).getReg();
5100 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5102 "Expected equal shuffle types during selection");
5111 SmallVector<int> NewMask;
5112 bool FirstUsed =
false;
5113 bool SecondUsed =
false;
5114 for (
int M : Mask) {
5116 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5119 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5124 FirstUsed |=
M < NumElts;
5125 SecondUsed |=
M >= NumElts;
5126 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5135 for (
int &M : NewMask) {
5137 assert(M >= ByteLanes && M < 2 * ByteLanes);
5147 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5148 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5161 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5168 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5172 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5177 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5178 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5180 I.eraseFromParent();
5185 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5188 I.eraseFromParent();
5196 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5199 I.eraseFromParent();
5203MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5205 unsigned LaneIdx,
const RegisterBank &RB,
5206 MachineIRBuilder &MIRBuilder)
const {
5207 MachineInstr *InsElt =
nullptr;
5209 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5218 if (RB.
getID() == AArch64::FPRRegBankID) {
5219 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5222 .
addUse(InsSub->getOperand(0).getReg())
5234bool AArch64InstructionSelector::selectUSMovFromExtend(
5235 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5236 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5237 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5238 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5240 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5241 const Register DefReg =
MI.getOperand(0).getReg();
5242 const LLT DstTy = MRI.
getType(DefReg);
5245 if (DstSize != 32 && DstSize != 64)
5248 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5249 MI.getOperand(1).getReg(), MRI);
5255 const LLT VecTy = MRI.
getType(Src0);
5260 const MachineInstr *ScalarToVector = emitScalarToVector(
5261 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5262 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5268 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5270 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5272 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5274 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5276 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5284 MachineInstr *ExtI =
nullptr;
5285 if (DstSize == 64 && !IsSigned) {
5287 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5288 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5290 .
addImm(AArch64::sub_32);
5293 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5296 MI.eraseFromParent();
5300MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5301 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5303 if (DstSize == 128) {
5304 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5306 Op = AArch64::MOVIv16b_ns;
5308 Op = AArch64::MOVIv8b_ns;
5311 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5315 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5322MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5323 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5327 if (DstSize == 128) {
5328 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5330 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5332 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5335 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5352MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5353 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5357 if (DstSize == 128) {
5358 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5360 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5362 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5365 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5388MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5389 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5392 if (DstSize == 128) {
5393 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5395 Op = AArch64::MOVIv2d_ns;
5397 Op = AArch64::MOVID;
5400 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5403 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5410MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5411 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5415 if (DstSize == 128) {
5416 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5418 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5420 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5423 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5440MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5441 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5444 bool IsWide =
false;
5445 if (DstSize == 128) {
5446 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5448 Op = AArch64::FMOVv4f32_ns;
5451 Op = AArch64::FMOVv2f32_ns;
5454 uint64_t Val =
Bits.zextOrTrunc(64).getZExtValue();
5460 Op = AArch64::FMOVv2f64_ns;
5464 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5469bool AArch64InstructionSelector::selectIndexedExtLoad(
5470 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5473 Register WriteBack = ExtLd.getWritebackReg();
5478 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5479 bool IsPre = ExtLd.isPre();
5481 unsigned InsertIntoSubReg = 0;
5487 if ((IsSExt && IsFPR) || Ty.
isVector())
5495 if (MemSizeBits == 8) {
5498 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5500 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5501 NewLdDstTy = IsDst64 ? s64 : s32;
5503 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5504 InsertIntoSubReg = AArch64::bsub;
5507 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5508 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5511 }
else if (MemSizeBits == 16) {
5514 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5516 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5517 NewLdDstTy = IsDst64 ? s64 : s32;
5519 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5520 InsertIntoSubReg = AArch64::hsub;
5523 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5524 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5527 }
else if (MemSizeBits == 32) {
5529 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5532 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5533 InsertIntoSubReg = AArch64::ssub;
5536 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5537 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5549 .addImm(Cst->getSExtValue());
5554 if (InsertIntoSubReg) {
5556 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5557 .addUse(LdMI.getReg(1))
5558 .
addImm(InsertIntoSubReg);
5561 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5568 MI.eraseFromParent();
5573bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5574 MachineRegisterInfo &MRI) {
5577 Register WriteBack = Ld.getWritebackReg();
5581 "Unexpected type for indexed load");
5582 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5585 return selectIndexedExtLoad(
MI, MRI);
5589 static constexpr unsigned GPROpcodes[] = {
5590 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5592 static constexpr unsigned FPROpcodes[] = {
5593 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5596 ? FPROpcodes[
Log2_32(MemSize)]
5597 : GPROpcodes[
Log2_32(MemSize)];
5600 static constexpr unsigned GPROpcodes[] = {
5601 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5603 static constexpr unsigned FPROpcodes[] = {
5604 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5605 AArch64::LDRDpost, AArch64::LDRQpost};
5607 ? FPROpcodes[
Log2_32(MemSize)]
5608 : GPROpcodes[
Log2_32(MemSize)];
5618 MI.eraseFromParent();
5622bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5623 MachineRegisterInfo &MRI) {
5629 "Unexpected type for indexed store");
5631 LocationSize MemSize =
I.getMMO().getSize();
5632 unsigned MemSizeInBytes = MemSize.
getValue();
5634 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5635 "Unexpected indexed store size");
5636 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5640 static constexpr unsigned GPROpcodes[] = {
5641 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5643 static constexpr unsigned FPROpcodes[] = {
5644 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5648 Opc = FPROpcodes[MemSizeLog2];
5650 Opc = GPROpcodes[MemSizeLog2];
5652 static constexpr unsigned GPROpcodes[] = {
5653 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5655 static constexpr unsigned FPROpcodes[] = {
5656 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5657 AArch64::STRDpost, AArch64::STRQpost};
5660 Opc = FPROpcodes[MemSizeLog2];
5662 Opc = GPROpcodes[MemSizeLog2];
5670 Str.cloneMemRefs(
I);
5672 I.eraseFromParent();
5677AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5678 MachineIRBuilder &MIRBuilder,
5679 MachineRegisterInfo &MRI) {
5682 assert((DstSize == 64 || DstSize == 128) &&
5683 "Unexpected vector constant size");
5686 if (DstSize == 128) {
5688 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5693 if (DstSize == 64) {
5696 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5699 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5706 APInt SplatValueAsInt =
5709 : SplatValue->getUniqueInteger();
5712 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5713 MachineInstr *NewOp;
5737 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5741 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5742 unsigned NegOpc) -> MachineInstr * {
5745 APInt NegBits(DstSize, 0);
5746 unsigned NumElts = DstSize / NumBits;
5747 for (
unsigned i = 0; i < NumElts; i++)
5748 NegBits |= Neg << (NumBits * i);
5749 NegBits = DefBits ^ NegBits;
5753 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5755 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5757 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5762 if ((R = TryWithFNeg(DefBits, 32,
5763 DstSize == 64 ? AArch64::FNEGv2f32
5764 : AArch64::FNEGv4f32)) ||
5765 (R = TryWithFNeg(DefBits, 64,
5766 DstSize == 64 ? AArch64::FNEGDr
5767 : AArch64::FNEGv2f64)) ||
5768 (STI.hasFullFP16() &&
5769 (R = TryWithFNeg(DefBits, 16,
5770 DstSize == 64 ? AArch64::FNEGv4f16
5771 : AArch64::FNEGv8f16))))
5777 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5781 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5783 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5787bool AArch64InstructionSelector::tryOptConstantBuildVec(
5788 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5789 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5791 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5797 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5798 Register OpReg =
I.getOperand(Idx).getReg();
5807 std::move(AnyConst->Value)));
5820 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5822 I.eraseFromParent();
5826bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5827 MachineInstr &
I, MachineRegisterInfo &MRI) {
5832 Register Dst =
I.getOperand(0).getReg();
5833 Register EltReg =
I.getOperand(1).getReg();
5834 LLT EltTy = MRI.
getType(EltReg);
5837 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5842 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5850 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5855 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5858 I.eraseFromParent();
5863bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5864 MachineRegisterInfo &MRI) {
5865 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5868 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5869 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5872 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5874 if (tryOptBuildVecToSubregToReg(
I, MRI))
5877 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5879 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5882 MachineInstr *ScalarToVec =
5884 I.getOperand(1).getReg(), MIB);
5893 MachineInstr *PrevMI = ScalarToVec;
5894 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5897 Register OpReg =
I.getOperand(i).getReg();
5900 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5907 if (DstSize < 128) {
5910 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5913 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5918 unsigned SubReg = 0;
5921 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5922 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5928 Register DstReg =
I.getOperand(0).getReg();
5930 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5931 MachineOperand &RegOp =
I.getOperand(1);
5951 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5953 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5962bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5965 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5967 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5968 auto &MRI = *MIB.
getMRI();
5969 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
5972 "Destination must be 64 bits or 128 bits?");
5973 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5974 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5979 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5980 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5981 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5982 .addReg(SelectedLoadDst, {}, SubReg + Idx);
5991bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
5992 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
5993 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5995 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5996 auto &MRI = *MIB.
getMRI();
5997 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6000 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6002 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6003 [](
auto MO) { return MO.getReg(); });
6007 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6022 .
addImm(LaneNo->getZExtValue())
6026 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6027 unsigned SubReg = AArch64::qsub0;
6028 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6029 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6030 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6031 : DstOp(
I.getOperand(Idx).
getReg())},
6033 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6038 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6044void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6047 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6048 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6049 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6052 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6053 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6062bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6063 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6064 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6065 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6069 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6070 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6074 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6084 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6087 .
addImm(LaneNo->getZExtValue())
6094bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6095 MachineInstr &
I, MachineRegisterInfo &MRI) {
6108 case Intrinsic::aarch64_ldxp:
6109 case Intrinsic::aarch64_ldaxp: {
6111 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6112 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6118 case Intrinsic::aarch64_neon_ld1x2: {
6119 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6122 Opc = AArch64::LD1Twov8b;
6124 Opc = AArch64::LD1Twov16b;
6126 Opc = AArch64::LD1Twov4h;
6128 Opc = AArch64::LD1Twov8h;
6130 Opc = AArch64::LD1Twov2s;
6132 Opc = AArch64::LD1Twov4s;
6134 Opc = AArch64::LD1Twov2d;
6135 else if (Ty ==
S64 || Ty == P0)
6136 Opc = AArch64::LD1Twov1d;
6139 selectVectorLoadIntrinsic(
Opc, 2,
I);
6142 case Intrinsic::aarch64_neon_ld1x3: {
6143 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6146 Opc = AArch64::LD1Threev8b;
6148 Opc = AArch64::LD1Threev16b;
6150 Opc = AArch64::LD1Threev4h;
6152 Opc = AArch64::LD1Threev8h;
6154 Opc = AArch64::LD1Threev2s;
6156 Opc = AArch64::LD1Threev4s;
6158 Opc = AArch64::LD1Threev2d;
6159 else if (Ty ==
S64 || Ty == P0)
6160 Opc = AArch64::LD1Threev1d;
6163 selectVectorLoadIntrinsic(
Opc, 3,
I);
6166 case Intrinsic::aarch64_neon_ld1x4: {
6167 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6170 Opc = AArch64::LD1Fourv8b;
6172 Opc = AArch64::LD1Fourv16b;
6174 Opc = AArch64::LD1Fourv4h;
6176 Opc = AArch64::LD1Fourv8h;
6178 Opc = AArch64::LD1Fourv2s;
6180 Opc = AArch64::LD1Fourv4s;
6182 Opc = AArch64::LD1Fourv2d;
6183 else if (Ty ==
S64 || Ty == P0)
6184 Opc = AArch64::LD1Fourv1d;
6187 selectVectorLoadIntrinsic(
Opc, 4,
I);
6190 case Intrinsic::aarch64_neon_ld2: {
6191 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6194 Opc = AArch64::LD2Twov8b;
6196 Opc = AArch64::LD2Twov16b;
6198 Opc = AArch64::LD2Twov4h;
6200 Opc = AArch64::LD2Twov8h;
6202 Opc = AArch64::LD2Twov2s;
6204 Opc = AArch64::LD2Twov4s;
6206 Opc = AArch64::LD2Twov2d;
6207 else if (Ty ==
S64 || Ty == P0)
6208 Opc = AArch64::LD1Twov1d;
6211 selectVectorLoadIntrinsic(
Opc, 2,
I);
6214 case Intrinsic::aarch64_neon_ld2lane: {
6215 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6218 Opc = AArch64::LD2i8;
6220 Opc = AArch64::LD2i16;
6222 Opc = AArch64::LD2i32;
6225 Opc = AArch64::LD2i64;
6228 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6232 case Intrinsic::aarch64_neon_ld2r: {
6233 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6236 Opc = AArch64::LD2Rv8b;
6238 Opc = AArch64::LD2Rv16b;
6240 Opc = AArch64::LD2Rv4h;
6242 Opc = AArch64::LD2Rv8h;
6244 Opc = AArch64::LD2Rv2s;
6246 Opc = AArch64::LD2Rv4s;
6248 Opc = AArch64::LD2Rv2d;
6249 else if (Ty ==
S64 || Ty == P0)
6250 Opc = AArch64::LD2Rv1d;
6253 selectVectorLoadIntrinsic(
Opc, 2,
I);
6256 case Intrinsic::aarch64_neon_ld3: {
6257 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6260 Opc = AArch64::LD3Threev8b;
6262 Opc = AArch64::LD3Threev16b;
6264 Opc = AArch64::LD3Threev4h;
6266 Opc = AArch64::LD3Threev8h;
6268 Opc = AArch64::LD3Threev2s;
6270 Opc = AArch64::LD3Threev4s;
6272 Opc = AArch64::LD3Threev2d;
6273 else if (Ty ==
S64 || Ty == P0)
6274 Opc = AArch64::LD1Threev1d;
6277 selectVectorLoadIntrinsic(
Opc, 3,
I);
6280 case Intrinsic::aarch64_neon_ld3lane: {
6281 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6284 Opc = AArch64::LD3i8;
6286 Opc = AArch64::LD3i16;
6288 Opc = AArch64::LD3i32;
6291 Opc = AArch64::LD3i64;
6294 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6298 case Intrinsic::aarch64_neon_ld3r: {
6299 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6302 Opc = AArch64::LD3Rv8b;
6304 Opc = AArch64::LD3Rv16b;
6306 Opc = AArch64::LD3Rv4h;
6308 Opc = AArch64::LD3Rv8h;
6310 Opc = AArch64::LD3Rv2s;
6312 Opc = AArch64::LD3Rv4s;
6314 Opc = AArch64::LD3Rv2d;
6315 else if (Ty ==
S64 || Ty == P0)
6316 Opc = AArch64::LD3Rv1d;
6319 selectVectorLoadIntrinsic(
Opc, 3,
I);
6322 case Intrinsic::aarch64_neon_ld4: {
6323 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6326 Opc = AArch64::LD4Fourv8b;
6328 Opc = AArch64::LD4Fourv16b;
6330 Opc = AArch64::LD4Fourv4h;
6332 Opc = AArch64::LD4Fourv8h;
6334 Opc = AArch64::LD4Fourv2s;
6336 Opc = AArch64::LD4Fourv4s;
6338 Opc = AArch64::LD4Fourv2d;
6339 else if (Ty ==
S64 || Ty == P0)
6340 Opc = AArch64::LD1Fourv1d;
6343 selectVectorLoadIntrinsic(
Opc, 4,
I);
6346 case Intrinsic::aarch64_neon_ld4lane: {
6347 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6350 Opc = AArch64::LD4i8;
6352 Opc = AArch64::LD4i16;
6354 Opc = AArch64::LD4i32;
6357 Opc = AArch64::LD4i64;
6360 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6364 case Intrinsic::aarch64_neon_ld4r: {
6365 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6368 Opc = AArch64::LD4Rv8b;
6370 Opc = AArch64::LD4Rv16b;
6372 Opc = AArch64::LD4Rv4h;
6374 Opc = AArch64::LD4Rv8h;
6376 Opc = AArch64::LD4Rv2s;
6378 Opc = AArch64::LD4Rv4s;
6380 Opc = AArch64::LD4Rv2d;
6381 else if (Ty ==
S64 || Ty == P0)
6382 Opc = AArch64::LD4Rv1d;
6385 selectVectorLoadIntrinsic(
Opc, 4,
I);
6388 case Intrinsic::aarch64_neon_st1x2: {
6389 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6392 Opc = AArch64::ST1Twov8b;
6394 Opc = AArch64::ST1Twov16b;
6396 Opc = AArch64::ST1Twov4h;
6398 Opc = AArch64::ST1Twov8h;
6400 Opc = AArch64::ST1Twov2s;
6402 Opc = AArch64::ST1Twov4s;
6404 Opc = AArch64::ST1Twov2d;
6405 else if (Ty ==
S64 || Ty == P0)
6406 Opc = AArch64::ST1Twov1d;
6409 selectVectorStoreIntrinsic(
I, 2,
Opc);
6412 case Intrinsic::aarch64_neon_st1x3: {
6413 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6416 Opc = AArch64::ST1Threev8b;
6418 Opc = AArch64::ST1Threev16b;
6420 Opc = AArch64::ST1Threev4h;
6422 Opc = AArch64::ST1Threev8h;
6424 Opc = AArch64::ST1Threev2s;
6426 Opc = AArch64::ST1Threev4s;
6428 Opc = AArch64::ST1Threev2d;
6429 else if (Ty ==
S64 || Ty == P0)
6430 Opc = AArch64::ST1Threev1d;
6433 selectVectorStoreIntrinsic(
I, 3,
Opc);
6436 case Intrinsic::aarch64_neon_st1x4: {
6437 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6440 Opc = AArch64::ST1Fourv8b;
6442 Opc = AArch64::ST1Fourv16b;
6444 Opc = AArch64::ST1Fourv4h;
6446 Opc = AArch64::ST1Fourv8h;
6448 Opc = AArch64::ST1Fourv2s;
6450 Opc = AArch64::ST1Fourv4s;
6452 Opc = AArch64::ST1Fourv2d;
6453 else if (Ty ==
S64 || Ty == P0)
6454 Opc = AArch64::ST1Fourv1d;
6457 selectVectorStoreIntrinsic(
I, 4,
Opc);
6460 case Intrinsic::aarch64_neon_st2: {
6461 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6464 Opc = AArch64::ST2Twov8b;
6466 Opc = AArch64::ST2Twov16b;
6468 Opc = AArch64::ST2Twov4h;
6470 Opc = AArch64::ST2Twov8h;
6472 Opc = AArch64::ST2Twov2s;
6474 Opc = AArch64::ST2Twov4s;
6476 Opc = AArch64::ST2Twov2d;
6477 else if (Ty ==
S64 || Ty == P0)
6478 Opc = AArch64::ST1Twov1d;
6481 selectVectorStoreIntrinsic(
I, 2,
Opc);
6484 case Intrinsic::aarch64_neon_st3: {
6485 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6488 Opc = AArch64::ST3Threev8b;
6490 Opc = AArch64::ST3Threev16b;
6492 Opc = AArch64::ST3Threev4h;
6494 Opc = AArch64::ST3Threev8h;
6496 Opc = AArch64::ST3Threev2s;
6498 Opc = AArch64::ST3Threev4s;
6500 Opc = AArch64::ST3Threev2d;
6501 else if (Ty ==
S64 || Ty == P0)
6502 Opc = AArch64::ST1Threev1d;
6505 selectVectorStoreIntrinsic(
I, 3,
Opc);
6508 case Intrinsic::aarch64_neon_st4: {
6509 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6512 Opc = AArch64::ST4Fourv8b;
6514 Opc = AArch64::ST4Fourv16b;
6516 Opc = AArch64::ST4Fourv4h;
6518 Opc = AArch64::ST4Fourv8h;
6520 Opc = AArch64::ST4Fourv2s;
6522 Opc = AArch64::ST4Fourv4s;
6524 Opc = AArch64::ST4Fourv2d;
6525 else if (Ty ==
S64 || Ty == P0)
6526 Opc = AArch64::ST1Fourv1d;
6529 selectVectorStoreIntrinsic(
I, 4,
Opc);
6532 case Intrinsic::aarch64_neon_st2lane: {
6533 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6536 Opc = AArch64::ST2i8;
6538 Opc = AArch64::ST2i16;
6540 Opc = AArch64::ST2i32;
6543 Opc = AArch64::ST2i64;
6546 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6550 case Intrinsic::aarch64_neon_st3lane: {
6551 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6554 Opc = AArch64::ST3i8;
6556 Opc = AArch64::ST3i16;
6558 Opc = AArch64::ST3i32;
6561 Opc = AArch64::ST3i64;
6564 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6568 case Intrinsic::aarch64_neon_st4lane: {
6569 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6572 Opc = AArch64::ST4i8;
6574 Opc = AArch64::ST4i16;
6576 Opc = AArch64::ST4i32;
6579 Opc = AArch64::ST4i64;
6582 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6586 case Intrinsic::aarch64_mops_memset_tag: {
6599 Register DstDef =
I.getOperand(0).getReg();
6601 Register DstUse =
I.getOperand(2).getReg();
6602 Register ValUse =
I.getOperand(3).getReg();
6603 Register SizeUse =
I.getOperand(4).getReg();
6610 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6611 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6616 case Intrinsic::ptrauth_resign_load_relative: {
6617 Register DstReg =
I.getOperand(0).getReg();
6618 Register ValReg =
I.getOperand(2).getReg();
6619 uint64_t AUTKey =
I.getOperand(3).getImm();
6620 Register AUTDisc =
I.getOperand(4).getReg();
6621 uint64_t PACKey =
I.getOperand(5).getImm();
6622 Register PACDisc =
I.getOperand(6).getReg();
6623 int64_t Addend =
I.getOperand(7).getImm();
6626 uint16_t AUTConstDiscC = 0;
6627 std::tie(AUTConstDiscC, AUTAddrDisc) =
6631 uint16_t PACConstDiscC = 0;
6632 std::tie(PACConstDiscC, PACAddrDisc) =
6635 MIB.
buildCopy({AArch64::X16}, {ValReg});
6649 I.eraseFromParent();
6654 I.eraseFromParent();
6658bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6659 MachineRegisterInfo &MRI) {
6665 case Intrinsic::ptrauth_resign: {
6666 Register DstReg =
I.getOperand(0).getReg();
6667 Register ValReg =
I.getOperand(2).getReg();
6668 uint64_t AUTKey =
I.getOperand(3).getImm();
6669 Register AUTDisc =
I.getOperand(4).getReg();
6670 uint64_t PACKey =
I.getOperand(5).getImm();
6671 Register PACDisc =
I.getOperand(6).getReg();
6674 uint16_t AUTConstDiscC = 0;
6675 std::tie(AUTConstDiscC, AUTAddrDisc) =
6679 uint16_t PACConstDiscC = 0;
6680 std::tie(PACConstDiscC, PACAddrDisc) =
6683 MIB.
buildCopy({AArch64::X16}, {ValReg});
6684 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6696 I.eraseFromParent();
6699 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6700 Register DstReg =
I.getOperand(0).getReg();
6701 Register ValReg =
I.getOperand(2).getReg();
6702 uint64_t AUTKey =
I.getOperand(3).getImm();
6703 Register AUTDisc =
I.getOperand(4).getReg();
6704 Register AUTPC =
I.getOperand(5).getReg();
6705 uint64_t PACKey =
I.getOperand(6).getImm();
6706 Register PACDisc =
I.getOperand(7).getReg();
6709 "auth_with_pc_and_resign only supports IA and IB keys");
6711 uint16_t PACConstDiscC = 0;
6713 std::tie(PACConstDiscC, PACAddrDisc) =
6716 if (PACAddrDisc == AArch64::NoRegister)
6717 PACAddrDisc = AArch64::XZR;
6719 MIB.
buildCopy({AArch64::X17}, {ValReg});
6720 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6732 I.eraseFromParent();
6735 case Intrinsic::ptrauth_auth: {
6736 Register DstReg =
I.getOperand(0).getReg();
6737 Register ValReg =
I.getOperand(2).getReg();
6738 uint64_t AUTKey =
I.getOperand(3).getImm();
6739 Register AUTDisc =
I.getOperand(4).getReg();
6742 uint16_t AUTConstDiscC = 0;
6743 std::tie(AUTConstDiscC, AUTAddrDisc) =
6747 MIB.
buildCopy({AArch64::X16}, {ValReg});
6748 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6769 I.eraseFromParent();
6772 case Intrinsic::frameaddress:
6773 case Intrinsic::returnaddress: {
6777 unsigned Depth =
I.getOperand(2).getImm();
6778 Register DstReg =
I.getOperand(0).getReg();
6781 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6782 if (!MFReturnAddr) {
6787 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6790 if (STI.hasPAuth()) {
6791 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6798 I.eraseFromParent();
6807 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6809 FrameAddr = NextFrame;
6812 if (IntrinID == Intrinsic::frameaddress)
6817 if (STI.hasPAuth()) {
6819 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6820 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6829 I.eraseFromParent();
6832 case Intrinsic::aarch64_neon_tbl2:
6833 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6835 case Intrinsic::aarch64_neon_tbl3:
6836 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6839 case Intrinsic::aarch64_neon_tbl4:
6840 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6842 case Intrinsic::aarch64_neon_tbx2:
6843 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6845 case Intrinsic::aarch64_neon_tbx3:
6846 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6848 case Intrinsic::aarch64_neon_tbx4:
6849 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6851 case Intrinsic::swift_async_context_addr:
6852 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6859 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6860 I.eraseFromParent();
6895bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6896 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6897 Register DefReg =
I.getOperand(0).getReg();
6898 Register Addr =
I.getOperand(1).getReg();
6899 uint64_t
Key =
I.getOperand(2).getImm();
6900 Register AddrDisc =
I.getOperand(3).getReg();
6901 uint64_t Disc =
I.getOperand(4).getImm();
6911 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6927 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6939 const GlobalValue *GV;
6950 MachineIRBuilder MIB(
I);
6956 "unsupported non-GOT op flags on ptrauth global reference");
6958 "unsupported non-GOT reference to weak ptrauth global");
6961 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6968 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6969 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6970 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6973 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6978 I.eraseFromParent();
6990 "unsupported non-zero offset in weak ptrauth global reference");
6995 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6996 .addGlobalAddress(GV,
Offset)
7001 I.eraseFromParent();
7005void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7006 MachineRegisterInfo &MRI,
7007 unsigned NumVec,
unsigned Opc1,
7008 unsigned Opc2,
bool isExt) {
7009 Register DstReg =
I.getOperand(0).getReg();
7014 for (
unsigned i = 0; i < NumVec; i++)
7015 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7018 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7019 MachineInstrBuilder
Instr;
7026 I.eraseFromParent();
7029InstructionSelector::ComplexRendererFns
7030AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7032 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7033 return std::nullopt;
7034 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7035 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7038InstructionSelector::ComplexRendererFns
7039AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7041 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7042 return std::nullopt;
7043 uint64_t Enc = 31 - *MaybeImmed;
7044 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7047InstructionSelector::ComplexRendererFns
7048AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7050 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7051 return std::nullopt;
7052 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7053 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7056InstructionSelector::ComplexRendererFns
7057AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7059 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7060 return std::nullopt;
7061 uint64_t Enc = 63 - *MaybeImmed;
7062 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7070InstructionSelector::ComplexRendererFns
7071AArch64InstructionSelector::select12BitValueWithLeftShift(
7072 uint64_t Immed)
const {
7074 if (Immed >> 12 == 0) {
7076 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7078 Immed = Immed >> 12;
7080 return std::nullopt;
7084 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7085 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7092InstructionSelector::ComplexRendererFns
7093AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7100 if (MaybeImmed == std::nullopt)
7101 return std::nullopt;
7102 return select12BitValueWithLeftShift(*MaybeImmed);
7107InstructionSelector::ComplexRendererFns
7108AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7112 return std::nullopt;
7114 if (MaybeImmed == std::nullopt)
7115 return std::nullopt;
7116 uint64_t Immed = *MaybeImmed;
7122 return std::nullopt;
7128 Immed = ~((uint32_t)Immed) + 1;
7130 Immed = ~Immed + 1ULL;
7132 if (Immed & 0xFFFFFFFFFF000000ULL)
7133 return std::nullopt;
7135 Immed &= 0xFFFFFFULL;
7136 return select12BitValueWithLeftShift(Immed);
7153std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7154 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7155 if (
MI.getOpcode() == AArch64::G_SHL) {
7159 MI.getOperand(2).getReg(), MRI)) {
7160 const APInt ShiftVal = ValAndVeg->Value;
7163 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7166 return std::nullopt;
7174bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7175 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7176 bool IsAddrOperand)
const {
7181 MI.getParent()->getParent()->getFunction().hasOptSize())
7184 if (IsAddrOperand) {
7186 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7190 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7191 MachineInstr *OffsetInst =
7197 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7208 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7211InstructionSelector::ComplexRendererFns
7212AArch64InstructionSelector::selectExtendedSHL(
7213 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7214 unsigned SizeInBytes,
bool WantsExt)
const {
7215 assert(
Base.isReg() &&
"Expected base to be a register operand");
7216 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7221 unsigned OffsetOpc = OffsetInst->
getOpcode();
7222 bool LookedThroughZExt =
false;
7223 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7225 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7226 return std::nullopt;
7230 LookedThroughZExt =
true;
7232 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7233 return std::nullopt;
7236 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7237 if (LegalShiftVal == 0)
7238 return std::nullopt;
7239 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7240 return std::nullopt;
7251 if (OffsetOpc == TargetOpcode::G_SHL)
7252 return std::nullopt;
7258 return std::nullopt;
7263 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7267 if (OffsetOpc == TargetOpcode::G_MUL) {
7269 return std::nullopt;
7275 if ((ImmVal & 0x7) != ImmVal)
7276 return std::nullopt;
7280 if (ImmVal != LegalShiftVal)
7281 return std::nullopt;
7283 unsigned SignExtend = 0;
7287 if (!LookedThroughZExt) {
7289 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7291 return std::nullopt;
7296 return std::nullopt;
7302 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7307 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7308 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7309 [=](MachineInstrBuilder &MIB) {
7312 MIB.addImm(SignExtend);
7325InstructionSelector::ComplexRendererFns
7326AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7327 MachineOperand &Root,
unsigned SizeInBytes)
const {
7329 return std::nullopt;
7344 MachineInstr *PtrAdd =
7346 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7347 return std::nullopt;
7351 MachineInstr *OffsetInst =
7353 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7366InstructionSelector::ComplexRendererFns
7367AArch64InstructionSelector::selectAddrModeRegisterOffset(
7368 MachineOperand &Root)
const {
7373 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7374 return std::nullopt;
7380 return std::nullopt;
7383 return {{[=](MachineInstrBuilder &MIB) {
7386 [=](MachineInstrBuilder &MIB) {
7389 [=](MachineInstrBuilder &MIB) {
7399InstructionSelector::ComplexRendererFns
7400AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7401 unsigned SizeInBytes)
const {
7404 return std::nullopt;
7405 MachineInstr *PtrAdd =
7408 return std::nullopt;
7426 unsigned Scale =
Log2_32(SizeInBytes);
7427 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7431 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7432 ImmOff < (0x1000 << Scale))
7433 return std::nullopt;
7438 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7442 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7448 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7449 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7454 return std::nullopt;
7458 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7464 return selectAddrModeRegisterOffset(Root);
7473InstructionSelector::ComplexRendererFns
7474AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7475 unsigned SizeInBytes)
const {
7478 MachineInstr *PtrAdd =
7480 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7481 return std::nullopt;
7502 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7511 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7512 return std::nullopt;
7516 getExtendTypeForInst(*OffsetInst, MRI,
true);
7518 return std::nullopt;
7521 MachineIRBuilder MIB(*PtrAdd);
7523 AArch64::GPR32RegClass, MIB);
7527 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7528 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7529 [=](MachineInstrBuilder &MIB) {
7530 MIB.addImm(SignExtend);
7540InstructionSelector::ComplexRendererFns
7541AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7542 unsigned Size)
const {
7543 MachineRegisterInfo &MRI =
7547 return std::nullopt;
7549 if (!isBaseWithConstantOffset(Root, MRI))
7550 return std::nullopt;
7554 MachineOperand &OffImm = RootDef->
getOperand(2);
7555 if (!OffImm.
isReg())
7556 return std::nullopt;
7558 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7559 return std::nullopt;
7561 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7563 return std::nullopt;
7566 if (RHSC >= -256 && RHSC < 256) {
7569 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7570 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7573 return std::nullopt;
7576InstructionSelector::ComplexRendererFns
7577AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7579 MachineRegisterInfo &MRI)
const {
7580 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7581 return std::nullopt;
7584 return std::nullopt;
7589 return std::nullopt;
7593 return std::nullopt;
7597 return std::nullopt;
7600 MachineIRBuilder MIRBuilder(RootDef);
7602 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7603 [=](MachineInstrBuilder &MIB) {
7604 MIB.addGlobalAddress(GV,
Offset,
7613InstructionSelector::ComplexRendererFns
7614AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7615 unsigned Size)
const {
7620 return std::nullopt;
7623 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7625 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7626 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7634 MachineInstr *RootParent = Root.
getParent();
7636 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7638 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7643 if (isBaseWithConstantOffset(Root, MRI)) {
7651 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7652 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7654 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7655 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7659 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7660 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7667 if (selectAddrModeUnscaled(Root,
Size))
7668 return std::nullopt;
7671 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7672 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7679 switch (
MI.getOpcode()) {
7682 case TargetOpcode::G_SHL:
7684 case TargetOpcode::G_LSHR:
7686 case TargetOpcode::G_ASHR:
7688 case TargetOpcode::G_ROTR:
7695InstructionSelector::ComplexRendererFns
7696AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7697 bool AllowROR)
const {
7699 return std::nullopt;
7700 MachineRegisterInfo &MRI =
7708 return std::nullopt;
7710 return std::nullopt;
7711 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7712 return std::nullopt;
7715 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7718 return std::nullopt;
7722 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7726 unsigned Val = *Immed & (NumBits - 1);
7729 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7730 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7734 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7735 unsigned Opc =
MI.getOpcode();
7738 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7740 if (
Opc == TargetOpcode::G_SEXT)
7743 Size =
MI.getOperand(2).getImm();
7744 assert(
Size != 64 &&
"Extend from 64 bits?");
7757 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7759 assert(
Size != 64 &&
"Extend from 64 bits?");
7774 if (
Opc != TargetOpcode::G_AND)
7780 uint64_t AndMask = *MaybeAndMask;
7793Register AArch64InstructionSelector::moveScalarRegClass(
7795 MachineRegisterInfo &MRI = *MIB.
getMRI();
7805 return Copy.getReg(0);
7810InstructionSelector::ComplexRendererFns
7811AArch64InstructionSelector::selectArithExtendedRegister(
7812 MachineOperand &Root)
const {
7814 return std::nullopt;
7815 MachineRegisterInfo &MRI =
7818 uint64_t ShiftVal = 0;
7823 return std::nullopt;
7825 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7826 return std::nullopt;
7829 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7834 return std::nullopt;
7835 ShiftVal = *MaybeShiftVal;
7837 return std::nullopt;
7842 return std::nullopt;
7843 Ext = getExtendTypeForInst(*ExtDef, MRI);
7845 return std::nullopt;
7849 Ext = getExtendTypeForInst(*RootDef, MRI);
7851 return std::nullopt;
7859 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7860 if (isDef32(*ExtInst))
7861 return std::nullopt;
7867 MachineIRBuilder MIB(*RootDef);
7868 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7870 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7871 [=](MachineInstrBuilder &MIB) {
7872 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7876InstructionSelector::ComplexRendererFns
7877AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7879 return std::nullopt;
7880 MachineRegisterInfo &MRI =
7884 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7889 return std::nullopt;
7892 if (Unmerge->getNumDefs() == 2 &&
7894 Register ExtReg = Unmerge->getSourceReg();
7895 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7899 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7903 LaneIdx->Value.getSExtValue() == 1) {
7904 Register ExtReg = ExtElt->getVectorReg();
7905 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7909 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7910 auto LaneIdx = Subvec->getIndexImm();
7912 Register ExtReg = Subvec->getSrcVec();
7913 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7917 return std::nullopt;
7920InstructionSelector::ComplexRendererFns
7921AArch64InstructionSelector::selectCVTFixedPointVecBase(
7922 const MachineOperand &Root,
bool isReciprocal)
const {
7924 return std::nullopt;
7925 const MachineRegisterInfo &MRI =
7930 return std::nullopt;
7931 std::optional<ValueAndVReg> CstVal =
7934 return std::nullopt;
7940 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7943 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7946 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7949 return std::nullopt;
7951 if (
unsigned FBits =
7953 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7955 return std::nullopt;
7958InstructionSelector::ComplexRendererFns
7959AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
7960 return selectCVTFixedPointVecBase(Root,
false);
7963InstructionSelector::ComplexRendererFns
7964AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
7965 MachineOperand &Root)
const {
7966 return selectCVTFixedPointVecBase(Root,
true);
7969void AArch64InstructionSelector::renderFixedPointScalarXForm(
7970 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7971 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
7972 "Expected vecshift immediate operand");
7973 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
7976void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
7977 const MachineInstr &
MI,
7982 InstructionSelector::ComplexRendererFns Renderer =
7983 selectCVTFixedPointVecBase(
MI.getOperand(OpIdx),
false);
7984 assert((Renderer && Renderer->size() == 1) &&
7985 "Expected selectCVTFixedPointVec to provide a function\n");
7986 (Renderer->front())(MIB);
7989void AArch64InstructionSelector::renderFixedPointRecipXForm(
7990 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
7991 InstructionSelector::ComplexRendererFns Renderer =
7992 selectCVTFixedPointVecBase(
MI.getOperand(OpIdx),
true);
7993 assert((Renderer && Renderer->size() == 1) &&
7994 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
7995 (Renderer->front())(MIB);
7998void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
7999 const MachineInstr &
MI,
8001 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8002 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8003 "Expected G_CONSTANT");
8004 std::optional<int64_t> CstVal =
8006 assert(CstVal &&
"Expected constant value");
8010void AArch64InstructionSelector::renderLogicalImm32(
8011 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8012 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8013 "Expected G_CONSTANT");
8014 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8019void AArch64InstructionSelector::renderLogicalImm64(
8020 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8021 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8022 "Expected G_CONSTANT");
8023 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8028void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8029 const MachineInstr &
MI,
8031 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8032 "Expected G_UBSANTRAP");
8033 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8036void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8037 const MachineInstr &
MI,
8039 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8040 "Expected G_FCONSTANT");
8045void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8046 const MachineInstr &
MI,
8048 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8049 "Expected G_FCONSTANT");
8054void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8055 const MachineInstr &
MI,
8057 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8058 "Expected G_FCONSTANT");
8063void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8064 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8065 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8066 "Expected G_FCONSTANT");
8074bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8075 const MachineInstr &
MI,
unsigned NumBytes)
const {
8076 if (!
MI.mayLoadOrStore())
8079 "Expected load/store to have only one mem op!");
8080 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8083bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8084 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8092 switch (
MI.getOpcode()) {
8095 case TargetOpcode::COPY:
8096 case TargetOpcode::G_BITCAST:
8097 case TargetOpcode::G_TRUNC:
8098 case TargetOpcode::G_PHI:
8108 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8111 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8129 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8134 MO.setReg(Copy.getReg(0));
8143 for (
auto &BB : MF) {
8144 for (
auto &
MI : BB) {
8145 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8150 for (
auto *
MI : Phis) {
8172 bool HasGPROp =
false, HasFPROp =
false;
8176 const LLT &Ty = MRI.
getType(MO.getReg());
8186 if (RB->
getID() == AArch64::GPRRegBankID)
8192 if (HasGPROp && HasFPROp)
8198InstructionSelector *
8202 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
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
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)
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.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
@ 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.