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 TargetOpcode::G_VECREDUCE_ADD:
2124 case TargetOpcode::G_VECREDUCE_SMAX:
2125 case TargetOpcode::G_VECREDUCE_SMIN:
2126 case TargetOpcode::G_VECREDUCE_UMAX:
2127 case TargetOpcode::G_VECREDUCE_UMIN: {
2130 Register DstReg =
I.getOperand(0).getReg();
2131 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2132 if (DstRB.
getID() != AArch64::GPRRegBankID)
2135 LLT DstTy = MRI.
getType(DstReg);
2137 getRegClassForTypeOnBank(DstTy, DstRB,
true);
2143 I.getOperand(0).setReg(FPRDst);
2145 BuildMI(
MBB, std::next(
I.getIterator()), MIMetadata(
I),
2146 TII.get(TargetOpcode::COPY), DstReg)
2150 case AArch64::G_DUP: {
2152 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2156 MRI.
setType(
I.getOperand(0).getReg(),
2158 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2159 I.getOperand(1).setReg(NewSrc.getReg(0));
2162 case AArch64::G_INSERT_VECTOR_ELT: {
2163 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2164 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2168 MRI.
setType(
I.getOperand(1).getReg(),
2170 MRI.
setType(
I.getOperand(0).getReg(),
2172 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2173 I.getOperand(2).setReg(NewSrc.getReg(0));
2177 Register EltReg =
I.getOperand(2).getReg();
2178 LLT EltTy = MRI.
getType(EltReg);
2184 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2185 I.getOperand(2).setReg(NewElt.getReg(0));
2190 case TargetOpcode::G_UITOFP:
2191 case TargetOpcode::G_SITOFP: {
2196 Register SrcReg =
I.getOperand(1).getReg();
2197 LLT SrcTy = MRI.
getType(SrcReg);
2198 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2207 I.getOperand(1).setReg(
Copy.getReg(0));
2209 getRegClassForTypeOnBank(
2210 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2212 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2213 I.setDesc(
TII.get(AArch64::G_SITOF));
2215 I.setDesc(
TII.get(AArch64::G_UITOF));
2233bool AArch64InstructionSelector::convertPtrAddToAdd(
2234 MachineInstr &
I, MachineRegisterInfo &MRI) {
2235 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2236 Register DstReg =
I.getOperand(0).getReg();
2237 Register AddOp1Reg =
I.getOperand(1).getReg();
2238 const LLT PtrTy = MRI.
getType(DstReg);
2242 const LLT CastPtrTy = PtrTy.
isVector()
2254 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2255 MRI.
setType(DstReg, CastPtrTy);
2256 I.getOperand(1).setReg(PtrToInt.getReg(0));
2257 if (!select(*PtrToInt)) {
2258 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2267 I.getOperand(2).setReg(NegatedReg);
2268 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2272bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2273 MachineRegisterInfo &MRI) {
2277 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2278 const auto &MO =
I.getOperand(2);
2283 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2287 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2288 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2290 if (!Imm1Fn || !Imm2Fn)
2294 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2295 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2297 for (
auto &RenderFn : *Imm1Fn)
2299 for (
auto &RenderFn : *Imm2Fn)
2302 I.eraseFromParent();
2307bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2308 MachineInstr &
I, MachineRegisterInfo &MRI) {
2309 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2327 LLT DefDstTy = MRI.
getType(DefDstReg);
2328 Register StoreSrcReg =
I.getOperand(0).getReg();
2329 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2345 I.getOperand(0).setReg(DefDstReg);
2349bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2350 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2351 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2357 switch (
I.getOpcode()) {
2358 case AArch64::G_DUP: {
2361 Register Src =
I.getOperand(1).getReg();
2363 Src, MRI,
true,
true);
2367 Register Dst =
I.getOperand(0).getReg();
2373 if (!emitConstantVector(Dst, CV, MIB, MRI))
2375 I.eraseFromParent();
2378 case TargetOpcode::G_SEXT:
2381 if (selectUSMovFromExtend(
I, MRI))
2384 case TargetOpcode::G_BR:
2386 case TargetOpcode::G_SHL:
2387 return earlySelectSHL(
I, MRI);
2388 case TargetOpcode::G_CONSTANT: {
2389 bool IsZero =
false;
2390 if (
I.getOperand(1).isCImm())
2391 IsZero =
I.getOperand(1).getCImm()->isZero();
2392 else if (
I.getOperand(1).isImm())
2393 IsZero =
I.getOperand(1).getImm() == 0;
2398 Register DefReg =
I.getOperand(0).getReg();
2401 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2404 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2409 I.setDesc(
TII.get(TargetOpcode::COPY));
2413 case TargetOpcode::G_ADD: {
2422 Register AddDst =
I.getOperand(0).getReg();
2423 Register AddLHS =
I.getOperand(1).getReg();
2424 Register AddRHS =
I.getOperand(2).getReg();
2434 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2455 MachineInstr *
Cmp = MatchCmp(AddRHS);
2459 Cmp = MatchCmp(AddRHS);
2463 auto &PredOp =
Cmp->getOperand(1);
2465 emitIntegerCompare(
Cmp->getOperand(2),
2466 Cmp->getOperand(3), PredOp, MIB);
2470 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2471 I.eraseFromParent();
2474 case TargetOpcode::G_OR: {
2478 Register Dst =
I.getOperand(0).getReg();
2498 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2501 int64_t Immr =
Size - ShiftImm;
2502 int64_t Imms =
Size - ShiftImm - 1;
2503 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2504 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2505 I.eraseFromParent();
2508 case TargetOpcode::G_FENCE: {
2509 if (
I.getOperand(1).getImm() == 0)
2513 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2514 I.eraseFromParent();
2522bool AArch64InstructionSelector::select(MachineInstr &
I) {
2523 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2524 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2530 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2531 if (Subtarget->requiresStrictAlign()) {
2533 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2539 unsigned Opcode =
I.getOpcode();
2541 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2544 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2549 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2550 const Register DefReg =
I.getOperand(0).getReg();
2551 const LLT DefTy = MRI.
getType(DefReg);
2564 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2571 I.setDesc(
TII.get(TargetOpcode::PHI));
2579 if (
I.isDebugInstr())
2586 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2588 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2595 if (preISelLower(
I)) {
2596 Opcode =
I.getOpcode();
2607 if (selectImpl(
I, *CoverageInfo))
2611 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2614 case TargetOpcode::G_SBFX:
2615 case TargetOpcode::G_UBFX: {
2616 static const unsigned OpcTable[2][2] = {
2617 {AArch64::UBFMWri, AArch64::UBFMXri},
2618 {AArch64::SBFMWri, AArch64::SBFMXri}};
2619 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2621 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2624 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2627 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2628 auto LSB = Cst1->Value.getZExtValue();
2629 auto Width = Cst2->Value.getZExtValue();
2633 .
addImm(LSB + Width - 1);
2634 I.eraseFromParent();
2638 case TargetOpcode::G_BRCOND:
2639 return selectCompareBranch(
I, MF, MRI);
2641 case TargetOpcode::G_BRINDIRECT: {
2643 if (std::optional<uint16_t> BADisc =
2645 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2649 I.eraseFromParent();
2653 I.setDesc(
TII.get(AArch64::BR));
2658 case TargetOpcode::G_BRJT:
2659 return selectBrJT(
I, MRI);
2661 case AArch64::G_ADD_LOW: {
2666 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2667 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2668 I.setDesc(
TII.get(AArch64::ADDXri));
2674 "Expected small code model");
2676 auto Op2 =
I.getOperand(2);
2677 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2678 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2679 Op1.getTargetFlags())
2681 Op2.getTargetFlags());
2682 I.eraseFromParent();
2687 case TargetOpcode::G_FCONSTANT: {
2688 const Register DefReg =
I.getOperand(0).getReg();
2689 const LLT DefTy = MRI.
getType(DefReg);
2700 bool OptForSize = shouldOptForSize(&MF);
2704 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2711 auto *FPImm =
I.getOperand(1).getFPImm();
2714 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2717 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2718 I.eraseFromParent();
2723 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2726 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2727 MachineOperand &RegOp =
I.getOperand(0);
2733 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2737 MachineOperand &ImmOp =
I.getOperand(1);
2741 const unsigned MovOpc =
2742 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2743 I.setDesc(
TII.get(MovOpc));
2747 case TargetOpcode::G_EXTRACT: {
2748 Register DstReg =
I.getOperand(0).getReg();
2749 Register SrcReg =
I.getOperand(1).getReg();
2750 LLT SrcTy = MRI.
getType(SrcReg);
2751 LLT DstTy = MRI.
getType(DstReg);
2763 unsigned Offset =
I.getOperand(2).getImm();
2768 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2769 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2772 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2774 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2776 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2778 AArch64::GPR64RegClass, NewI->getOperand(0));
2779 I.eraseFromParent();
2785 unsigned LaneIdx =
Offset / 64;
2786 MachineInstr *Extract = emitExtractVectorElt(
2787 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2790 I.eraseFromParent();
2794 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2795 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2800 "unexpected G_EXTRACT types");
2807 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2808 .addReg(DstReg, {}, AArch64::sub_32);
2810 AArch64::GPR32RegClass, MRI);
2811 I.getOperand(0).setReg(DstReg);
2817 case TargetOpcode::G_INSERT: {
2818 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2819 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2826 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2827 unsigned LSB =
I.getOperand(3).getImm();
2829 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2830 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2834 "unexpected G_INSERT types");
2841 TII.get(AArch64::SUBREG_TO_REG))
2843 .
addUse(
I.getOperand(2).getReg())
2844 .
addImm(AArch64::sub_32);
2846 AArch64::GPR32RegClass, MRI);
2847 I.getOperand(2).setReg(SrcReg);
2852 case TargetOpcode::G_FRAME_INDEX: {
2859 I.setDesc(
TII.get(AArch64::ADDXri));
2869 case TargetOpcode::G_GLOBAL_VALUE: {
2870 const GlobalValue *GV =
nullptr;
2872 if (
I.getOperand(1).isSymbol()) {
2873 OpFlags =
I.getOperand(1).getTargetFlags();
2882 return selectTLSGlobalValue(
I, MRI);
2888 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2889 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2890 I.getOperand(1).setTargetFlags(OpFlags);
2891 I.addImplicitDefUseOperands(MF);
2895 materializeLargeCMVal(
I, GV, OpFlags);
2896 I.eraseFromParent();
2899 I.setDesc(
TII.get(AArch64::ADR));
2900 I.getOperand(1).setTargetFlags(OpFlags);
2902 I.setDesc(
TII.get(AArch64::MOVaddr));
2904 MachineInstrBuilder MIB(MF,
I);
2905 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2912 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2913 return selectPtrAuthGlobalValue(
I, MRI);
2915 case TargetOpcode::G_ZEXTLOAD:
2916 case TargetOpcode::G_LOAD:
2917 case TargetOpcode::G_STORE: {
2919 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2934 assert(MemSizeInBytes <= 8 &&
2935 "128-bit atomics should already be custom-legalized");
2938 static constexpr unsigned LDAPROpcodes[] = {
2939 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2940 static constexpr unsigned LDAROpcodes[] = {
2941 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2942 ArrayRef<unsigned> Opcodes =
2943 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2946 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2948 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2949 AArch64::STLRW, AArch64::STLRX};
2954 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2955 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2956 I.getOperand(0).setReg(NewVal);
2958 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2966 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2969 "Load/Store pointer operand isn't a GPR");
2971 "Load/Store pointer operand isn't a pointer");
2976 LLT ValTy = MRI.
getType(ValReg);
2981 RB.
getID() == AArch64::FPRRegBankID) {
2984 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2990 .addReg(ValReg, {}, SubReg)
2997 if (RB.
getID() == AArch64::FPRRegBankID) {
3000 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3010 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3013 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3022 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3024 const unsigned NewOpc =
3026 if (NewOpc ==
I.getOpcode())
3030 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3033 I.setDesc(
TII.get(NewOpc));
3039 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3040 Register CurValReg =
I.getOperand(0).getReg();
3041 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3042 NewInst.cloneMemRefs(
I);
3043 for (
auto &Fn : *AddrModeFns)
3045 I.eraseFromParent();
3049 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3054 if (Opcode == TargetOpcode::G_STORE) {
3056 LoadStore->getOperand(0).getReg(), MRI);
3057 if (CVal && CVal->Value == 0) {
3059 case AArch64::STRWui:
3060 case AArch64::STRHHui:
3061 case AArch64::STRBBui:
3062 LoadStore->getOperand(0).setReg(AArch64::WZR);
3064 case AArch64::STRXui:
3065 LoadStore->getOperand(0).setReg(AArch64::XZR);
3071 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3072 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3084 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3086 .
addImm(AArch64::sub_32);
3095 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3096 case TargetOpcode::G_INDEXED_SEXTLOAD:
3097 return selectIndexedExtLoad(
I, MRI);
3098 case TargetOpcode::G_INDEXED_LOAD:
3099 return selectIndexedLoad(
I, MRI);
3100 case TargetOpcode::G_INDEXED_STORE:
3103 case TargetOpcode::G_LSHR:
3104 case TargetOpcode::G_ASHR:
3106 return selectVectorAshrLshr(
I, MRI);
3108 case TargetOpcode::G_SHL: {
3109 if (Opcode == TargetOpcode::G_SHL &&
3111 return selectVectorSHL(
I, MRI);
3118 Register SrcReg =
I.getOperand(1).getReg();
3119 Register ShiftReg =
I.getOperand(2).getReg();
3120 const LLT ShiftTy = MRI.
getType(ShiftReg);
3121 const LLT SrcTy = MRI.
getType(SrcReg);
3126 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3127 .addReg(ShiftReg, {}, AArch64::sub_32);
3129 I.getOperand(2).setReg(Trunc.getReg(0));
3134 const Register DefReg =
I.getOperand(0).getReg();
3138 if (NewOpc ==
I.getOpcode())
3141 I.setDesc(
TII.get(NewOpc));
3149 case TargetOpcode::G_PTR_ADD: {
3150 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3151 I.eraseFromParent();
3155 case TargetOpcode::G_SADDE:
3156 case TargetOpcode::G_UADDE:
3157 case TargetOpcode::G_SSUBE:
3158 case TargetOpcode::G_USUBE:
3159 case TargetOpcode::G_SADDO:
3160 case TargetOpcode::G_UADDO:
3161 case TargetOpcode::G_SSUBO:
3162 case TargetOpcode::G_USUBO:
3163 return selectOverflowOp(
I, MRI);
3165 case TargetOpcode::G_PTRMASK: {
3166 Register MaskReg =
I.getOperand(2).getReg();
3173 I.setDesc(
TII.get(AArch64::ANDXri));
3174 I.getOperand(2).ChangeToImmediate(
3180 case TargetOpcode::G_PTRTOINT:
3181 case TargetOpcode::G_TRUNC: {
3182 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3183 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3185 const Register DstReg =
I.getOperand(0).getReg();
3186 const Register SrcReg =
I.getOperand(1).getReg();
3188 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3189 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3193 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3197 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3208 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3212 if (DstRC == SrcRC) {
3214 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3218 }
else if (DstRC == &AArch64::GPR32RegClass &&
3219 SrcRC == &AArch64::GPR64RegClass) {
3220 I.getOperand(1).setSubReg(AArch64::sub_32);
3223 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3227 I.setDesc(
TII.get(TargetOpcode::COPY));
3229 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3232 I.setDesc(
TII.get(AArch64::XTNv4i16));
3238 MachineInstr *Extract = emitExtractVectorElt(
3242 I.eraseFromParent();
3247 if (Opcode == TargetOpcode::G_PTRTOINT) {
3248 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3249 I.setDesc(
TII.get(TargetOpcode::COPY));
3257 case TargetOpcode::G_ANYEXT: {
3258 if (selectUSMovFromExtend(
I, MRI))
3261 const Register DstReg =
I.getOperand(0).getReg();
3262 const Register SrcReg =
I.getOperand(1).getReg();
3264 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3265 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3267 <<
", expected: GPR\n");
3271 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3272 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3274 <<
", expected: GPR\n");
3281 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3285 if (DstSize != 64 && DstSize > 32) {
3287 <<
", expected: 32 or 64\n");
3297 .
addImm(AArch64::sub_32);
3298 I.getOperand(1).setReg(ExtSrc);
3303 case TargetOpcode::G_ZEXT:
3304 case TargetOpcode::G_SEXT_INREG:
3305 case TargetOpcode::G_SEXT: {
3306 if (selectUSMovFromExtend(
I, MRI))
3309 unsigned Opcode =
I.getOpcode();
3310 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3311 const Register DefReg =
I.getOperand(0).getReg();
3312 Register SrcReg =
I.getOperand(1).getReg();
3313 const LLT DstTy = MRI.
getType(DefReg);
3314 const LLT SrcTy = MRI.
getType(SrcReg);
3320 if (Opcode == TargetOpcode::G_SEXT_INREG)
3321 SrcSize =
I.getOperand(2).getImm();
3327 AArch64::GPRRegBankID &&
3328 "Unexpected ext regbank");
3339 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3342 if (LoadMI && IsGPR) {
3343 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3344 unsigned BytesLoaded = MemOp->getSize().getValue();
3351 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3354 const Register ZReg = AArch64::WZR;
3355 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3358 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3359 .addUse(SubregToRegSrc)
3360 .
addImm(AArch64::sub_32);
3364 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3374 I.eraseFromParent();
3379 if (DstSize == 64) {
3380 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3388 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3389 {&AArch64::GPR64RegClass}, {})
3395 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3399 }
else if (DstSize <= 32) {
3400 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3409 I.eraseFromParent();
3413 case TargetOpcode::G_FREEZE:
3416 case TargetOpcode::G_INTTOPTR:
3421 case TargetOpcode::G_BITCAST:
3429 case TargetOpcode::G_SELECT: {
3431 const Register CondReg = Sel.getCondReg();
3433 const Register FReg = Sel.getFalseReg();
3435 if (tryOptSelect(Sel))
3441 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3446 Sel.eraseFromParent();
3449 case TargetOpcode::G_ICMP: {
3459 auto &PredOp =
I.getOperand(1);
3460 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3464 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3465 AArch64::WZR, InvCC, MIB);
3466 I.eraseFromParent();
3470 case TargetOpcode::G_FCMP: {
3473 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3475 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3477 I.eraseFromParent();
3480 case TargetOpcode::G_VASTART:
3482 : selectVaStartAAPCS(
I, MF, MRI);
3483 case TargetOpcode::G_INTRINSIC:
3484 return selectIntrinsic(
I, MRI);
3485 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3486 return selectIntrinsicWithSideEffects(
I, MRI);
3487 case TargetOpcode::G_IMPLICIT_DEF: {
3488 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3489 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3490 const Register DstReg =
I.getOperand(0).getReg();
3491 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3496 case TargetOpcode::G_BLOCK_ADDR: {
3497 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3498 if (std::optional<uint16_t> BADisc =
3500 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3501 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3510 AArch64::GPR64RegClass, MRI);
3511 I.eraseFromParent();
3515 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3516 I.eraseFromParent();
3519 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3520 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3521 I.getOperand(0).getReg())
3525 I.getOperand(1).getBlockAddress(), 0,
3527 I.eraseFromParent();
3532 case AArch64::G_DUP: {
3539 AArch64::GPRRegBankID)
3541 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3543 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3545 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3547 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3549 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3555 case TargetOpcode::G_BUILD_VECTOR:
3556 return selectBuildVector(
I, MRI);
3557 case TargetOpcode::G_MERGE_VALUES:
3559 case TargetOpcode::G_UNMERGE_VALUES:
3561 case TargetOpcode::G_SHUFFLE_VECTOR:
3562 return selectShuffleVector(
I, MRI);
3563 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3564 return selectExtractElt(
I, MRI);
3565 case TargetOpcode::G_CONCAT_VECTORS:
3566 return selectConcatVectors(
I, MRI);
3567 case TargetOpcode::G_JUMP_TABLE:
3568 return selectJumpTable(
I, MRI);
3569 case TargetOpcode::G_MEMCPY:
3570 case TargetOpcode::G_MEMCPY_INLINE:
3571 case TargetOpcode::G_MEMMOVE:
3572 case TargetOpcode::G_MEMSET:
3573 case TargetOpcode::G_MEMSET_INLINE:
3574 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3575 return selectMOPS(
I, MRI);
3581bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3582 MachineIRBuilderState OldMIBState = MIB.
getState();
3588bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3589 MachineRegisterInfo &MRI) {
3592 case TargetOpcode::G_MEMCPY:
3593 case TargetOpcode::G_MEMCPY_INLINE:
3594 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3596 case TargetOpcode::G_MEMMOVE:
3597 Mopcode = AArch64::MOPSMemoryMovePseudo;
3599 case TargetOpcode::G_MEMSET:
3600 case TargetOpcode::G_MEMSET_INLINE:
3602 Mopcode = AArch64::MOPSMemorySetPseudo;
3615 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3616 const auto &SrcValRegClass =
3617 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3635 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3636 {DstPtrCopy, SizeCopy, SrcValCopy});
3639 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3640 {DstPtrCopy, SrcValCopy, SizeCopy});
3647bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3648 MachineRegisterInfo &MRI) {
3649 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3650 Register JTAddr =
I.getOperand(0).getReg();
3651 unsigned JTI =
I.getOperand(1).getIndex();
3654 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3666 "jump table hardening only supported on MachO/ELF");
3674 I.eraseFromParent();
3681 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3682 {TargetReg, ScratchReg}, {JTAddr,
Index})
3683 .addJumpTableIndex(JTI);
3685 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3686 {
static_cast<int64_t
>(JTI)});
3688 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3689 I.eraseFromParent();
3694bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3695 MachineRegisterInfo &MRI) {
3696 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3697 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3699 Register DstReg =
I.getOperand(0).getReg();
3700 unsigned JTI =
I.getOperand(1).getIndex();
3703 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3706 I.eraseFromParent();
3711bool AArch64InstructionSelector::selectTLSGlobalValue(
3712 MachineInstr &
I, MachineRegisterInfo &MRI) {
3718 const auto &GlobalOp =
I.getOperand(1);
3719 assert(GlobalOp.getOffset() == 0 &&
3720 "Shouldn't have an offset on TLS globals!");
3721 const GlobalValue &GV = *GlobalOp.getGlobal();
3724 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3727 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3728 {LoadGOT.getReg(0)})
3739 assert(Opcode == AArch64::BLR);
3740 Opcode = AArch64::BLRAAZ;
3744 .addUse(AArch64::X0, RegState::Implicit)
3745 .
addDef(AArch64::X0, RegState::Implicit)
3751 I.eraseFromParent();
3755MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3757 MachineIRBuilder &MIRBuilder)
const {
3758 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3760 auto BuildFn = [&](
unsigned SubregIndex) {
3764 .addImm(SubregIndex);
3772 return BuildFn(AArch64::bsub);
3774 return BuildFn(AArch64::hsub);
3776 return BuildFn(AArch64::ssub);
3778 return BuildFn(AArch64::dsub);
3785AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3786 MachineIRBuilder &MIB,
3787 MachineRegisterInfo &MRI)
const {
3788 LLT DstTy = MRI.
getType(DstReg);
3790 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3791 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3795 unsigned SubReg = 0;
3798 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3804 .addReg(SrcReg, {}, SubReg);
3809bool AArch64InstructionSelector::selectMergeValues(
3810 MachineInstr &
I, MachineRegisterInfo &MRI) {
3811 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3812 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3813 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3815 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3817 if (
I.getNumOperands() != 3)
3824 Register DstReg =
I.getOperand(0).getReg();
3825 Register Src1Reg =
I.getOperand(1).getReg();
3826 Register Src2Reg =
I.getOperand(2).getReg();
3827 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3828 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3832 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3833 Src2Reg, 1, RB, MIB);
3838 I.eraseFromParent();
3842 if (RB.
getID() != AArch64::GPRRegBankID)
3848 auto *DstRC = &AArch64::GPR64RegClass;
3850 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3851 TII.get(TargetOpcode::SUBREG_TO_REG))
3853 .
addUse(
I.getOperand(1).getReg())
3854 .
addImm(AArch64::sub_32);
3857 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3858 TII.get(TargetOpcode::SUBREG_TO_REG))
3860 .
addUse(
I.getOperand(2).getReg())
3861 .
addImm(AArch64::sub_32);
3863 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3864 .
addDef(
I.getOperand(0).getReg())
3872 I.eraseFromParent();
3877 const unsigned EltSize) {
3882 CopyOpc = AArch64::DUPi8;
3883 ExtractSubReg = AArch64::bsub;
3886 CopyOpc = AArch64::DUPi16;
3887 ExtractSubReg = AArch64::hsub;
3890 CopyOpc = AArch64::DUPi32;
3891 ExtractSubReg = AArch64::ssub;
3894 CopyOpc = AArch64::DUPi64;
3895 ExtractSubReg = AArch64::dsub;
3899 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3905MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3906 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3907 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3908 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3909 unsigned CopyOpc = 0;
3910 unsigned ExtractSubReg = 0;
3913 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3918 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3920 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3924 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3925 const LLT &VecTy = MRI.
getType(VecReg);
3927 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3929 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3939 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3940 .addReg(VecReg, {}, ExtractSubReg);
3949 MachineInstr *ScalarToVector = emitScalarToVector(
3950 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3951 if (!ScalarToVector)
3956 MachineInstr *LaneCopyMI =
3957 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3965bool AArch64InstructionSelector::selectExtractElt(
3966 MachineInstr &
I, MachineRegisterInfo &MRI) {
3967 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3968 "unexpected opcode!");
3969 Register DstReg =
I.getOperand(0).getReg();
3970 const LLT NarrowTy = MRI.
getType(DstReg);
3971 const Register SrcReg =
I.getOperand(1).getReg();
3972 const LLT WideTy = MRI.
getType(SrcReg);
3974 "source register size too small!");
3975 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
3978 MachineOperand &LaneIdxOp =
I.getOperand(2);
3979 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
3985 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
3987 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3988 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3992 Opcode = AArch64::UMOVvi8;
3995 Opcode = AArch64::UMOVvi16;
3998 Opcode = AArch64::UMOVvi32;
4005 MachineInstr *ScalarToVector = emitScalarToVector(
4006 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4007 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4011 I.setDesc(
TII.get(Opcode));
4012 I.getOperand(2).ChangeToImmediate(LaneIdx);
4017 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4022 I.eraseFromParent();
4026bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4027 MachineInstr &
I, MachineRegisterInfo &MRI) {
4028 unsigned NumElts =
I.getNumOperands() - 1;
4029 Register SrcReg =
I.getOperand(NumElts).getReg();
4030 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4031 const LLT SrcTy = MRI.
getType(SrcReg);
4033 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4035 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4041 const RegisterBank &DstRB =
4043 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4044 Register Dst =
I.getOperand(OpIdx).getReg();
4045 MachineInstr *Extract =
4046 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4050 I.eraseFromParent();
4054bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4055 MachineRegisterInfo &MRI) {
4056 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4057 "unexpected opcode");
4061 unsigned NumElts =
I.getNumOperands() - 1;
4062 Register SrcReg =
I.getOperand(NumElts).getReg();
4063 Register LoReg =
I.getOperand(0).getReg();
4064 Register HiReg =
I.getOperand(1).getReg();
4065 const LLT NarrowTy = MRI.
getType(LoReg);
4066 const LLT WideTy = MRI.
getType(SrcReg);
4067 const RegisterBank &LoRB = *RBI.
getRegBank(LoReg, MRI,
TRI);
4068 const RegisterBank &HiRB = *RBI.
getRegBank(HiReg, MRI,
TRI);
4069 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
4073 LoRB.
getID() == AArch64::GPRRegBankID &&
4074 HiRB.
getID() == AArch64::GPRRegBankID &&
4075 SrcRB.
getID() == AArch64::FPRRegBankID) {
4076 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4077 TII.get(AArch64::UMOVvi64), LoReg)
4080 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4081 TII.get(AArch64::UMOVvi64), HiReg)
4086 I.eraseFromParent();
4091 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4092 HiRB.
getID() != AArch64::FPRRegBankID) {
4093 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4094 "currently unsupported.\n");
4099 "source register size too small!");
4102 return selectSplitVectorUnmerge(
I, MRI);
4106 unsigned CopyOpc = 0;
4107 unsigned ExtractSubReg = 0;
4118 unsigned NumInsertRegs = NumElts - 1;
4124 InsertRegs.
assign(NumInsertRegs, SrcReg);
4133 unsigned SubReg = 0;
4136 assert(Found &&
"expected to find last operand's subeg idx");
4137 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4139 MachineInstr &ImpDefMI =
4140 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4145 MachineInstr &InsMI =
4147 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4164 Register CopyTo =
I.getOperand(0).getReg();
4165 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4166 .addReg(InsertRegs[0], {}, ExtractSubReg);
4170 unsigned LaneIdx = 1;
4171 for (
Register InsReg : InsertRegs) {
4172 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4173 MachineInstr &CopyInst =
4192 I.eraseFromParent();
4196bool AArch64InstructionSelector::selectConcatVectors(
4197 MachineInstr &
I, MachineRegisterInfo &MRI) {
4198 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4199 "Unexpected opcode");
4200 Register Dst =
I.getOperand(0).getReg();
4201 Register Op1 =
I.getOperand(1).getReg();
4202 Register Op2 =
I.getOperand(2).getReg();
4203 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4206 I.eraseFromParent();
4211AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4220MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4221 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4228 RC = &AArch64::FPR128RegClass;
4229 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4232 RC = &AArch64::FPR64RegClass;
4233 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4236 RC = &AArch64::FPR32RegClass;
4237 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4240 RC = &AArch64::FPR16RegClass;
4241 Opc = AArch64::LDRHui;
4244 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4249 MachineInstr *LoadMI =
nullptr;
4250 auto &MF = MIRBuilder.
getMF();
4251 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4252 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4254 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4257 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4261 .addConstantPoolIndex(
4277static std::pair<unsigned, unsigned>
4279 unsigned Opc, SubregIdx;
4280 if (RB.
getID() == AArch64::GPRRegBankID) {
4282 Opc = AArch64::INSvi8gpr;
4283 SubregIdx = AArch64::bsub;
4284 }
else if (EltSize == 16) {
4285 Opc = AArch64::INSvi16gpr;
4286 SubregIdx = AArch64::ssub;
4287 }
else if (EltSize == 32) {
4288 Opc = AArch64::INSvi32gpr;
4289 SubregIdx = AArch64::ssub;
4290 }
else if (EltSize == 64) {
4291 Opc = AArch64::INSvi64gpr;
4292 SubregIdx = AArch64::dsub;
4298 Opc = AArch64::INSvi8lane;
4299 SubregIdx = AArch64::bsub;
4300 }
else if (EltSize == 16) {
4301 Opc = AArch64::INSvi16lane;
4302 SubregIdx = AArch64::hsub;
4303 }
else if (EltSize == 32) {
4304 Opc = AArch64::INSvi32lane;
4305 SubregIdx = AArch64::ssub;
4306 }
else if (EltSize == 64) {
4307 Opc = AArch64::INSvi64lane;
4308 SubregIdx = AArch64::dsub;
4313 return std::make_pair(
Opc, SubregIdx);
4316MachineInstr *AArch64InstructionSelector::emitInstr(
4317 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4318 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4319 const ComplexRendererFns &RenderFns)
const {
4320 assert(Opcode &&
"Expected an opcode?");
4322 "Function should only be used to produce selected instructions!");
4323 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4325 for (
auto &Fn : *RenderFns)
4331MachineInstr *AArch64InstructionSelector::emitAddSub(
4332 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4334 MachineIRBuilder &MIRBuilder)
const {
4336 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4340 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4341 bool Is32Bit =
Size == 32;
4344 if (
auto Fns = selectArithImmed(
RHS))
4345 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4349 if (
auto Fns = selectNegArithImmed(
RHS))
4350 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4354 if (
auto Fns = selectArithExtendedRegister(
RHS))
4355 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4359 if (
auto Fns = selectShiftedRegister(
RHS))
4360 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4362 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4367AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4368 MachineOperand &
RHS,
4369 MachineIRBuilder &MIRBuilder)
const {
4370 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4371 {{AArch64::ADDXri, AArch64::ADDWri},
4372 {AArch64::ADDXrs, AArch64::ADDWrs},
4373 {AArch64::ADDXrr, AArch64::ADDWrr},
4374 {AArch64::SUBXri, AArch64::SUBWri},
4375 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4376 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4380AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4381 MachineOperand &
RHS,
4382 MachineIRBuilder &MIRBuilder)
const {
4383 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4384 {{AArch64::ADDSXri, AArch64::ADDSWri},
4385 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4386 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4387 {AArch64::SUBSXri, AArch64::SUBSWri},
4388 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4389 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4393AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4394 MachineOperand &
RHS,
4395 MachineIRBuilder &MIRBuilder)
const {
4396 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4397 {{AArch64::SUBSXri, AArch64::SUBSWri},
4398 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4399 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4400 {AArch64::ADDSXri, AArch64::ADDSWri},
4401 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4402 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4406AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4407 MachineOperand &
RHS,
4408 MachineIRBuilder &MIRBuilder)
const {
4409 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4410 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4412 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4413 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4417AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4418 MachineOperand &
RHS,
4419 MachineIRBuilder &MIRBuilder)
const {
4420 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4421 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4423 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4424 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4428AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4429 MachineIRBuilder &MIRBuilder)
const {
4432 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4437AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4438 MachineIRBuilder &MIRBuilder)
const {
4441 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4446AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4447 MachineIRBuilder &MIRBuilder)
const {
4448 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4452 bool Is32Bit = (
RegSize == 32);
4453 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4454 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4455 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4459 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4462 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4469 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4470 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4471 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4474MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4475 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4476 MachineIRBuilder &MIRBuilder)
const {
4477 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4484 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4486 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4488 return emitCMP(
LHS,
RHS, MIRBuilder);
4491MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4493 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4497 "Expected a 32-bit scalar register?");
4499 const Register ZReg = AArch64::WZR;
4504 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4510 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4511 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4512 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4517MachineInstr *AArch64InstructionSelector::emitFPCompare(
4519 std::optional<CmpInst::Predicate> Pred)
const {
4520 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4525 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4535 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4538 ShouldUseImm =
true;
4542 unsigned CmpOpcTbl[2][3] = {
4543 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4544 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4546 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4558MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4560 MachineIRBuilder &MIRBuilder)
const {
4567 const LLT Op1Ty = MRI.
getType(Op1);
4568 const LLT Op2Ty = MRI.
getType(Op2);
4570 if (Op1Ty != Op2Ty) {
4571 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4574 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4577 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4588 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4592 MachineInstr *WidenedOp1 =
4593 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4594 MachineInstr *WidenedOp2 =
4595 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4596 if (!WidenedOp1 || !WidenedOp2) {
4597 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4602 unsigned InsertOpc, InsSubRegIdx;
4603 std::tie(InsertOpc, InsSubRegIdx) =
4621 MachineIRBuilder &MIRBuilder)
const {
4622 auto &MRI = *MIRBuilder.
getMRI();
4628 Size =
TRI.getRegSizeInBits(*RC);
4632 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4633 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4634 unsigned Opc = OpcTable[
Size == 64];
4635 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4640MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4642 MachineRegisterInfo *MRI = MIB.
getMRI();
4643 unsigned Opcode =
I.getOpcode();
4647 bool NeedsNegatedCarry =
4648 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4657 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4658 if (SrcMI ==
I.getPrevNode()) {
4660 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4661 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4662 CarrySrcMI->isUnsigned() &&
4663 CarrySrcMI->getCarryOutReg() == CarryReg &&
4664 selectAndRestoreState(*SrcMI))
4671 if (NeedsNegatedCarry) {
4674 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4678 auto Fns = select12BitValueWithLeftShift(1);
4679 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4682bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4683 MachineRegisterInfo &MRI) {
4688 emitCarryIn(
I, CarryInMI->getCarryInReg());
4692 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4693 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4695 Register CarryOutReg = CarryMI.getCarryOutReg();
4704 emitCSINC(CarryOutReg, ZReg, ZReg,
4705 getInvertedCondCode(OpAndCC.second), MIB);
4708 I.eraseFromParent();
4712std::pair<MachineInstr *, AArch64CC::CondCode>
4713AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4714 MachineOperand &
LHS,
4715 MachineOperand &
RHS,
4716 MachineIRBuilder &MIRBuilder)
const {
4720 case TargetOpcode::G_SADDO:
4722 case TargetOpcode::G_UADDO:
4724 case TargetOpcode::G_SSUBO:
4726 case TargetOpcode::G_USUBO:
4728 case TargetOpcode::G_SADDE:
4730 case TargetOpcode::G_UADDE:
4732 case TargetOpcode::G_SSUBE:
4734 case TargetOpcode::G_USUBE:
4755 unsigned Depth = 0) {
4762 MustBeFirst =
false;
4768 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4769 bool IsOR = Opcode == TargetOpcode::G_OR;
4781 if (MustBeFirstL && MustBeFirstR)
4787 if (!CanNegateL && !CanNegateR)
4791 CanNegate = WillNegate && CanNegateL && CanNegateR;
4794 MustBeFirst = !CanNegate;
4796 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4799 MustBeFirst = MustBeFirstL || MustBeFirstR;
4806MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4809 MachineIRBuilder &MIB)
const {
4810 auto &MRI = *MIB.
getMRI();
4813 std::optional<ValueAndVReg>
C;
4817 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4818 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4819 else if (
C->Value.ule(31))
4820 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4822 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4828 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4829 CCmpOpc = AArch64::FCCMPHrr;
4832 CCmpOpc = AArch64::FCCMPSrr;
4835 CCmpOpc = AArch64::FCCMPDrr;
4845 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4846 CCmp.
addImm(
C->Value.getZExtValue());
4847 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4848 CCmp.
addImm(
C->Value.abs().getZExtValue());
4856MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4860 auto &MRI = *MIB.
getMRI();
4878 MachineInstr *ExtraCmp;
4880 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4892 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4893 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4894 Cmp->getOperand(3).getReg(), MIB);
4901 bool IsOR = Opcode == TargetOpcode::G_OR;
4907 assert(ValidL &&
"Valid conjunction/disjunction tree");
4914 assert(ValidR &&
"Valid conjunction/disjunction tree");
4919 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4928 bool NegateAfterAll;
4929 if (Opcode == TargetOpcode::G_OR) {
4932 assert(CanNegateR &&
"at least one side must be negatable");
4933 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4937 NegateAfterR =
true;
4940 NegateR = CanNegateR;
4941 NegateAfterR = !CanNegateR;
4944 NegateAfterAll = !Negate;
4946 assert(Opcode == TargetOpcode::G_AND &&
4947 "Valid conjunction/disjunction tree");
4948 assert(!Negate &&
"Valid conjunction/disjunction tree");
4952 NegateAfterR =
false;
4953 NegateAfterAll =
false;
4958 MachineInstr *CmpR =
4969MachineInstr *AArch64InstructionSelector::emitConjunction(
4971 bool DummyCanNegate;
4972 bool DummyMustBeFirst;
4979bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
4980 MachineInstr &CondMI) {
4991bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
4992 MachineRegisterInfo &MRI = *MIB.
getMRI();
5011 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5020 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5026 unsigned CondOpc = CondDef->
getOpcode();
5027 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5028 if (tryOptSelectConjunction(
I, *CondDef))
5034 if (CondOpc == TargetOpcode::G_ICMP) {
5063 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5064 I.getOperand(3).getReg(), CondCode, MIB);
5065 I.eraseFromParent();
5069MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5070 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5071 MachineIRBuilder &MIRBuilder)
const {
5073 "Unexpected MachineOperand");
5074 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5097 if (
isCMN(RHSDef,
P, MRI))
5112 if (
isCMN(LHSDef,
P, MRI)) {
5129 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5132 if (!ValAndVReg || ValAndVReg->Value != 0)
5142bool AArch64InstructionSelector::selectShuffleVector(
5143 MachineInstr &
I, MachineRegisterInfo &MRI) {
5144 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5145 Register Src1Reg =
I.getOperand(1).getReg();
5146 Register Src2Reg =
I.getOperand(2).getReg();
5147 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5149 "Expected equal shuffle types during selection");
5158 SmallVector<int> NewMask;
5159 bool FirstUsed =
false;
5160 bool SecondUsed =
false;
5161 for (
int M : Mask) {
5163 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5166 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5171 FirstUsed |=
M < NumElts;
5172 SecondUsed |=
M >= NumElts;
5173 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5182 for (
int &M : NewMask) {
5184 assert(M >= ByteLanes && M < 2 * ByteLanes);
5194 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5195 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5208 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5215 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5219 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5224 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5225 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5227 I.eraseFromParent();
5232 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5235 I.eraseFromParent();
5243 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5246 I.eraseFromParent();
5250MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5252 unsigned LaneIdx,
const RegisterBank &RB,
5253 MachineIRBuilder &MIRBuilder)
const {
5254 MachineInstr *InsElt =
nullptr;
5256 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5265 if (RB.
getID() == AArch64::FPRRegBankID) {
5266 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5269 .
addUse(InsSub->getOperand(0).getReg())
5281bool AArch64InstructionSelector::selectUSMovFromExtend(
5282 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5283 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5284 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5285 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5287 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5288 const Register DefReg =
MI.getOperand(0).getReg();
5289 const LLT DstTy = MRI.
getType(DefReg);
5292 if (DstSize != 32 && DstSize != 64)
5295 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5296 MI.getOperand(1).getReg(), MRI);
5302 const LLT VecTy = MRI.
getType(Src0);
5307 const MachineInstr *ScalarToVector = emitScalarToVector(
5308 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5309 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5315 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5317 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5319 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5321 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5323 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5331 MachineInstr *ExtI =
nullptr;
5332 if (DstSize == 64 && !IsSigned) {
5334 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5335 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5337 .
addImm(AArch64::sub_32);
5340 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5343 MI.eraseFromParent();
5347MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5348 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5350 if (DstSize == 128) {
5351 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5353 Op = AArch64::MOVIv16b_ns;
5355 Op = AArch64::MOVIv8b_ns;
5362 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5369MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5370 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5374 if (DstSize == 128) {
5375 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5377 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5379 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5399MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5400 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5404 if (DstSize == 128) {
5405 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5407 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5409 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5435MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5436 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5439 if (DstSize == 128) {
5440 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5442 Op = AArch64::MOVIv2d_ns;
5444 Op = AArch64::MOVID;
5450 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5457MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5458 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5462 if (DstSize == 128) {
5463 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5465 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5467 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5487MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5488 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5491 bool IsWide =
false;
5492 if (DstSize == 128) {
5493 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5495 Op = AArch64::FMOVv4f32_ns;
5498 Op = AArch64::FMOVv2f32_ns;
5507 Op = AArch64::FMOVv2f64_ns;
5511 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5516bool AArch64InstructionSelector::selectIndexedExtLoad(
5517 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5520 Register WriteBack = ExtLd.getWritebackReg();
5525 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5526 bool IsPre = ExtLd.isPre();
5528 unsigned InsertIntoSubReg = 0;
5534 if ((IsSExt && IsFPR) || Ty.
isVector())
5542 if (MemSizeBits == 8) {
5545 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5547 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5548 NewLdDstTy = IsDst64 ? s64 : s32;
5550 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5551 InsertIntoSubReg = AArch64::bsub;
5554 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5555 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5558 }
else if (MemSizeBits == 16) {
5561 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5563 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5564 NewLdDstTy = IsDst64 ? s64 : s32;
5566 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5567 InsertIntoSubReg = AArch64::hsub;
5570 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5571 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5574 }
else if (MemSizeBits == 32) {
5576 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5579 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5580 InsertIntoSubReg = AArch64::ssub;
5583 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5584 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5596 .addImm(Cst->getSExtValue());
5601 if (InsertIntoSubReg) {
5603 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5604 .addUse(LdMI.getReg(1))
5605 .
addImm(InsertIntoSubReg);
5608 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5615 MI.eraseFromParent();
5620bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5621 MachineRegisterInfo &MRI) {
5624 Register WriteBack = Ld.getWritebackReg();
5628 "Unexpected type for indexed load");
5629 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5632 return selectIndexedExtLoad(
MI, MRI);
5636 static constexpr unsigned GPROpcodes[] = {
5637 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5639 static constexpr unsigned FPROpcodes[] = {
5640 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5643 ? FPROpcodes[
Log2_32(MemSize)]
5644 : GPROpcodes[
Log2_32(MemSize)];
5647 static constexpr unsigned GPROpcodes[] = {
5648 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5650 static constexpr unsigned FPROpcodes[] = {
5651 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5652 AArch64::LDRDpost, AArch64::LDRQpost};
5654 ? FPROpcodes[
Log2_32(MemSize)]
5655 : GPROpcodes[
Log2_32(MemSize)];
5665 MI.eraseFromParent();
5669bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5670 MachineRegisterInfo &MRI) {
5676 "Unexpected type for indexed store");
5678 LocationSize MemSize =
I.getMMO().getSize();
5679 unsigned MemSizeInBytes = MemSize.
getValue();
5681 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5682 "Unexpected indexed store size");
5683 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5687 static constexpr unsigned GPROpcodes[] = {
5688 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5690 static constexpr unsigned FPROpcodes[] = {
5691 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5695 Opc = FPROpcodes[MemSizeLog2];
5697 Opc = GPROpcodes[MemSizeLog2];
5699 static constexpr unsigned GPROpcodes[] = {
5700 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5702 static constexpr unsigned FPROpcodes[] = {
5703 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5704 AArch64::STRDpost, AArch64::STRQpost};
5707 Opc = FPROpcodes[MemSizeLog2];
5709 Opc = GPROpcodes[MemSizeLog2];
5717 Str.cloneMemRefs(
I);
5719 I.eraseFromParent();
5724AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5725 MachineIRBuilder &MIRBuilder,
5726 MachineRegisterInfo &MRI) {
5729 assert((DstSize == 64 || DstSize == 128) &&
5730 "Unexpected vector constant size");
5733 if (DstSize == 128) {
5735 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5740 if (DstSize == 64) {
5743 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5746 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5753 APInt SplatValueAsInt =
5756 : SplatValue->getUniqueInteger();
5759 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5760 MachineInstr *NewOp;
5784 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5788 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5789 unsigned NegOpc) -> MachineInstr * {
5792 APInt NegBits(DstSize, 0);
5793 unsigned NumElts = DstSize / NumBits;
5794 for (
unsigned i = 0; i < NumElts; i++)
5795 NegBits |= Neg << (NumBits * i);
5796 NegBits = DefBits ^ NegBits;
5800 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5802 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5804 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5809 if ((R = TryWithFNeg(DefBits, 32,
5810 DstSize == 64 ? AArch64::FNEGv2f32
5811 : AArch64::FNEGv4f32)) ||
5812 (R = TryWithFNeg(DefBits, 64,
5813 DstSize == 64 ? AArch64::FNEGDr
5814 : AArch64::FNEGv2f64)) ||
5815 (STI.hasFullFP16() &&
5816 (R = TryWithFNeg(DefBits, 16,
5817 DstSize == 64 ? AArch64::FNEGv4f16
5818 : AArch64::FNEGv8f16))))
5824 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5828 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5830 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5834bool AArch64InstructionSelector::tryOptConstantBuildVec(
5835 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5836 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5838 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5844 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5845 Register OpReg =
I.getOperand(Idx).getReg();
5854 std::move(AnyConst->Value)));
5867 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5869 I.eraseFromParent();
5873bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5874 MachineInstr &
I, MachineRegisterInfo &MRI) {
5879 Register Dst =
I.getOperand(0).getReg();
5880 Register EltReg =
I.getOperand(1).getReg();
5881 LLT EltTy = MRI.
getType(EltReg);
5884 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5889 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5897 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5902 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5905 I.eraseFromParent();
5910bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5911 MachineRegisterInfo &MRI) {
5912 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5915 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5916 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5919 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5921 if (tryOptBuildVecToSubregToReg(
I, MRI))
5924 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5926 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5929 MachineInstr *ScalarToVec =
5931 I.getOperand(1).getReg(), MIB);
5940 MachineInstr *PrevMI = ScalarToVec;
5941 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5944 Register OpReg =
I.getOperand(i).getReg();
5947 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5954 if (DstSize < 128) {
5957 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5960 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5965 unsigned SubReg = 0;
5968 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5969 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5975 Register DstReg =
I.getOperand(0).getReg();
5977 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5978 MachineOperand &RegOp =
I.getOperand(1);
5998 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6000 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6009bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6012 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6014 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6015 auto &MRI = *MIB.
getMRI();
6016 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6019 "Destination must be 64 bits or 128 bits?");
6020 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6021 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6026 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6027 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6028 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6029 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6038bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6039 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6040 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6042 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6043 auto &MRI = *MIB.
getMRI();
6044 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6047 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6049 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6050 [](
auto MO) { return MO.getReg(); });
6054 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6069 .
addImm(LaneNo->getZExtValue())
6073 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6074 unsigned SubReg = AArch64::qsub0;
6075 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6076 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6077 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6078 : DstOp(
I.getOperand(Idx).
getReg())},
6080 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6085 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6091void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6094 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6095 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6096 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6099 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6100 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6109bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6110 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6111 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6112 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6116 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6117 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6121 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6131 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6134 .
addImm(LaneNo->getZExtValue())
6141bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6142 MachineInstr &
I, MachineRegisterInfo &MRI) {
6155 case Intrinsic::aarch64_ldxp:
6156 case Intrinsic::aarch64_ldaxp: {
6158 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6159 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6165 case Intrinsic::aarch64_neon_ld1x2: {
6166 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6169 Opc = AArch64::LD1Twov8b;
6171 Opc = AArch64::LD1Twov16b;
6173 Opc = AArch64::LD1Twov4h;
6175 Opc = AArch64::LD1Twov8h;
6177 Opc = AArch64::LD1Twov2s;
6179 Opc = AArch64::LD1Twov4s;
6181 Opc = AArch64::LD1Twov2d;
6182 else if (Ty ==
S64 || Ty == P0)
6183 Opc = AArch64::LD1Twov1d;
6186 selectVectorLoadIntrinsic(
Opc, 2,
I);
6189 case Intrinsic::aarch64_neon_ld1x3: {
6190 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6193 Opc = AArch64::LD1Threev8b;
6195 Opc = AArch64::LD1Threev16b;
6197 Opc = AArch64::LD1Threev4h;
6199 Opc = AArch64::LD1Threev8h;
6201 Opc = AArch64::LD1Threev2s;
6203 Opc = AArch64::LD1Threev4s;
6205 Opc = AArch64::LD1Threev2d;
6206 else if (Ty ==
S64 || Ty == P0)
6207 Opc = AArch64::LD1Threev1d;
6210 selectVectorLoadIntrinsic(
Opc, 3,
I);
6213 case Intrinsic::aarch64_neon_ld1x4: {
6214 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6217 Opc = AArch64::LD1Fourv8b;
6219 Opc = AArch64::LD1Fourv16b;
6221 Opc = AArch64::LD1Fourv4h;
6223 Opc = AArch64::LD1Fourv8h;
6225 Opc = AArch64::LD1Fourv2s;
6227 Opc = AArch64::LD1Fourv4s;
6229 Opc = AArch64::LD1Fourv2d;
6230 else if (Ty ==
S64 || Ty == P0)
6231 Opc = AArch64::LD1Fourv1d;
6234 selectVectorLoadIntrinsic(
Opc, 4,
I);
6237 case Intrinsic::aarch64_neon_ld2: {
6238 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6241 Opc = AArch64::LD2Twov8b;
6243 Opc = AArch64::LD2Twov16b;
6245 Opc = AArch64::LD2Twov4h;
6247 Opc = AArch64::LD2Twov8h;
6249 Opc = AArch64::LD2Twov2s;
6251 Opc = AArch64::LD2Twov4s;
6253 Opc = AArch64::LD2Twov2d;
6254 else if (Ty ==
S64 || Ty == P0)
6255 Opc = AArch64::LD1Twov1d;
6258 selectVectorLoadIntrinsic(
Opc, 2,
I);
6261 case Intrinsic::aarch64_neon_ld2lane: {
6262 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6265 Opc = AArch64::LD2i8;
6267 Opc = AArch64::LD2i16;
6269 Opc = AArch64::LD2i32;
6272 Opc = AArch64::LD2i64;
6275 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6279 case Intrinsic::aarch64_neon_ld2r: {
6280 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6283 Opc = AArch64::LD2Rv8b;
6285 Opc = AArch64::LD2Rv16b;
6287 Opc = AArch64::LD2Rv4h;
6289 Opc = AArch64::LD2Rv8h;
6291 Opc = AArch64::LD2Rv2s;
6293 Opc = AArch64::LD2Rv4s;
6295 Opc = AArch64::LD2Rv2d;
6296 else if (Ty ==
S64 || Ty == P0)
6297 Opc = AArch64::LD2Rv1d;
6300 selectVectorLoadIntrinsic(
Opc, 2,
I);
6303 case Intrinsic::aarch64_neon_ld3: {
6304 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6307 Opc = AArch64::LD3Threev8b;
6309 Opc = AArch64::LD3Threev16b;
6311 Opc = AArch64::LD3Threev4h;
6313 Opc = AArch64::LD3Threev8h;
6315 Opc = AArch64::LD3Threev2s;
6317 Opc = AArch64::LD3Threev4s;
6319 Opc = AArch64::LD3Threev2d;
6320 else if (Ty ==
S64 || Ty == P0)
6321 Opc = AArch64::LD1Threev1d;
6324 selectVectorLoadIntrinsic(
Opc, 3,
I);
6327 case Intrinsic::aarch64_neon_ld3lane: {
6328 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6331 Opc = AArch64::LD3i8;
6333 Opc = AArch64::LD3i16;
6335 Opc = AArch64::LD3i32;
6338 Opc = AArch64::LD3i64;
6341 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6345 case Intrinsic::aarch64_neon_ld3r: {
6346 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6349 Opc = AArch64::LD3Rv8b;
6351 Opc = AArch64::LD3Rv16b;
6353 Opc = AArch64::LD3Rv4h;
6355 Opc = AArch64::LD3Rv8h;
6357 Opc = AArch64::LD3Rv2s;
6359 Opc = AArch64::LD3Rv4s;
6361 Opc = AArch64::LD3Rv2d;
6362 else if (Ty ==
S64 || Ty == P0)
6363 Opc = AArch64::LD3Rv1d;
6366 selectVectorLoadIntrinsic(
Opc, 3,
I);
6369 case Intrinsic::aarch64_neon_ld4: {
6370 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6373 Opc = AArch64::LD4Fourv8b;
6375 Opc = AArch64::LD4Fourv16b;
6377 Opc = AArch64::LD4Fourv4h;
6379 Opc = AArch64::LD4Fourv8h;
6381 Opc = AArch64::LD4Fourv2s;
6383 Opc = AArch64::LD4Fourv4s;
6385 Opc = AArch64::LD4Fourv2d;
6386 else if (Ty ==
S64 || Ty == P0)
6387 Opc = AArch64::LD1Fourv1d;
6390 selectVectorLoadIntrinsic(
Opc, 4,
I);
6393 case Intrinsic::aarch64_neon_ld4lane: {
6394 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6397 Opc = AArch64::LD4i8;
6399 Opc = AArch64::LD4i16;
6401 Opc = AArch64::LD4i32;
6404 Opc = AArch64::LD4i64;
6407 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6411 case Intrinsic::aarch64_neon_ld4r: {
6412 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6415 Opc = AArch64::LD4Rv8b;
6417 Opc = AArch64::LD4Rv16b;
6419 Opc = AArch64::LD4Rv4h;
6421 Opc = AArch64::LD4Rv8h;
6423 Opc = AArch64::LD4Rv2s;
6425 Opc = AArch64::LD4Rv4s;
6427 Opc = AArch64::LD4Rv2d;
6428 else if (Ty ==
S64 || Ty == P0)
6429 Opc = AArch64::LD4Rv1d;
6432 selectVectorLoadIntrinsic(
Opc, 4,
I);
6435 case Intrinsic::aarch64_neon_st1x2: {
6436 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6439 Opc = AArch64::ST1Twov8b;
6441 Opc = AArch64::ST1Twov16b;
6443 Opc = AArch64::ST1Twov4h;
6445 Opc = AArch64::ST1Twov8h;
6447 Opc = AArch64::ST1Twov2s;
6449 Opc = AArch64::ST1Twov4s;
6451 Opc = AArch64::ST1Twov2d;
6452 else if (Ty ==
S64 || Ty == P0)
6453 Opc = AArch64::ST1Twov1d;
6456 selectVectorStoreIntrinsic(
I, 2,
Opc);
6459 case Intrinsic::aarch64_neon_st1x3: {
6460 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6463 Opc = AArch64::ST1Threev8b;
6465 Opc = AArch64::ST1Threev16b;
6467 Opc = AArch64::ST1Threev4h;
6469 Opc = AArch64::ST1Threev8h;
6471 Opc = AArch64::ST1Threev2s;
6473 Opc = AArch64::ST1Threev4s;
6475 Opc = AArch64::ST1Threev2d;
6476 else if (Ty ==
S64 || Ty == P0)
6477 Opc = AArch64::ST1Threev1d;
6480 selectVectorStoreIntrinsic(
I, 3,
Opc);
6483 case Intrinsic::aarch64_neon_st1x4: {
6484 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6487 Opc = AArch64::ST1Fourv8b;
6489 Opc = AArch64::ST1Fourv16b;
6491 Opc = AArch64::ST1Fourv4h;
6493 Opc = AArch64::ST1Fourv8h;
6495 Opc = AArch64::ST1Fourv2s;
6497 Opc = AArch64::ST1Fourv4s;
6499 Opc = AArch64::ST1Fourv2d;
6500 else if (Ty ==
S64 || Ty == P0)
6501 Opc = AArch64::ST1Fourv1d;
6504 selectVectorStoreIntrinsic(
I, 4,
Opc);
6507 case Intrinsic::aarch64_neon_st2: {
6508 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6511 Opc = AArch64::ST2Twov8b;
6513 Opc = AArch64::ST2Twov16b;
6515 Opc = AArch64::ST2Twov4h;
6517 Opc = AArch64::ST2Twov8h;
6519 Opc = AArch64::ST2Twov2s;
6521 Opc = AArch64::ST2Twov4s;
6523 Opc = AArch64::ST2Twov2d;
6524 else if (Ty ==
S64 || Ty == P0)
6525 Opc = AArch64::ST1Twov1d;
6528 selectVectorStoreIntrinsic(
I, 2,
Opc);
6531 case Intrinsic::aarch64_neon_st3: {
6532 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6535 Opc = AArch64::ST3Threev8b;
6537 Opc = AArch64::ST3Threev16b;
6539 Opc = AArch64::ST3Threev4h;
6541 Opc = AArch64::ST3Threev8h;
6543 Opc = AArch64::ST3Threev2s;
6545 Opc = AArch64::ST3Threev4s;
6547 Opc = AArch64::ST3Threev2d;
6548 else if (Ty ==
S64 || Ty == P0)
6549 Opc = AArch64::ST1Threev1d;
6552 selectVectorStoreIntrinsic(
I, 3,
Opc);
6555 case Intrinsic::aarch64_neon_st4: {
6556 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6559 Opc = AArch64::ST4Fourv8b;
6561 Opc = AArch64::ST4Fourv16b;
6563 Opc = AArch64::ST4Fourv4h;
6565 Opc = AArch64::ST4Fourv8h;
6567 Opc = AArch64::ST4Fourv2s;
6569 Opc = AArch64::ST4Fourv4s;
6571 Opc = AArch64::ST4Fourv2d;
6572 else if (Ty ==
S64 || Ty == P0)
6573 Opc = AArch64::ST1Fourv1d;
6576 selectVectorStoreIntrinsic(
I, 4,
Opc);
6579 case Intrinsic::aarch64_neon_st2lane: {
6580 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6583 Opc = AArch64::ST2i8;
6585 Opc = AArch64::ST2i16;
6587 Opc = AArch64::ST2i32;
6590 Opc = AArch64::ST2i64;
6593 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6597 case Intrinsic::aarch64_neon_st3lane: {
6598 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6601 Opc = AArch64::ST3i8;
6603 Opc = AArch64::ST3i16;
6605 Opc = AArch64::ST3i32;
6608 Opc = AArch64::ST3i64;
6611 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6615 case Intrinsic::aarch64_neon_st4lane: {
6616 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6619 Opc = AArch64::ST4i8;
6621 Opc = AArch64::ST4i16;
6623 Opc = AArch64::ST4i32;
6626 Opc = AArch64::ST4i64;
6629 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6633 case Intrinsic::aarch64_mops_memset_tag: {
6646 Register DstDef =
I.getOperand(0).getReg();
6648 Register DstUse =
I.getOperand(2).getReg();
6649 Register ValUse =
I.getOperand(3).getReg();
6650 Register SizeUse =
I.getOperand(4).getReg();
6657 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6658 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6663 case Intrinsic::ptrauth_resign_load_relative: {
6664 Register DstReg =
I.getOperand(0).getReg();
6665 Register ValReg =
I.getOperand(2).getReg();
6666 uint64_t AUTKey =
I.getOperand(3).getImm();
6667 Register AUTDisc =
I.getOperand(4).getReg();
6668 uint64_t PACKey =
I.getOperand(5).getImm();
6669 Register PACDisc =
I.getOperand(6).getReg();
6670 int64_t Addend =
I.getOperand(7).getImm();
6673 uint16_t AUTConstDiscC = 0;
6674 std::tie(AUTConstDiscC, AUTAddrDisc) =
6678 uint16_t PACConstDiscC = 0;
6679 std::tie(PACConstDiscC, PACAddrDisc) =
6682 MIB.
buildCopy({AArch64::X16}, {ValReg});
6696 I.eraseFromParent();
6701 I.eraseFromParent();
6705bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6706 MachineRegisterInfo &MRI) {
6712 case Intrinsic::ptrauth_resign: {
6713 Register DstReg =
I.getOperand(0).getReg();
6714 Register ValReg =
I.getOperand(2).getReg();
6715 uint64_t AUTKey =
I.getOperand(3).getImm();
6716 Register AUTDisc =
I.getOperand(4).getReg();
6717 uint64_t PACKey =
I.getOperand(5).getImm();
6718 Register PACDisc =
I.getOperand(6).getReg();
6721 uint16_t AUTConstDiscC = 0;
6722 std::tie(AUTConstDiscC, AUTAddrDisc) =
6726 uint16_t PACConstDiscC = 0;
6727 std::tie(PACConstDiscC, PACAddrDisc) =
6730 MIB.
buildCopy({AArch64::X16}, {ValReg});
6731 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6743 I.eraseFromParent();
6746 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6747 Register DstReg =
I.getOperand(0).getReg();
6748 Register ValReg =
I.getOperand(2).getReg();
6749 uint64_t AUTKey =
I.getOperand(3).getImm();
6750 Register AUTDisc =
I.getOperand(4).getReg();
6751 Register AUTPC =
I.getOperand(5).getReg();
6752 uint64_t PACKey =
I.getOperand(6).getImm();
6753 Register PACDisc =
I.getOperand(7).getReg();
6756 "auth_with_pc_and_resign only supports IA and IB keys");
6758 uint16_t PACConstDiscC = 0;
6760 std::tie(PACConstDiscC, PACAddrDisc) =
6763 if (PACAddrDisc == AArch64::NoRegister)
6764 PACAddrDisc = AArch64::XZR;
6766 MIB.
buildCopy({AArch64::X17}, {ValReg});
6767 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6779 I.eraseFromParent();
6782 case Intrinsic::ptrauth_auth: {
6783 Register DstReg =
I.getOperand(0).getReg();
6784 Register ValReg =
I.getOperand(2).getReg();
6785 uint64_t AUTKey =
I.getOperand(3).getImm();
6786 Register AUTDisc =
I.getOperand(4).getReg();
6789 uint16_t AUTConstDiscC = 0;
6790 std::tie(AUTConstDiscC, AUTAddrDisc) =
6794 MIB.
buildCopy({AArch64::X16}, {ValReg});
6795 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6816 I.eraseFromParent();
6819 case Intrinsic::frameaddress:
6820 case Intrinsic::returnaddress: {
6824 unsigned Depth =
I.getOperand(2).getImm();
6825 Register DstReg =
I.getOperand(0).getReg();
6828 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6829 if (!MFReturnAddr) {
6834 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6837 if (STI.hasPAuth()) {
6838 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6845 I.eraseFromParent();
6854 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6856 FrameAddr = NextFrame;
6859 if (IntrinID == Intrinsic::frameaddress)
6864 if (STI.hasPAuth()) {
6866 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6867 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6876 I.eraseFromParent();
6879 case Intrinsic::aarch64_neon_tbl2:
6880 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6882 case Intrinsic::aarch64_neon_tbl3:
6883 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6886 case Intrinsic::aarch64_neon_tbl4:
6887 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6889 case Intrinsic::aarch64_neon_tbx2:
6890 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6892 case Intrinsic::aarch64_neon_tbx3:
6893 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6895 case Intrinsic::aarch64_neon_tbx4:
6896 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6898 case Intrinsic::swift_async_context_addr:
6899 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6906 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6907 I.eraseFromParent();
6942bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6943 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6944 Register DefReg =
I.getOperand(0).getReg();
6945 Register Addr =
I.getOperand(1).getReg();
6947 Register AddrDisc =
I.getOperand(3).getReg();
6948 uint64_t Disc =
I.getOperand(4).getImm();
6958 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6974 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6986 const GlobalValue *GV;
6997 MachineIRBuilder MIB(
I);
7003 "unsupported non-GOT op flags on ptrauth global reference");
7005 "unsupported non-GOT reference to weak ptrauth global");
7008 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7015 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7016 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7017 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7020 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7025 I.eraseFromParent();
7037 "unsupported non-zero offset in weak ptrauth global reference");
7042 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7043 .addGlobalAddress(GV,
Offset)
7048 I.eraseFromParent();
7052void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7053 MachineRegisterInfo &MRI,
7054 unsigned NumVec,
unsigned Opc1,
7055 unsigned Opc2,
bool isExt) {
7056 Register DstReg =
I.getOperand(0).getReg();
7061 for (
unsigned i = 0; i < NumVec; i++)
7062 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7065 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7066 MachineInstrBuilder
Instr;
7073 I.eraseFromParent();
7076InstructionSelector::ComplexRendererFns
7077AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7079 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7080 return std::nullopt;
7081 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7082 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7085InstructionSelector::ComplexRendererFns
7086AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7088 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7089 return std::nullopt;
7091 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7094InstructionSelector::ComplexRendererFns
7095AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7097 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7098 return std::nullopt;
7099 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7100 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7103InstructionSelector::ComplexRendererFns
7104AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7106 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7107 return std::nullopt;
7109 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7117InstructionSelector::ComplexRendererFns
7118AArch64InstructionSelector::select12BitValueWithLeftShift(
7121 if (Immed >> 12 == 0) {
7123 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7125 Immed = Immed >> 12;
7127 return std::nullopt;
7131 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7132 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7139InstructionSelector::ComplexRendererFns
7140AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7147 if (MaybeImmed == std::nullopt)
7148 return std::nullopt;
7149 return select12BitValueWithLeftShift(*MaybeImmed);
7154InstructionSelector::ComplexRendererFns
7155AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7159 return std::nullopt;
7161 if (MaybeImmed == std::nullopt)
7162 return std::nullopt;
7169 return std::nullopt;
7175 Immed = ~((uint32_t)Immed) + 1;
7177 Immed = ~Immed + 1ULL;
7179 if (Immed & 0xFFFFFFFFFF000000ULL)
7180 return std::nullopt;
7182 Immed &= 0xFFFFFFULL;
7183 return select12BitValueWithLeftShift(Immed);
7200std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7201 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7202 if (
MI.getOpcode() == AArch64::G_SHL) {
7206 MI.getOperand(2).getReg(), MRI)) {
7207 const APInt ShiftVal = ValAndVeg->Value;
7210 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7213 return std::nullopt;
7221bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7222 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7223 bool IsAddrOperand)
const {
7228 MI.getParent()->getParent()->getFunction().hasOptSize())
7231 if (IsAddrOperand) {
7233 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7237 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7238 MachineInstr *OffsetInst =
7244 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7255 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7258InstructionSelector::ComplexRendererFns
7259AArch64InstructionSelector::selectExtendedSHL(
7260 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7261 unsigned SizeInBytes,
bool WantsExt)
const {
7262 assert(
Base.isReg() &&
"Expected base to be a register operand");
7263 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7268 unsigned OffsetOpc = OffsetInst->
getOpcode();
7269 bool LookedThroughZExt =
false;
7270 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7272 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7273 return std::nullopt;
7277 LookedThroughZExt =
true;
7279 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7280 return std::nullopt;
7283 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7284 if (LegalShiftVal == 0)
7285 return std::nullopt;
7286 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7287 return std::nullopt;
7298 if (OffsetOpc == TargetOpcode::G_SHL)
7299 return std::nullopt;
7305 return std::nullopt;
7310 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7314 if (OffsetOpc == TargetOpcode::G_MUL) {
7316 return std::nullopt;
7322 if ((ImmVal & 0x7) != ImmVal)
7323 return std::nullopt;
7327 if (ImmVal != LegalShiftVal)
7328 return std::nullopt;
7330 unsigned SignExtend = 0;
7334 if (!LookedThroughZExt) {
7336 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7338 return std::nullopt;
7343 return std::nullopt;
7349 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7354 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7355 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7356 [=](MachineInstrBuilder &MIB) {
7359 MIB.addImm(SignExtend);
7372InstructionSelector::ComplexRendererFns
7373AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7374 MachineOperand &Root,
unsigned SizeInBytes)
const {
7376 return std::nullopt;
7391 MachineInstr *PtrAdd =
7393 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7394 return std::nullopt;
7398 MachineInstr *OffsetInst =
7400 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7413InstructionSelector::ComplexRendererFns
7414AArch64InstructionSelector::selectAddrModeRegisterOffset(
7415 MachineOperand &Root)
const {
7421 return std::nullopt;
7427 return std::nullopt;
7430 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7431 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7432 [=](MachineInstrBuilder &MIB) {
7442InstructionSelector::ComplexRendererFns
7443AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7444 unsigned SizeInBytes)
const {
7447 return std::nullopt;
7448 MachineInstr *PtrAdd =
7451 return std::nullopt;
7469 unsigned Scale =
Log2_32(SizeInBytes);
7470 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7474 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7475 ImmOff < (0x1000 << Scale))
7476 return std::nullopt;
7481 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7485 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7491 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7492 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7497 return std::nullopt;
7501 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7507 return selectAddrModeRegisterOffset(Root);
7516InstructionSelector::ComplexRendererFns
7517AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7518 unsigned SizeInBytes)
const {
7521 MachineInstr *PtrAdd =
7523 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7524 return std::nullopt;
7545 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7554 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7555 return std::nullopt;
7559 getExtendTypeForInst(*OffsetInst, MRI,
true);
7561 return std::nullopt;
7564 MachineIRBuilder MIB(*PtrAdd);
7566 AArch64::GPR32RegClass, MIB);
7570 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7571 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7572 [=](MachineInstrBuilder &MIB) {
7573 MIB.addImm(SignExtend);
7583InstructionSelector::ComplexRendererFns
7584AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7585 unsigned Size)
const {
7586 MachineRegisterInfo &MRI =
7590 return std::nullopt;
7592 if (!isBaseWithConstantOffset(Root, MRI))
7593 return std::nullopt;
7597 MachineOperand &OffImm = RootDef->
getOperand(2);
7598 if (!OffImm.
isReg())
7599 return std::nullopt;
7601 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7602 return std::nullopt;
7604 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7606 return std::nullopt;
7609 if (RHSC >= -256 && RHSC < 256) {
7612 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7613 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7616 return std::nullopt;
7619InstructionSelector::ComplexRendererFns
7620AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7622 MachineRegisterInfo &MRI)
const {
7623 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7624 return std::nullopt;
7627 return std::nullopt;
7632 return std::nullopt;
7636 return std::nullopt;
7640 return std::nullopt;
7643 MachineIRBuilder MIRBuilder(RootDef);
7645 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7646 [=](MachineInstrBuilder &MIB) {
7647 MIB.addGlobalAddress(GV,
Offset,
7656InstructionSelector::ComplexRendererFns
7657AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7658 unsigned Size)
const {
7663 return std::nullopt;
7666 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7668 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7669 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7677 MachineInstr *RootParent = Root.
getParent();
7679 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7681 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7686 if (isBaseWithConstantOffset(Root, MRI)) {
7694 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7695 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7697 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7698 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7702 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7703 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7710 if (selectAddrModeUnscaled(Root,
Size))
7711 return std::nullopt;
7714 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7715 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7722 switch (
MI.getOpcode()) {
7725 case TargetOpcode::G_SHL:
7727 case TargetOpcode::G_LSHR:
7729 case TargetOpcode::G_ASHR:
7731 case TargetOpcode::G_ROTR:
7738InstructionSelector::ComplexRendererFns
7739AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7740 bool AllowROR)
const {
7742 return std::nullopt;
7743 MachineRegisterInfo &MRI =
7751 return std::nullopt;
7753 return std::nullopt;
7754 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7755 return std::nullopt;
7758 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7761 return std::nullopt;
7765 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7769 unsigned Val = *Immed & (NumBits - 1);
7772 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7773 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7777 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7778 unsigned Opc =
MI.getOpcode();
7781 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7783 if (
Opc == TargetOpcode::G_SEXT)
7786 Size =
MI.getOperand(2).getImm();
7787 assert(
Size != 64 &&
"Extend from 64 bits?");
7800 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7802 assert(
Size != 64 &&
"Extend from 64 bits?");
7817 if (
Opc != TargetOpcode::G_AND)
7836Register AArch64InstructionSelector::moveScalarRegClass(
7838 MachineRegisterInfo &MRI = *MIB.
getMRI();
7848 return Copy.getReg(0);
7853InstructionSelector::ComplexRendererFns
7854AArch64InstructionSelector::selectArithExtendedRegister(
7855 MachineOperand &Root)
const {
7857 return std::nullopt;
7858 MachineRegisterInfo &MRI =
7866 return std::nullopt;
7868 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7869 return std::nullopt;
7872 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7877 return std::nullopt;
7878 ShiftVal = *MaybeShiftVal;
7880 return std::nullopt;
7885 return std::nullopt;
7886 Ext = getExtendTypeForInst(*ExtDef, MRI);
7888 return std::nullopt;
7892 Ext = getExtendTypeForInst(*RootDef, MRI);
7894 return std::nullopt;
7902 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7903 if (isDef32(*ExtInst))
7904 return std::nullopt;
7910 MachineIRBuilder MIB(*RootDef);
7911 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7913 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7914 [=](MachineInstrBuilder &MIB) {
7915 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7919InstructionSelector::ComplexRendererFns
7920AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7922 return std::nullopt;
7923 MachineRegisterInfo &MRI =
7927 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7932 return std::nullopt;
7935 if (Unmerge->getNumDefs() == 2 &&
7937 Register ExtReg = Unmerge->getSourceReg();
7938 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7942 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7946 LaneIdx->Value.getSExtValue() == 1) {
7947 Register ExtReg = ExtElt->getVectorReg();
7948 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7952 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7953 auto LaneIdx = Subvec->getIndexImm();
7955 Register ExtReg = Subvec->getSrcVec();
7956 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7960 return std::nullopt;
7963InstructionSelector::ComplexRendererFns
7964AArch64InstructionSelector::selectCVTFixedPointVecBase(
7965 const MachineOperand &Root,
bool isReciprocal)
const {
7967 return std::nullopt;
7968 const MachineRegisterInfo &MRI =
7973 return std::nullopt;
7974 std::optional<ValueAndVReg> CstVal =
7977 return std::nullopt;
7983 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
7986 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
7989 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
7992 return std::nullopt;
7994 if (
unsigned FBits =
7996 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
7998 return std::nullopt;
8001InstructionSelector::ComplexRendererFns
8002AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8003 return selectCVTFixedPointVecBase(Root,
false);
8006InstructionSelector::ComplexRendererFns
8007AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8008 MachineOperand &Root)
const {
8009 return selectCVTFixedPointVecBase(Root,
true);
8012void AArch64InstructionSelector::renderFixedPointScalarXForm(
8013 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8014 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8015 "Expected vecshift immediate operand");
8016 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8019void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8020 const MachineInstr &
MI,
8025 InstructionSelector::ComplexRendererFns Renderer =
8026 selectCVTFixedPointVecBase(
MI.getOperand(OpIdx),
false);
8027 assert((Renderer && Renderer->size() == 1) &&
8028 "Expected selectCVTFixedPointVec to provide a function\n");
8029 (Renderer->front())(MIB);
8032void AArch64InstructionSelector::renderFixedPointRecipXForm(
8033 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8034 InstructionSelector::ComplexRendererFns Renderer =
8035 selectCVTFixedPointVecBase(
MI.getOperand(OpIdx),
true);
8036 assert((Renderer && Renderer->size() == 1) &&
8037 "Expected selectCVTFixedPosRecipOperandVec to provide a function\n");
8038 (Renderer->front())(MIB);
8041void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8042 const MachineInstr &
MI,
8044 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8045 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8046 "Expected G_CONSTANT");
8047 std::optional<int64_t> CstVal =
8049 assert(CstVal &&
"Expected constant value");
8053void AArch64InstructionSelector::renderLogicalImm32(
8054 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8055 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8056 "Expected G_CONSTANT");
8057 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8062void AArch64InstructionSelector::renderLogicalImm64(
8063 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8064 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8065 "Expected G_CONSTANT");
8066 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8071void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8072 const MachineInstr &
MI,
8074 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8075 "Expected G_UBSANTRAP");
8076 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8079void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8080 const MachineInstr &
MI,
8082 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8083 "Expected G_FCONSTANT");
8088void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8089 const MachineInstr &
MI,
8091 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8092 "Expected G_FCONSTANT");
8097void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8098 const MachineInstr &
MI,
8100 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8101 "Expected G_FCONSTANT");
8106void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8107 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8108 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8109 "Expected G_FCONSTANT");
8117bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8118 const MachineInstr &
MI,
unsigned NumBytes)
const {
8119 if (!
MI.mayLoadOrStore())
8122 "Expected load/store to have only one mem op!");
8123 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8126bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8127 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8135 switch (
MI.getOpcode()) {
8138 case TargetOpcode::COPY:
8139 case TargetOpcode::G_BITCAST:
8140 case TargetOpcode::G_TRUNC:
8141 case TargetOpcode::G_PHI:
8151 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8154 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8172 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8177 MO.setReg(Copy.getReg(0));
8186 for (
auto &BB : MF) {
8187 for (
auto &
MI : BB) {
8188 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8193 for (
auto *
MI : Phis) {
8215 bool HasGPROp =
false, HasFPROp =
false;
8219 const LLT &Ty = MRI.
getType(MO.getReg());
8229 if (RB->
getID() == AArch64::GPRRegBankID)
8235 if (HasGPROp && HasFPROp)
8241InstructionSelector *
8245 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
static std::pair< const TargetRegisterClass *, const TargetRegisterClass * > getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Helper function to get the source and destination register classes for a copy.
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc, appropriate for the register ban...
static bool getSubRegForClass(const TargetRegisterClass *RC, const TargetRegisterInfo &TRI, unsigned &SubReg)
Returns the correct subregister to use for a given register class.
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI, Register SrcReg, const TargetRegisterClass *To, unsigned SubReg)
Helper function for selectCopy.
static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P, Register RHS={}, MachineRegisterInfo *MRI=nullptr)
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, const AArch64RegisterBankInfo &RBI)
static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static MachineBasicBlock * emitSelect(MachineInstr &MI, MachineBasicBlock *BB, const TargetInstrInfo *TII, const PPCSubtarget &Subtarget)
Emit SELECT instruction, using ISEL if available, otherwise use branch-based control flow.
static StringRef getName(Value *V)
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
auto m_PosZeroFP()
Matches a floating-point positive zero.
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
@ O1
Optimize quickly without destroying debuggability.
@ O0
Disable as many optimizations as possible.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.