46#include "llvm/IR/IntrinsicsAArch64.h"
53#define DEBUG_TYPE "aarch64-isel"
66#define GET_GLOBALISEL_PREDICATE_BITSET
67#include "AArch64GenGlobalISel.inc"
68#undef GET_GLOBALISEL_PREDICATE_BITSET
88 ProduceNonFlagSettingCondBr =
136 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
203 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
205 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
207 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
209 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
226 unsigned Opc1,
unsigned Opc2,
bool isExt);
232 unsigned emitConstantPoolEntry(
const Constant *CPVal,
251 std::optional<CmpInst::Predicate> = std::nullopt)
const;
254 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
255 std::initializer_list<llvm::SrcOp> SrcOps,
257 const ComplexRendererFns &RenderFns = std::nullopt)
const;
292 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
315 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
337 std::pair<MachineInstr *, AArch64CC::CondCode>
372 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
373 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
374 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
375 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
377 template <
unsigned ShiftW
idth>
379 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
381 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
384 unsigned Size)
const;
386 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
387 return selectAddrModeUnscaled(Root, 1);
389 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
390 return selectAddrModeUnscaled(Root, 2);
392 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
393 return selectAddrModeUnscaled(Root, 4);
395 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
396 return selectAddrModeUnscaled(Root, 8);
398 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
399 return selectAddrModeUnscaled(Root, 16);
404 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
408 unsigned Size)
const;
410 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
411 return selectAddrModeIndexed(Root, Width / 8);
420 bool IsAddrOperand)
const;
423 unsigned SizeInBytes)
const;
431 bool WantsExt)
const;
432 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
434 unsigned SizeInBytes)
const;
436 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
437 return selectAddrModeXRO(Root, Width / 8);
441 unsigned SizeInBytes)
const;
443 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
444 return selectAddrModeWRO(Root, Width / 8);
448 bool AllowROR =
false)
const;
450 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
451 return selectShiftedRegister(Root);
454 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
455 return selectShiftedRegister(Root,
true);
465 bool IsLoadStore =
false)
const;
476 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
479 template <
unsigned W
idth>
480 ComplexRendererFns selectCVTFixedPoint(
MachineOperand &Root)
const;
481 template <
unsigned W
idth>
482 ComplexRendererFns selectCVTFixedPosRecipOperand(
MachineOperand &Root)
const;
483 ComplexRendererFns selectCVTFixedPointBase(
const MachineOperand &Root,
485 bool isReciprocal =
false)
const;
486 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
491 unsigned getFixedPointWidthFromOperand(
const MachineOperand &Root)
const;
493 int OpIdx = -1)
const;
497 unsigned Width,
bool isReciprocal)
const;
499 int OpIdx = -1)
const;
501 int OpIdx = -1)
const;
503 int OpIdx = -1)
const;
507 int OpIdx = -1)
const;
509 int OpIdx = -1)
const;
511 int OpIdx = -1)
const;
514 int OpIdx = -1)
const;
520 bool tryOptSelect(
GSelect &Sel);
527 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
540 bool ProduceNonFlagSettingCondBr =
false;
549#define GET_GLOBALISEL_PREDICATES_DECL
550#include "AArch64GenGlobalISel.inc"
551#undef GET_GLOBALISEL_PREDICATES_DECL
555#define GET_GLOBALISEL_TEMPORARIES_DECL
556#include "AArch64GenGlobalISel.inc"
557#undef GET_GLOBALISEL_TEMPORARIES_DECL
562#define GET_GLOBALISEL_IMPL
563#include "AArch64GenGlobalISel.inc"
564#undef GET_GLOBALISEL_IMPL
566AArch64InstructionSelector::AArch64InstructionSelector(
569 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
572#include
"AArch64GenGlobalISel.inc"
575#include
"AArch64GenGlobalISel.inc"
587 bool GetAllRegSet =
false) {
588 if (RB.
getID() == AArch64::GPRRegBankID) {
589 if (Ty.getSizeInBits() <= 32)
590 return GetAllRegSet ? &AArch64::GPR32allRegClass
591 : &AArch64::GPR32RegClass;
592 if (Ty.getSizeInBits() == 64)
593 return GetAllRegSet ? &AArch64::GPR64allRegClass
594 : &AArch64::GPR64RegClass;
595 if (Ty.getSizeInBits() == 128)
596 return &AArch64::XSeqPairsClassRegClass;
600 if (RB.
getID() == AArch64::FPRRegBankID) {
601 switch (Ty.getSizeInBits()) {
603 return &AArch64::FPR8RegClass;
605 return &AArch64::FPR16RegClass;
607 return &AArch64::FPR32RegClass;
609 return &AArch64::FPR64RegClass;
611 return &AArch64::FPR128RegClass;
623 bool GetAllRegSet =
false) {
626 "Expected FPR regbank for scalable type size");
627 return &AArch64::ZPRRegClass;
630 unsigned RegBankID = RB.
getID();
632 if (RegBankID == AArch64::GPRRegBankID) {
634 if (SizeInBits <= 32)
635 return GetAllRegSet ? &AArch64::GPR32allRegClass
636 : &AArch64::GPR32RegClass;
637 if (SizeInBits == 64)
638 return GetAllRegSet ? &AArch64::GPR64allRegClass
639 : &AArch64::GPR64RegClass;
640 if (SizeInBits == 128)
641 return &AArch64::XSeqPairsClassRegClass;
644 if (RegBankID == AArch64::FPRRegBankID) {
647 "Unexpected scalable register size");
648 return &AArch64::ZPRRegClass;
651 switch (SizeInBits) {
655 return &AArch64::FPR8RegClass;
657 return &AArch64::FPR16RegClass;
659 return &AArch64::FPR32RegClass;
661 return &AArch64::FPR64RegClass;
663 return &AArch64::FPR128RegClass;
673 switch (
TRI.getRegSizeInBits(*RC)) {
675 SubReg = AArch64::bsub;
678 SubReg = AArch64::hsub;
681 if (RC != &AArch64::FPR32RegClass)
682 SubReg = AArch64::sub_32;
684 SubReg = AArch64::ssub;
687 SubReg = AArch64::dsub;
691 dbgs() <<
"Couldn't find appropriate subregister for register class.");
700 switch (RB.
getID()) {
701 case AArch64::GPRRegBankID:
703 case AArch64::FPRRegBankID:
726 const unsigned RegClassIDs[],
728 unsigned NumRegs = Regs.
size();
731 assert(NumRegs >= 2 && NumRegs <= 4 &&
732 "Only support between two and 4 registers in a tuple!");
734 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
736 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
737 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
738 RegSequence.addUse(Regs[
I]);
739 RegSequence.addImm(SubRegs[
I]);
741 return RegSequence.getReg(0);
746 static const unsigned RegClassIDs[] = {
747 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
748 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
749 AArch64::dsub2, AArch64::dsub3};
750 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
755 static const unsigned RegClassIDs[] = {
756 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
757 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
758 AArch64::qsub2, AArch64::qsub3};
759 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
764 auto &
MBB = *
MI.getParent();
765 auto &MF = *
MBB.getParent();
766 auto &
MRI = MF.getRegInfo();
772 else if (Root.
isReg()) {
777 Immed = ValAndVReg->Value.getSExtValue();
788 if (RegBankID == AArch64::GPRRegBankID) {
790 switch (GenericOpc) {
791 case TargetOpcode::G_SHL:
792 return AArch64::LSLVWr;
793 case TargetOpcode::G_LSHR:
794 return AArch64::LSRVWr;
795 case TargetOpcode::G_ASHR:
796 return AArch64::ASRVWr;
800 }
else if (OpSize == 64) {
801 switch (GenericOpc) {
802 case TargetOpcode::G_SHL:
803 return AArch64::LSLVXr;
804 case TargetOpcode::G_LSHR:
805 return AArch64::LSRVXr;
806 case TargetOpcode::G_ASHR:
807 return AArch64::ASRVXr;
823 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
825 case AArch64::GPRRegBankID:
828 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
830 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
832 return isStore ? AArch64::STRWui : AArch64::LDRWui;
834 return isStore ? AArch64::STRXui : AArch64::LDRXui;
837 case AArch64::FPRRegBankID:
840 return isStore ? AArch64::STRBui : AArch64::LDRBui;
842 return isStore ? AArch64::STRHui : AArch64::LDRHui;
844 return isStore ? AArch64::STRSui : AArch64::LDRSui;
846 return isStore ? AArch64::STRDui : AArch64::LDRDui;
848 return isStore ? AArch64::STRQui : AArch64::LDRQui;
862 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
863 assert(To &&
"Destination register class cannot be null");
864 assert(SubReg &&
"Expected a valid subregister");
868 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
870 RegOp.
setReg(SubRegCopy.getReg(0));
874 if (!
I.getOperand(0).getReg().isPhysical())
883 Register DstReg =
I.getOperand(0).getReg();
884 Register SrcReg =
I.getOperand(1).getReg();
911 <<
TRI.getRegSizeInBits(DstReg,
MRI) <<
'\n');
915 if (
I.getOpcode() == TargetOpcode::G_BITCAST &&
917 if (DstRegBank.
getID() == AArch64::FPRRegBankID &&
918 SrcRegBank.
getID() == AArch64::GPRRegBankID) {
926 Register FPR32 =
MRI.createVirtualRegister(&AArch64::FPR32RegClass);
927 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::FMOVWSr))
930 I.setDesc(
TII.get(TargetOpcode::COPY));
931 I.getOperand(1).setReg(FPR32);
932 I.getOperand(1).setSubReg(AArch64::hsub);
936 if (DstRegBank.
getID() == AArch64::GPRRegBankID &&
937 SrcRegBank.
getID() == AArch64::FPRRegBankID) {
945 Register FPR32 =
MRI.createVirtualRegister(&AArch64::FPR32RegClass);
947 TII.get(TargetOpcode::SUBREG_TO_REG))
951 I.setDesc(
TII.get(AArch64::FMOVSWr));
952 I.getOperand(1).setReg(FPR32);
961 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
965 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
966 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
967 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
981 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
983 }
else if (SrcSize > DstSize) {
990 }
else if (DstSize > SrcSize) {
997 Register PromoteReg =
MRI.createVirtualRegister(PromotionRC);
999 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1003 RegOp.
setReg(PromoteReg);
1022 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1023 I.setDesc(
TII.get(AArch64::COPY));
1024 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1028 I.setDesc(
TII.get(AArch64::COPY));
1036 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1039 "Expected both select operands to have the same regbank?");
1045 "Expected 32 bit or 64 bit select only?");
1046 const bool Is32Bit =
Size == 32;
1048 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1055 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1057 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &
CC, &
MRI,
1072 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1089 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1108 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1130 if (!TrueCst && !FalseCst)
1133 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1134 if (TrueCst && FalseCst) {
1135 int64_t
T = TrueCst->Value.getSExtValue();
1136 int64_t
F = FalseCst->Value.getSExtValue();
1138 if (
T == 0 &&
F == 1) {
1140 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1146 if (
T == 0 &&
F == -1) {
1148 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1156 int64_t
T = TrueCst->Value.getSExtValue();
1159 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1168 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1177 int64_t
F = FalseCst->Value.getSExtValue();
1180 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1187 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1200 return &*SelectInst;
1205 MachineRegisterInfo *
MRI =
nullptr) {
1218 if (ValAndVReg && ValAndVReg->Value == 0)
1225 if (ValAndVReg && ValAndVReg->Value == 0)
1329 assert(
Reg.isValid() &&
"Expected valid register!");
1330 bool HasZext =
false;
1332 unsigned Opc =
MI->getOpcode();
1334 if (!
MI->getOperand(0).isReg() ||
1335 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1343 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1344 Opc == TargetOpcode::G_TRUNC) {
1345 if (
Opc == TargetOpcode::G_ZEXT)
1348 Register NextReg =
MI->getOperand(1).getReg();
1350 if (!NextReg.
isValid() || !
MRI.hasOneNonDBGUse(NextReg))
1352 TypeSize InSize =
MRI.getType(NextReg).getSizeInBits();
1362 std::optional<uint64_t>
C;
1367 case TargetOpcode::G_AND:
1368 case TargetOpcode::G_XOR: {
1369 TestReg =
MI->getOperand(1).getReg();
1370 Register ConstantReg =
MI->getOperand(2).getReg();
1381 C = VRegAndVal->Value.getZExtValue();
1383 C = VRegAndVal->Value.getSExtValue();
1387 case TargetOpcode::G_ASHR:
1388 case TargetOpcode::G_LSHR:
1389 case TargetOpcode::G_SHL: {
1390 TestReg =
MI->getOperand(1).getReg();
1394 C = VRegAndVal->Value.getSExtValue();
1406 unsigned TestRegSize =
MRI.getType(TestReg).getSizeInBits();
1410 case TargetOpcode::G_AND:
1412 if ((*
C >> Bit) & 1)
1415 case TargetOpcode::G_SHL:
1418 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1423 case TargetOpcode::G_ASHR:
1428 if (Bit >= TestRegSize)
1429 Bit = TestRegSize - 1;
1431 case TargetOpcode::G_LSHR:
1433 if ((Bit + *
C) < TestRegSize) {
1438 case TargetOpcode::G_XOR:
1447 if ((*
C >> Bit) & 1)
1462MachineInstr *AArch64InstructionSelector::emitTestBit(
1463 Register TestReg,
uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1464 MachineIRBuilder &MIB)
const {
1466 assert(ProduceNonFlagSettingCondBr &&
1467 "Cannot emit TB(N)Z with speculation tracking!");
1468 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1475 assert(Bit < 64 &&
"Bit is too large!");
1479 bool UseWReg =
Bit < 32;
1480 unsigned NecessarySize = UseWReg ? 32 : 64;
1481 if (
Size != NecessarySize)
1482 TestReg = moveScalarRegClass(
1483 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1486 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1487 {AArch64::TBZW, AArch64::TBNZW}};
1488 unsigned Opc = OpcTable[UseWReg][IsNegative];
1495bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1496 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1497 MachineIRBuilder &MIB)
const {
1498 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1525 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1532 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1536MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1538 MachineBasicBlock *DestMBB,
1539 MachineIRBuilder &MIB)
const {
1540 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1541 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1543 AArch64::GPRRegBankID &&
1544 "Expected GPRs only?");
1548 assert(Width <= 64 &&
"Expected width to be at most 64?");
1549 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1550 {AArch64::CBNZW, AArch64::CBNZX}};
1551 unsigned Opc = OpcTable[IsNegative][Width == 64];
1552 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1557bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1558 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1560 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1568 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1572 I.eraseFromParent();
1576bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1577 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1579 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1585 if (!ProduceNonFlagSettingCondBr)
1588 MachineRegisterInfo &
MRI = *MIB.
getMRI();
1589 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1604 if (VRegAndVal && !AndInst) {
1605 int64_t
C = VRegAndVal->Value.getSExtValue();
1611 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1612 I.eraseFromParent();
1620 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1621 I.eraseFromParent();
1629 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1630 I.eraseFromParent();
1644 if (VRegAndVal && VRegAndVal->Value == 0) {
1652 tryOptAndIntoCompareBranch(
1654 I.eraseFromParent();
1660 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1662 I.eraseFromParent();
1671bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1672 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1674 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1675 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1679 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1686 I.eraseFromParent();
1690bool AArch64InstructionSelector::selectCompareBranch(
1692 Register CondReg =
I.getOperand(0).getReg();
1697 if (CCMIOpc == TargetOpcode::G_FCMP)
1698 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1699 if (CCMIOpc == TargetOpcode::G_ICMP)
1700 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1705 if (ProduceNonFlagSettingCondBr) {
1706 emitTestBit(CondReg, 0,
true,
1707 I.getOperand(1).getMBB(), MIB);
1708 I.eraseFromParent();
1718 .
addMBB(
I.getOperand(1).getMBB());
1719 I.eraseFromParent();
1728 assert(
MRI.getType(
Reg).isVector() &&
"Expected a *vector* shift operand");
1732 return std::nullopt;
1742 return std::nullopt;
1745 if (
Imm >= SrcTy.getElementType().getSizeInBits())
1746 return std::nullopt;
1750bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1751 MachineRegisterInfo &
MRI) {
1752 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1753 Register DstReg =
I.getOperand(0).getReg();
1755 Register Src1Reg =
I.getOperand(1).getReg();
1756 Register Src2Reg =
I.getOperand(2).getReg();
1767 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1769 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1771 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1773 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1775 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1777 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1779 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1791 I.eraseFromParent();
1795bool AArch64InstructionSelector::selectVectorAshrLshr(
1796 MachineInstr &
I, MachineRegisterInfo &
MRI) {
1797 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1798 I.getOpcode() == TargetOpcode::G_LSHR);
1799 Register DstReg =
I.getOperand(0).getReg();
1801 Register Src1Reg =
I.getOperand(1).getReg();
1802 Register Src2Reg =
I.getOperand(2).getReg();
1807 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1817 unsigned NegOpc = 0;
1819 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1821 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1822 NegOpc = AArch64::NEGv2i64;
1824 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1825 NegOpc = AArch64::NEGv4i32;
1827 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1828 NegOpc = AArch64::NEGv2i32;
1830 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1831 NegOpc = AArch64::NEGv4i16;
1833 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1834 NegOpc = AArch64::NEGv8i16;
1836 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1837 NegOpc = AArch64::NEGv16i8;
1839 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1840 NegOpc = AArch64::NEGv8i8;
1846 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1850 I.eraseFromParent();
1854bool AArch64InstructionSelector::selectVaStartAAPCS(
1864 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1866 const auto *PtrRegClass =
1867 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1869 const MCInstrDesc &MCIDAddAddr =
1871 const MCInstrDesc &MCIDStoreAddr =
1883 const auto VAList =
I.getOperand(0).getReg();
1886 unsigned OffsetBytes = 0;
1890 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1892 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1899 const auto *MMO = *
I.memoperands_begin();
1900 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1903 .
addImm(OffsetBytes / PtrSize)
1905 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1909 OffsetBytes += PtrSize;
1925 const auto PushIntConstant = [&](
const int32_t
Value) {
1926 constexpr int IntSize = 4;
1929 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
1934 const auto *MMO = *
I.memoperands_begin();
1935 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
1938 .
addImm(OffsetBytes / IntSize)
1940 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1943 OffsetBytes += IntSize;
1947 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
1950 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
1954 I.eraseFromParent();
1958bool AArch64InstructionSelector::selectVaStartDarwin(
1960 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1961 Register ListReg =
I.getOperand(0).getReg();
1966 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
1974 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
1982 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
1989 I.eraseFromParent();
1993void AArch64InstructionSelector::materializeLargeCMVal(
1994 MachineInstr &
I,
const Value *
V,
unsigned OpFlags) {
1999 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2014 GV, MovZ->getOperand(1).getOffset(), Flags));
2018 MovZ->getOperand(1).getOffset(), Flags));
2024 Register DstReg = BuildMovK(MovZ.getReg(0),
2030bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2035 switch (
I.getOpcode()) {
2036 case TargetOpcode::G_CONSTANT: {
2037 Register DefReg =
I.getOperand(0).getReg();
2044 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2045 I.getOperand(1).setCImm(
2050 I.getOperand(0).setReg(WideReg);
2059 if (PtrSize != 32 && PtrSize != 64)
2065 case TargetOpcode::G_STORE: {
2066 bool Changed = contractCrossBankCopyIntoStore(
I,
MRI);
2067 MachineOperand &SrcOp =
I.getOperand(0);
2080 case TargetOpcode::G_PTR_ADD: {
2084 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2086 return convertPtrAddToAdd(
I,
MRI);
2088 case TargetOpcode::G_LOAD: {
2093 Register DstReg =
I.getOperand(0).getReg();
2100 case TargetOpcode::G_VECREDUCE_ADD:
2101 case TargetOpcode::G_VECREDUCE_SMAX:
2102 case TargetOpcode::G_VECREDUCE_SMIN:
2103 case TargetOpcode::G_VECREDUCE_UMAX:
2104 case TargetOpcode::G_VECREDUCE_UMIN: {
2107 Register DstReg =
I.getOperand(0).getReg();
2109 if (DstRB.
getID() != AArch64::GPRRegBankID)
2114 getRegClassForTypeOnBank(DstTy, DstRB,
true);
2120 I.getOperand(0).setReg(FPRDst);
2122 BuildMI(
MBB, std::next(
I.getIterator()), MIMetadata(
I),
2123 TII.get(TargetOpcode::COPY), DstReg)
2127 case TargetOpcode::G_SPLAT_VECTOR: {
2129 LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
2136 I.getOperand(1).setReg(NewSrc.getReg(0));
2139 case AArch64::G_INSERT_VECTOR_ELT: {
2140 LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
2141 LLT SrcVecTy =
MRI.
getType(
I.getOperand(1).getReg());
2150 I.getOperand(2).setReg(NewSrc.getReg(0));
2154 Register EltReg =
I.getOperand(2).getReg();
2162 I.getOperand(2).setReg(NewElt.getReg(0));
2167 case TargetOpcode::G_UITOFP:
2168 case TargetOpcode::G_SITOFP: {
2173 Register SrcReg =
I.getOperand(1).getReg();
2175 LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
2184 I.getOperand(1).setReg(
Copy.getReg(0));
2186 getRegClassForTypeOnBank(
2187 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2189 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2190 I.setDesc(
TII.get(AArch64::G_SITOF));
2192 I.setDesc(
TII.get(AArch64::G_UITOF));
2210bool AArch64InstructionSelector::convertPtrAddToAdd(
2211 MachineInstr &
I, MachineRegisterInfo &
MRI) {
2212 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2213 Register DstReg =
I.getOperand(0).getReg();
2214 Register AddOp1Reg =
I.getOperand(1).getReg();
2219 const LLT CastPtrTy = PtrTy.
isVector()
2231 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2233 I.getOperand(1).setReg(PtrToInt.getReg(0));
2234 if (!select(*PtrToInt)) {
2235 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2244 I.getOperand(2).setReg(NegatedReg);
2245 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2249bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2250 MachineRegisterInfo &
MRI) {
2254 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2255 const auto &MO =
I.getOperand(2);
2260 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
2264 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2265 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2267 if (!Imm1Fn || !Imm2Fn)
2271 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2272 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2274 for (
auto &RenderFn : *Imm1Fn)
2276 for (
auto &RenderFn : *Imm2Fn)
2279 I.eraseFromParent();
2284bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2285 MachineInstr &
I, MachineRegisterInfo &
MRI) {
2286 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2305 Register StoreSrcReg =
I.getOperand(0).getReg();
2322 I.getOperand(0).setReg(DefDstReg);
2326bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2327 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2328 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2334 switch (
I.getOpcode()) {
2335 case TargetOpcode::G_SPLAT_VECTOR: {
2336 Register Dst =
I.getOperand(0).getReg();
2342 Register Src =
I.getOperand(1).getReg();
2344 Src,
MRI,
true,
true);
2355 if (!emitConstantVector(Dst, CV,
Imm,
MRI))
2357 I.eraseFromParent();
2360 case TargetOpcode::G_SEXT:
2363 if (selectUSMovFromExtend(
I,
MRI))
2366 case TargetOpcode::G_BR:
2368 case TargetOpcode::G_SHL:
2369 return earlySelectSHL(
I,
MRI);
2370 case TargetOpcode::G_CONSTANT: {
2371 bool IsZero =
false;
2372 if (
I.getOperand(1).isCImm())
2373 IsZero =
I.getOperand(1).getCImm()->isZero();
2374 else if (
I.getOperand(1).isImm())
2375 IsZero =
I.getOperand(1).getImm() == 0;
2380 Register DefReg =
I.getOperand(0).getReg();
2383 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2386 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2391 I.setDesc(
TII.get(TargetOpcode::COPY));
2395 case TargetOpcode::G_ADD: {
2404 Register AddDst =
I.getOperand(0).getReg();
2405 Register AddLHS =
I.getOperand(1).getReg();
2406 Register AddRHS =
I.getOperand(2).getReg();
2416 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2436 MachineInstr *
Cmp = MatchCmp(AddRHS);
2440 Cmp = MatchCmp(AddRHS);
2444 auto &PredOp =
Cmp->getOperand(1);
2446 emitIntegerCompare(
Cmp->getOperand(2),
2447 Cmp->getOperand(3), PredOp, MIB);
2451 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2452 I.eraseFromParent();
2455 case TargetOpcode::G_OR: {
2459 Register Dst =
I.getOperand(0).getReg();
2478 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2481 int64_t Immr =
Size - ShiftImm;
2482 int64_t Imms =
Size - ShiftImm - 1;
2483 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2484 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2485 I.eraseFromParent();
2488 case TargetOpcode::G_FENCE: {
2489 if (
I.getOperand(1).getImm() == 0)
2493 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2494 I.eraseFromParent();
2497 case TargetOpcode::G_BRINDIRECT: {
2499 if (std::optional<uint16_t> BADisc =
2501 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2505 I.eraseFromParent();
2518bool AArch64InstructionSelector::select(MachineInstr &
I) {
2519 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2520 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2529 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2535 unsigned Opcode =
I.getOpcode();
2537 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2540 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2545 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2546 const Register DefReg =
I.getOperand(0).getReg();
2560 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2567 I.setDesc(
TII.get(TargetOpcode::PHI));
2579 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2581 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2588 if (preISelLower(
I)) {
2589 Opcode =
I.getOpcode();
2600 if (selectImpl(
I, *CoverageInfo))
2604 I.getOperand(0).isReg() ?
MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2607 case TargetOpcode::G_SBFX:
2608 case TargetOpcode::G_UBFX: {
2609 static const unsigned OpcTable[2][2] = {
2610 {AArch64::UBFMWri, AArch64::UBFMXri},
2611 {AArch64::SBFMWri, AArch64::SBFMXri}};
2612 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2614 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2617 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2620 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2621 auto LSB = Cst1->Value.getZExtValue();
2622 auto Width = Cst2->Value.getZExtValue();
2626 .
addImm(LSB + Width - 1);
2627 I.eraseFromParent();
2631 case TargetOpcode::G_BRCOND:
2632 return selectCompareBranch(
I, MF,
MRI);
2634 case TargetOpcode::G_BRJT:
2635 return selectBrJT(
I,
MRI);
2637 case AArch64::G_ADD_LOW: {
2643 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2644 I.setDesc(
TII.get(AArch64::ADDXri));
2650 "Expected small code model");
2652 auto Op2 =
I.getOperand(2);
2653 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2654 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2655 Op1.getTargetFlags())
2657 Op2.getTargetFlags());
2658 I.eraseFromParent();
2663 case TargetOpcode::G_FCONSTANT: {
2664 const Register DefReg =
I.getOperand(0).getReg();
2671 (DefSize == 16 || DefSize == 32 || DefSize == 64 || DefSize == 128) &&
2672 "Unexpected destination size for G_FCONSTANT?");
2675 const ConstantFP *FPImm =
I.getOperand(1).getFPImm();
2676 APInt
Imm = DefSize >= 64
2679 if (
auto *Mov = emitConstantMOVVector(
2680 DefSize >= 64 ? DstOp(DefReg) : DstOp(&AArch64::FPR64RegClass),
Imm,
2683 MIB.
buildInstr(TargetOpcode::COPY, {DefReg}, {})
2684 .addReg(Mov->getOperand(0).getReg(), {},
2685 DefSize == 16 ? AArch64::hsub : AArch64::ssub);
2688 I.eraseFromParent();
2694 bool OptForSize = shouldOptForSize(&MF);
2696 if ((DefSize == 32 || DefSize == 64) &&
2701 DefSize == 64 ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass);
2702 MachineOperand &RegOp =
I.getOperand(0);
2708 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2712 MachineOperand &ImmOp =
I.getOperand(1);
2716 const unsigned MovOpc =
2717 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2718 I.setDesc(
TII.get(MovOpc));
2726 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2729 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2730 I.eraseFromParent();
2733 case TargetOpcode::G_EXTRACT: {
2734 Register DstReg =
I.getOperand(0).getReg();
2735 Register SrcReg =
I.getOperand(1).getReg();
2749 unsigned Offset =
I.getOperand(2).getImm();
2758 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2760 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2762 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2764 AArch64::GPR64RegClass, NewI->getOperand(0));
2765 I.eraseFromParent();
2771 unsigned LaneIdx =
Offset / 64;
2772 MachineInstr *Extract = emitExtractVectorElt(
2773 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2776 I.eraseFromParent();
2780 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2781 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2786 "unexpected G_EXTRACT types");
2793 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2794 .addReg(DstReg, {}, AArch64::sub_32);
2796 AArch64::GPR32RegClass,
MRI);
2797 I.getOperand(0).setReg(DstReg);
2803 case TargetOpcode::G_INSERT: {
2804 LLT SrcTy =
MRI.
getType(
I.getOperand(2).getReg());
2805 LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
2812 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2813 unsigned LSB =
I.getOperand(3).getImm();
2815 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2816 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2820 "unexpected G_INSERT types");
2827 TII.get(AArch64::SUBREG_TO_REG))
2829 .
addUse(
I.getOperand(2).getReg())
2830 .
addImm(AArch64::sub_32);
2832 AArch64::GPR32RegClass,
MRI);
2833 I.getOperand(2).setReg(SrcReg);
2838 case TargetOpcode::G_FRAME_INDEX: {
2845 I.setDesc(
TII.get(AArch64::ADDXri));
2855 case TargetOpcode::G_GLOBAL_VALUE: {
2856 const GlobalValue *GV =
nullptr;
2858 if (
I.getOperand(1).isSymbol()) {
2859 OpFlags =
I.getOperand(1).getTargetFlags();
2865 return selectTLSGlobalValue(
I,
MRI);
2871 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2872 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2873 I.getOperand(1).setTargetFlags(OpFlags);
2874 I.addImplicitDefUseOperands(MF);
2875 I.setImplicitPhysRegDefsDead();
2879 materializeLargeCMVal(
I, GV, OpFlags);
2880 I.eraseFromParent();
2883 I.setDesc(
TII.get(AArch64::ADR));
2884 I.getOperand(1).setTargetFlags(OpFlags);
2886 I.setDesc(
TII.get(AArch64::MOVaddr));
2888 MachineInstrBuilder MIB(MF,
I);
2889 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2896 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2897 return selectPtrAuthGlobalValue(
I,
MRI);
2899 case TargetOpcode::G_ZEXTLOAD:
2900 case TargetOpcode::G_LOAD:
2901 case TargetOpcode::G_STORE: {
2903 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2918 assert(MemSizeInBytes <= 8 &&
2919 "128-bit atomics should already be custom-legalized");
2922 static constexpr unsigned LDAPROpcodes[] = {
2923 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2924 static constexpr unsigned LDAROpcodes[] = {
2925 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2926 ArrayRef<unsigned> Opcodes =
2927 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2930 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2932 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2933 AArch64::STLRW, AArch64::STLRX};
2938 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2939 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2940 I.getOperand(0).setReg(NewVal);
2942 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2953 "Load/Store pointer operand isn't a GPR");
2955 "Load/Store pointer operand isn't a pointer");
2965 RB.
getID() == AArch64::FPRRegBankID) {
2968 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2974 .addReg(ValReg, {}, SubReg)
2981 if (RB.
getID() == AArch64::FPRRegBankID) {
2984 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2994 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
2997 auto SubRegRC = getRegClassForTypeOnBank(
MRI.
getType(OldDst), RB);
3006 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3008 const unsigned NewOpc =
3010 if (NewOpc ==
I.getOpcode())
3014 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3017 I.setDesc(
TII.get(NewOpc));
3023 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3024 Register CurValReg =
I.getOperand(0).getReg();
3025 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3026 NewInst.cloneMemRefs(
I);
3027 for (
auto &Fn : *AddrModeFns)
3029 I.eraseFromParent();
3033 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3038 if (Opcode == TargetOpcode::G_STORE) {
3041 if (CVal && CVal->Value == 0) {
3043 case AArch64::STRWui:
3044 case AArch64::STRHHui:
3045 case AArch64::STRBBui:
3046 LoadStore->getOperand(0).setReg(AArch64::WZR);
3048 case AArch64::STRXui:
3049 LoadStore->getOperand(0).setReg(AArch64::XZR);
3055 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3056 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3068 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3070 .
addImm(AArch64::sub_32);
3079 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3080 case TargetOpcode::G_INDEXED_SEXTLOAD:
3081 return selectIndexedExtLoad(
I,
MRI);
3082 case TargetOpcode::G_INDEXED_LOAD:
3083 return selectIndexedLoad(
I,
MRI);
3084 case TargetOpcode::G_INDEXED_STORE:
3087 case TargetOpcode::G_LSHR:
3088 case TargetOpcode::G_ASHR:
3090 return selectVectorAshrLshr(
I,
MRI);
3092 case TargetOpcode::G_SHL: {
3093 if (Opcode == TargetOpcode::G_SHL &&
3095 return selectVectorSHL(
I,
MRI);
3102 Register SrcReg =
I.getOperand(1).getReg();
3103 Register ShiftReg =
I.getOperand(2).getReg();
3110 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3111 .addReg(ShiftReg, {}, AArch64::sub_32);
3113 I.getOperand(2).setReg(Trunc.getReg(0));
3118 const Register DefReg =
I.getOperand(0).getReg();
3122 if (NewOpc ==
I.getOpcode())
3125 I.setDesc(
TII.get(NewOpc));
3133 case TargetOpcode::G_PTR_ADD: {
3134 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3135 I.eraseFromParent();
3139 case TargetOpcode::G_SADDE:
3140 case TargetOpcode::G_UADDE:
3141 case TargetOpcode::G_SSUBE:
3142 case TargetOpcode::G_USUBE:
3143 case TargetOpcode::G_SADDO:
3144 case TargetOpcode::G_UADDO:
3145 case TargetOpcode::G_SSUBO:
3146 case TargetOpcode::G_USUBO:
3147 return selectOverflowOp(
I,
MRI);
3149 case TargetOpcode::G_PTRMASK: {
3150 Register MaskReg =
I.getOperand(2).getReg();
3157 I.setDesc(
TII.get(AArch64::ANDXri));
3158 I.getOperand(2).ChangeToImmediate(
3164 case TargetOpcode::G_PTRTOINT:
3165 case TargetOpcode::G_TRUNC: {
3166 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3167 const LLT SrcTy =
MRI.
getType(
I.getOperand(1).getReg());
3169 const Register DstReg =
I.getOperand(0).getReg();
3170 const Register SrcReg =
I.getOperand(1).getReg();
3177 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3181 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3192 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3196 if (DstRC == SrcRC) {
3198 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3202 }
else if (DstRC == &AArch64::GPR32RegClass &&
3203 SrcRC == &AArch64::GPR64RegClass) {
3204 I.getOperand(1).setSubReg(AArch64::sub_32);
3207 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3211 I.setDesc(
TII.get(TargetOpcode::COPY));
3213 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3216 I.setDesc(
TII.get(AArch64::XTNv4i16));
3222 MachineInstr *Extract = emitExtractVectorElt(
3226 I.eraseFromParent();
3231 if (Opcode == TargetOpcode::G_PTRTOINT) {
3232 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3233 I.setDesc(
TII.get(TargetOpcode::COPY));
3241 case TargetOpcode::G_ANYEXT: {
3242 if (selectUSMovFromExtend(
I,
MRI))
3245 const Register DstReg =
I.getOperand(0).getReg();
3246 const Register SrcReg =
I.getOperand(1).getReg();
3249 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3251 <<
", expected: GPR\n");
3256 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3258 <<
", expected: GPR\n");
3265 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3269 if (DstSize != 64 && DstSize > 32) {
3271 <<
", expected: 32 or 64\n");
3281 .
addImm(AArch64::sub_32);
3282 I.getOperand(1).setReg(ExtSrc);
3287 case TargetOpcode::G_ZEXT:
3288 case TargetOpcode::G_SEXT_INREG:
3289 case TargetOpcode::G_SEXT: {
3290 if (selectUSMovFromExtend(
I,
MRI))
3293 unsigned Opcode =
I.getOpcode();
3294 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3295 const Register DefReg =
I.getOperand(0).getReg();
3296 Register SrcReg =
I.getOperand(1).getReg();
3304 if (Opcode == TargetOpcode::G_SEXT_INREG)
3305 SrcSize =
I.getOperand(2).getImm();
3311 AArch64::GPRRegBankID &&
3312 "Unexpected ext regbank");
3326 if (LoadMI && IsGPR) {
3327 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3328 unsigned BytesLoaded = MemOp->getSize().getValue();
3335 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3338 const Register ZReg = AArch64::WZR;
3339 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3342 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3343 .addUse(SubregToRegSrc)
3344 .
addImm(AArch64::sub_32);
3348 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3358 I.eraseFromParent();
3363 if (DstSize == 64) {
3364 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3372 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3373 {&AArch64::GPR64RegClass}, {})
3379 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3383 }
else if (DstSize <= 32) {
3384 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3393 I.eraseFromParent();
3397 case TargetOpcode::G_FREEZE:
3400 case TargetOpcode::G_INTTOPTR:
3405 case TargetOpcode::G_BITCAST:
3413 case TargetOpcode::G_SELECT: {
3415 const Register CondReg = Sel.getCondReg();
3417 const Register FReg = Sel.getFalseReg();
3419 if (tryOptSelect(Sel))
3425 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3430 Sel.eraseFromParent();
3433 case TargetOpcode::G_ICMP: {
3443 auto &PredOp =
I.getOperand(1);
3444 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3448 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3449 AArch64::WZR, InvCC, MIB);
3450 I.eraseFromParent();
3454 case TargetOpcode::G_FCMP: {
3457 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3459 !emitCSetForFCmp(
I.getOperand(0).getReg(),
Pred, MIB))
3461 I.eraseFromParent();
3464 case TargetOpcode::G_VASTART:
3466 : selectVaStartAAPCS(
I, MF,
MRI);
3467 case TargetOpcode::G_INTRINSIC:
3468 return selectIntrinsic(
I,
MRI);
3469 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3470 return selectIntrinsicWithSideEffects(
I,
MRI);
3471 case TargetOpcode::G_IMPLICIT_DEF: {
3472 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3473 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3474 const Register DstReg =
I.getOperand(0).getReg();
3480 case TargetOpcode::G_BLOCK_ADDR: {
3481 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3482 if (std::optional<uint16_t> BADisc =
3492 AArch64::GPR64RegClass,
MRI);
3493 I.eraseFromParent();
3497 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3498 I.eraseFromParent();
3501 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3502 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3503 I.getOperand(0).getReg())
3507 I.getOperand(1).getBlockAddress(), 0,
3509 I.eraseFromParent();
3514 case TargetOpcode::G_BUILD_VECTOR:
3515 return selectBuildVector(
I,
MRI);
3516 case TargetOpcode::G_MERGE_VALUES:
3518 case TargetOpcode::G_UNMERGE_VALUES:
3520 case TargetOpcode::G_SHUFFLE_VECTOR:
3521 return selectShuffleVector(
I,
MRI);
3522 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3523 return selectExtractElt(
I,
MRI);
3524 case TargetOpcode::G_CONCAT_VECTORS:
3525 return selectConcatVectors(
I,
MRI);
3526 case TargetOpcode::G_JUMP_TABLE:
3527 return selectJumpTable(
I,
MRI);
3528 case TargetOpcode::G_MEMCPY:
3529 case TargetOpcode::G_MEMCPY_INLINE:
3530 case TargetOpcode::G_MEMMOVE:
3531 case TargetOpcode::G_MEMSET:
3532 case TargetOpcode::G_MEMSET_INLINE:
3533 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3534 return selectMOPS(
I,
MRI);
3540bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3541 MachineIRBuilderState OldMIBState = MIB.
getState();
3547bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3548 MachineRegisterInfo &
MRI) {
3551 case TargetOpcode::G_MEMCPY:
3552 case TargetOpcode::G_MEMCPY_INLINE:
3553 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3555 case TargetOpcode::G_MEMMOVE:
3556 Mopcode = AArch64::MOPSMemoryMovePseudo;
3558 case TargetOpcode::G_MEMSET:
3559 case TargetOpcode::G_MEMSET_INLINE:
3561 Mopcode = AArch64::MOPSMemorySetPseudo;
3574 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3575 const auto &SrcValRegClass =
3576 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3594 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3595 {DstPtrCopy, SizeCopy, SrcValCopy})
3599 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3600 {DstPtrCopy, SrcValCopy, SizeCopy})
3608bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3609 MachineRegisterInfo &
MRI) {
3610 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3611 Register JTAddr =
I.getOperand(0).getReg();
3612 unsigned JTI =
I.getOperand(1).getIndex();
3615 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3627 "jump table hardening only supported on MachO/ELF");
3635 I.eraseFromParent();
3642 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3643 {TargetReg, ScratchReg}, {JTAddr,
Index})
3644 .addJumpTableIndex(JTI);
3646 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3647 {
static_cast<int64_t
>(JTI)});
3649 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3650 I.eraseFromParent();
3655bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3656 MachineRegisterInfo &
MRI) {
3657 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3658 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3660 Register DstReg =
I.getOperand(0).getReg();
3661 unsigned JTI =
I.getOperand(1).getIndex();
3664 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3667 I.eraseFromParent();
3672bool AArch64InstructionSelector::selectTLSLocalExecELF(
3673 const GlobalValue *GV, MachineInstr &
I, MachineRegisterInfo &
MRI) {
3674 auto ConstrainRegOps = [&](MachineInstrBuilder MIB) {
3678 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {}));
3686 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()},
3697 MIB.
buildInstr(AArch64::ADDXri, {Addr}, {ThreadBase})
3701 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()}, {Addr})
3718 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3723 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3724 {ThreadBase, Addr2}));
3738 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3744 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr3}, {Addr2})
3749 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3750 {ThreadBase, Addr3}));
3754 I.eraseFromParent();
3760bool AArch64InstructionSelector::selectTLSGlobalValueELF(
3761 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3762 const GlobalValue *GV =
I.
getOperand(1).getGlobal();
3763 auto *FuncInfo = MF->
getInfo<AArch64FunctionInfo>();
3770 return selectTLSLocalExecELF(GV,
I,
MRI);
3772 MIB.
buildInstr(AArch64::LOADgot, {TPOff}, {})
3778 SMEAttrs
Attrs = MF->
getInfo<AArch64FunctionInfo>()->getSMEFnAttrs();
3780 !
Attrs.hasStreamingCompatibleInterface() &&
3781 "unsupported SME features reached GlobalISel TLS lowering");
3784 ? AArch64::TLSDESC_AUTH_CALLSEQ
3785 : AArch64::TLSDESC_CALLSEQ;
3804 MIB.
buildInstr(AArch64::ADDXri, {TPOff}, {Add1.getReg(0)})
3805 .addGlobalAddress(GV, 0,
3814 MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {});
3815 auto Add = MIB.
buildInstr(AArch64::ADDXrr, {
I.getOperand(0).getReg()},
3816 {ThreadBase, TPOff});
3819 I.eraseFromParent();
3823bool AArch64InstructionSelector::selectTLSGlobalValueMachO(
3824 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3825 const auto &GlobalOp =
I.getOperand(1);
3826 assert(GlobalOp.getOffset() == 0 &&
3827 "Shouldn't have an offset on TLS globals!");
3829 const GlobalValue &GV = *GlobalOp.getGlobal();
3832 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3835 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3836 {LoadGOT.getReg(0)})
3847 assert(Opcode == AArch64::BLR);
3848 Opcode = AArch64::BLRAAZ;
3853 .
addUse(AArch64::X0, RegState::Implicit)
3854 .
addDef(AArch64::X0, RegState::Implicit)
3860 I.eraseFromParent();
3864bool AArch64InstructionSelector::selectTLSGlobalValue(
3865 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3871 return selectTLSGlobalValueELF(
I,
MRI);
3874 return selectTLSGlobalValueMachO(
I,
MRI);
3879MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3881 MachineIRBuilder &MIRBuilder)
const {
3882 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3884 auto BuildFn = [&](
unsigned SubregIndex) {
3888 .addImm(SubregIndex);
3896 return BuildFn(AArch64::bsub);
3898 return BuildFn(AArch64::hsub);
3900 return BuildFn(AArch64::ssub);
3902 return BuildFn(AArch64::dsub);
3909AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3910 MachineIRBuilder &MIB,
3911 MachineRegisterInfo &
MRI)
const {
3915 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3919 unsigned SubReg = 0;
3922 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3928 .addReg(SrcReg, {}, SubReg);
3933bool AArch64InstructionSelector::selectMergeValues(
3934 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3935 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3936 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3937 const LLT SrcTy =
MRI.
getType(
I.getOperand(1).getReg());
3941 if (
I.getNumOperands() != 3)
3948 Register DstReg =
I.getOperand(0).getReg();
3949 Register Src1Reg =
I.getOperand(1).getReg();
3950 Register Src2Reg =
I.getOperand(2).getReg();
3951 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3952 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3956 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3957 Src2Reg, 1, RB, MIB);
3962 I.eraseFromParent();
3966 if (RB.
getID() != AArch64::GPRRegBankID)
3972 auto *DstRC = &AArch64::GPR64RegClass;
3974 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3975 TII.get(TargetOpcode::SUBREG_TO_REG))
3977 .
addUse(
I.getOperand(1).getReg())
3978 .
addImm(AArch64::sub_32);
3981 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3982 TII.get(TargetOpcode::SUBREG_TO_REG))
3984 .
addUse(
I.getOperand(2).getReg())
3985 .
addImm(AArch64::sub_32);
3987 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3988 .
addDef(
I.getOperand(0).getReg())
3996 I.eraseFromParent();
4001 const unsigned EltSize) {
4006 CopyOpc = AArch64::DUPi8;
4007 ExtractSubReg = AArch64::bsub;
4010 CopyOpc = AArch64::DUPi16;
4011 ExtractSubReg = AArch64::hsub;
4014 CopyOpc = AArch64::DUPi32;
4015 ExtractSubReg = AArch64::ssub;
4018 CopyOpc = AArch64::DUPi64;
4019 ExtractSubReg = AArch64::dsub;
4023 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
4029MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
4030 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
4031 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
4032 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4033 unsigned CopyOpc = 0;
4034 unsigned ExtractSubReg = 0;
4037 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
4042 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
4044 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
4051 getRegClassForTypeOnBank(VecTy, VecRB,
true);
4053 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4063 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4064 .addReg(VecReg, {}, ExtractSubReg);
4073 MachineInstr *ScalarToVector = emitScalarToVector(
4074 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4075 if (!ScalarToVector)
4080 MachineInstr *LaneCopyMI =
4081 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4089bool AArch64InstructionSelector::selectExtractElt(
4090 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4091 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4092 "unexpected opcode!");
4093 Register DstReg =
I.getOperand(0).getReg();
4095 const Register SrcReg =
I.getOperand(1).getReg();
4098 "source register size too small!");
4099 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4102 MachineOperand &LaneIdxOp =
I.getOperand(2);
4103 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4109 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4112 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4116 Opcode = AArch64::UMOVvi8;
4119 Opcode = AArch64::UMOVvi16;
4122 Opcode = AArch64::UMOVvi32;
4129 MachineInstr *ScalarToVector = emitScalarToVector(
4130 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4131 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4135 I.setDesc(
TII.get(Opcode));
4136 I.getOperand(2).ChangeToImmediate(LaneIdx);
4141 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4146 I.eraseFromParent();
4150bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4151 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4152 unsigned NumElts =
I.getNumOperands() - 1;
4153 Register SrcReg =
I.getOperand(NumElts).getReg();
4154 const LLT NarrowTy =
MRI.
getType(
I.getOperand(0).getReg());
4157 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4159 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4165 const RegisterBank &DstRB =
4167 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4168 Register Dst =
I.getOperand(OpIdx).getReg();
4169 MachineInstr *Extract =
4170 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4174 I.eraseFromParent();
4178bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4179 MachineRegisterInfo &
MRI) {
4180 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4181 "unexpected opcode");
4185 unsigned NumElts =
I.getNumOperands() - 1;
4186 Register SrcReg =
I.getOperand(NumElts).getReg();
4187 Register LoReg =
I.getOperand(0).getReg();
4188 Register HiReg =
I.getOperand(1).getReg();
4197 LoRB.
getID() == AArch64::GPRRegBankID &&
4198 HiRB.
getID() == AArch64::GPRRegBankID &&
4199 SrcRB.
getID() == AArch64::FPRRegBankID) {
4200 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4201 TII.get(AArch64::UMOVvi64), LoReg)
4204 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4205 TII.get(AArch64::UMOVvi64), HiReg)
4210 I.eraseFromParent();
4215 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4216 HiRB.
getID() != AArch64::FPRRegBankID) {
4217 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4218 "currently unsupported.\n");
4223 "source register size too small!");
4226 return selectSplitVectorUnmerge(
I,
MRI);
4230 unsigned CopyOpc = 0;
4231 unsigned ExtractSubReg = 0;
4242 unsigned NumInsertRegs = NumElts - 1;
4248 InsertRegs.
assign(NumInsertRegs, SrcReg);
4257 unsigned SubReg = 0;
4260 assert(Found &&
"expected to find last operand's subeg idx");
4261 for (
unsigned Idx = 0;
Idx < NumInsertRegs; ++
Idx) {
4263 MachineInstr &ImpDefMI =
4264 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4269 MachineInstr &InsMI =
4271 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4288 Register CopyTo =
I.getOperand(0).getReg();
4289 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4290 .addReg(InsertRegs[0], {}, ExtractSubReg);
4294 unsigned LaneIdx = 1;
4295 for (
Register InsReg : InsertRegs) {
4296 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4297 MachineInstr &CopyInst =
4316 I.eraseFromParent();
4320bool AArch64InstructionSelector::selectConcatVectors(
4321 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4322 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4323 "Unexpected opcode");
4324 Register Dst =
I.getOperand(0).getReg();
4325 Register Op1 =
I.getOperand(1).getReg();
4326 Register Op2 =
I.getOperand(2).getReg();
4327 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4330 I.eraseFromParent();
4335AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4344MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4345 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4352 RC = &AArch64::FPR128RegClass;
4353 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4356 RC = &AArch64::FPR64RegClass;
4357 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4360 RC = &AArch64::FPR32RegClass;
4361 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4364 RC = &AArch64::FPR16RegClass;
4365 Opc = AArch64::LDRHui;
4368 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4373 MachineInstr *LoadMI =
nullptr;
4374 auto &MF = MIRBuilder.
getMF();
4375 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4376 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4378 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4381 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4385 .addConstantPoolIndex(
4401static std::pair<unsigned, unsigned>
4403 unsigned Opc, SubregIdx;
4404 if (RB.
getID() == AArch64::GPRRegBankID) {
4406 Opc = AArch64::INSvi8gpr;
4407 SubregIdx = AArch64::bsub;
4408 }
else if (EltSize == 16) {
4409 Opc = AArch64::INSvi16gpr;
4410 SubregIdx = AArch64::ssub;
4411 }
else if (EltSize == 32) {
4412 Opc = AArch64::INSvi32gpr;
4413 SubregIdx = AArch64::ssub;
4414 }
else if (EltSize == 64) {
4415 Opc = AArch64::INSvi64gpr;
4416 SubregIdx = AArch64::dsub;
4422 Opc = AArch64::INSvi8lane;
4423 SubregIdx = AArch64::bsub;
4424 }
else if (EltSize == 16) {
4425 Opc = AArch64::INSvi16lane;
4426 SubregIdx = AArch64::hsub;
4427 }
else if (EltSize == 32) {
4428 Opc = AArch64::INSvi32lane;
4429 SubregIdx = AArch64::ssub;
4430 }
else if (EltSize == 64) {
4431 Opc = AArch64::INSvi64lane;
4432 SubregIdx = AArch64::dsub;
4437 return std::make_pair(
Opc, SubregIdx);
4440MachineInstr *AArch64InstructionSelector::emitInstr(
4441 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4442 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4443 const ComplexRendererFns &RenderFns)
const {
4444 assert(Opcode &&
"Expected an opcode?");
4446 "Function should only be used to produce selected instructions!");
4447 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4449 for (
auto &Fn : *RenderFns)
4455MachineInstr *AArch64InstructionSelector::emitAddSub(
4456 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4458 MachineIRBuilder &MIRBuilder)
const {
4460 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4464 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4465 bool Is32Bit =
Size == 32;
4468 if (
auto Fns = selectArithImmed(
RHS))
4469 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4473 if (
auto Fns = selectNegArithImmed(
RHS))
4474 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4478 if (
auto Fns = selectArithExtendedRegister(
RHS))
4479 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4483 if (
auto Fns = selectShiftedRegister(
RHS))
4484 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4486 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4491AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4492 MachineOperand &
RHS,
4493 MachineIRBuilder &MIRBuilder)
const {
4494 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4495 {{AArch64::ADDXri, AArch64::ADDWri},
4496 {AArch64::ADDXrs, AArch64::ADDWrs},
4497 {AArch64::ADDXrr, AArch64::ADDWrr},
4498 {AArch64::SUBXri, AArch64::SUBWri},
4499 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4500 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4504AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4505 MachineOperand &
RHS,
4506 MachineIRBuilder &MIRBuilder)
const {
4507 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4508 {{AArch64::ADDSXri, AArch64::ADDSWri},
4509 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4510 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4511 {AArch64::SUBSXri, AArch64::SUBSWri},
4512 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4513 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4517AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4518 MachineOperand &
RHS,
4519 MachineIRBuilder &MIRBuilder)
const {
4520 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4521 {{AArch64::SUBSXri, AArch64::SUBSWri},
4522 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4523 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4524 {AArch64::ADDSXri, AArch64::ADDSWri},
4525 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4526 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4530AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4531 MachineOperand &
RHS,
4532 MachineIRBuilder &MIRBuilder)
const {
4533 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4534 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4536 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4537 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4541AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4542 MachineOperand &
RHS,
4543 MachineIRBuilder &MIRBuilder)
const {
4544 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4545 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4547 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4548 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4552AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4553 MachineIRBuilder &MIRBuilder)
const {
4556 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4561AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4562 MachineIRBuilder &MIRBuilder)
const {
4565 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4570AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4571 MachineIRBuilder &MIRBuilder)
const {
4572 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4576 bool Is32Bit = (
RegSize == 32);
4577 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4578 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4579 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4583 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4586 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4593 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4594 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4595 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4598MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4599 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4600 MachineIRBuilder &MIRBuilder)
const {
4601 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4608 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4610 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4612 return emitCMP(
LHS,
RHS, MIRBuilder);
4615MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4617 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4621 "Expected a 32-bit scalar register?");
4623 const Register ZReg = AArch64::WZR;
4628 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4634 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4635 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4636 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4641MachineInstr *AArch64InstructionSelector::emitFPCompare(
4643 std::optional<CmpInst::Predicate>
Pred)
const {
4644 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4649 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4659 if (!ShouldUseImm &&
Pred && IsEqualityPred(*
Pred)) {
4662 ShouldUseImm =
true;
4666 unsigned CmpOpcTbl[2][3] = {
4667 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4668 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4670 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4682MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4684 MachineIRBuilder &MIRBuilder)
const {
4694 if (Op1Ty != Op2Ty) {
4695 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4698 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4701 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4716 MachineInstr *WidenedOp1 =
4717 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4718 MachineInstr *WidenedOp2 =
4719 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4720 if (!WidenedOp1 || !WidenedOp2) {
4721 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4726 unsigned InsertOpc, InsSubRegIdx;
4727 std::tie(InsertOpc, InsSubRegIdx) =
4745 MachineIRBuilder &MIRBuilder)
const {
4752 Size =
TRI.getRegSizeInBits(*RC);
4756 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4757 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4758 unsigned Opc = OpcTable[
Size == 64];
4764MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4766 MachineRegisterInfo *
MRI = MIB.
getMRI();
4767 unsigned Opcode =
I.getOpcode();
4771 bool NeedsNegatedCarry =
4772 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4789 if (SrcMI == PrevMI) {
4791 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4792 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4793 CarrySrcMI->isUnsigned() &&
4794 CarrySrcMI->getCarryOutReg() == CarryReg &&
4795 selectAndRestoreState(*SrcMI))
4802 if (NeedsNegatedCarry) {
4805 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4809 auto Fns = select12BitValueWithLeftShift(1);
4810 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4813bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4814 MachineRegisterInfo &
MRI) {
4819 emitCarryIn(
I, CarryInMI->getCarryInReg());
4823 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4824 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4826 Register CarryOutReg = CarryMI.getCarryOutReg();
4830 OpAndCC.first->addRegisterDead(AArch64::NZCV, &
TRI);
4837 emitCSINC(CarryOutReg, ZReg, ZReg,
4838 getInvertedCondCode(OpAndCC.second), MIB);
4841 I.eraseFromParent();
4845std::pair<MachineInstr *, AArch64CC::CondCode>
4846AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4847 MachineOperand &
LHS,
4848 MachineOperand &
RHS,
4849 MachineIRBuilder &MIRBuilder)
const {
4853 case TargetOpcode::G_SADDO:
4855 case TargetOpcode::G_UADDO:
4857 case TargetOpcode::G_SSUBO:
4859 case TargetOpcode::G_USUBO:
4861 case TargetOpcode::G_SADDE:
4863 case TargetOpcode::G_UADDE:
4865 case TargetOpcode::G_SSUBE:
4867 case TargetOpcode::G_USUBE:
4888 unsigned Depth = 0) {
4889 if (!
MRI.hasOneNonDBGUse(Val))
4895 MustBeFirst =
false;
4901 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4902 bool IsOR = Opcode == TargetOpcode::G_OR;
4914 if (MustBeFirstL && MustBeFirstR)
4920 if (!CanNegateL && !CanNegateR)
4924 CanNegate = WillNegate && CanNegateL && CanNegateR;
4927 MustBeFirst = !CanNegate;
4929 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4932 MustBeFirst = MustBeFirstL || MustBeFirstR;
4939MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4942 MachineIRBuilder &MIB)
const {
4946 std::optional<ValueAndVReg>
C;
4950 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4951 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4952 else if (
C->Value.ule(31))
4953 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4955 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4961 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4962 CCmpOpc = AArch64::FCCMPHrr;
4965 CCmpOpc = AArch64::FCCMPSrr;
4968 CCmpOpc = AArch64::FCCMPDrr;
4978 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4979 CCmp.
addImm(
C->Value.getZExtValue());
4980 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4981 CCmp.
addImm(
C->Value.abs().getZExtValue());
4989MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
5011 MachineInstr *ExtraCmp;
5013 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB,
CC);
5025 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
5026 return emitFPCompare(
Cmp->getOperand(2).getReg(),
5027 Cmp->getOperand(3).getReg(), MIB);
5034 bool IsOR = Opcode == TargetOpcode::G_OR;
5040 assert(ValidL &&
"Valid conjunction/disjunction tree");
5047 assert(ValidR &&
"Valid conjunction/disjunction tree");
5052 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
5061 bool NegateAfterAll;
5062 if (Opcode == TargetOpcode::G_OR) {
5065 assert(CanNegateR &&
"at least one side must be negatable");
5066 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
5070 NegateAfterR =
true;
5073 NegateR = CanNegateR;
5074 NegateAfterR = !CanNegateR;
5077 NegateAfterAll = !Negate;
5079 assert(Opcode == TargetOpcode::G_AND &&
5080 "Valid conjunction/disjunction tree");
5081 assert(!Negate &&
"Valid conjunction/disjunction tree");
5085 NegateAfterR =
false;
5086 NegateAfterAll =
false;
5091 MachineInstr *CmpR =
5102MachineInstr *AArch64InstructionSelector::emitConjunction(
5104 bool DummyCanNegate;
5105 bool DummyMustBeFirst;
5112bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5113 MachineInstr &CondMI) {
5124bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5125 MachineRegisterInfo &
MRI = *MIB.
getMRI();
5144 MachineInstr *CondDef =
MRI.
getVRegDef(
I.getOperand(1).getReg());
5153 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5159 unsigned CondOpc = CondDef->
getOpcode();
5160 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5161 if (tryOptSelectConjunction(
I, *CondDef))
5167 if (CondOpc == TargetOpcode::G_ICMP) {
5196 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5197 I.getOperand(3).getReg(), CondCode, MIB);
5198 I.eraseFromParent();
5202MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5203 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5204 MachineIRBuilder &MIRBuilder)
const {
5206 "Unexpected MachineOperand");
5207 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5262 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5265 if (!ValAndVReg || ValAndVReg->Value != 0)
5275bool AArch64InstructionSelector::selectShuffleVector(
5276 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5277 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
5278 Register Src1Reg =
I.getOperand(1).getReg();
5279 Register Src2Reg =
I.getOperand(2).getReg();
5280 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5282 "Expected equal shuffle types during selection");
5291 SmallVector<int> NewMask;
5292 bool FirstUsed =
false;
5293 bool SecondUsed =
false;
5294 for (
int M : Mask) {
5296 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5299 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5304 FirstUsed |=
M < NumElts;
5305 SecondUsed |=
M >= NumElts;
5306 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5315 for (
int &M : NewMask) {
5317 assert(M >= ByteLanes && M < 2 * ByteLanes);
5327 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5328 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5341 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5348 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5352 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5357 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5358 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5360 I.eraseFromParent();
5365 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5368 I.eraseFromParent();
5376 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5379 I.eraseFromParent();
5383MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5385 unsigned LaneIdx,
const RegisterBank &RB,
5386 MachineIRBuilder &MIRBuilder)
const {
5387 MachineInstr *InsElt =
nullptr;
5389 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5398 if (RB.
getID() == AArch64::FPRRegBankID) {
5399 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5402 .
addUse(InsSub->getOperand(0).getReg())
5414bool AArch64InstructionSelector::selectUSMovFromExtend(
5415 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5416 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5417 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5418 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5420 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5421 const Register DefReg =
MI.getOperand(0).getReg();
5425 if (DstSize != 32 && DstSize != 64)
5428 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5429 MI.getOperand(1).getReg(),
MRI);
5440 const MachineInstr *ScalarToVector = emitScalarToVector(
5441 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5442 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5448 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5450 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5452 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5454 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5456 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5464 MachineInstr *ExtI =
nullptr;
5465 if (DstSize == 64 && !IsSigned) {
5468 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5470 .
addImm(AArch64::sub_32);
5476 MI.eraseFromParent();
5480bool AArch64InstructionSelector::selectIndexedExtLoad(
5481 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5484 Register WriteBack = ExtLd.getWritebackReg();
5489 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5490 bool IsPre = ExtLd.isPre();
5492 unsigned InsertIntoSubReg = 0;
5498 if ((IsSExt && IsFPR) || Ty.
isVector())
5506 if (MemSizeBits == 8) {
5509 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5511 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5512 NewLdDstTy = IsDst64 ? s64 : s32;
5514 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5515 InsertIntoSubReg = AArch64::bsub;
5518 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5519 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5522 }
else if (MemSizeBits == 16) {
5525 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5527 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5528 NewLdDstTy = IsDst64 ? s64 : s32;
5530 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5531 InsertIntoSubReg = AArch64::hsub;
5534 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5535 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5538 }
else if (MemSizeBits == 32) {
5540 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5543 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5544 InsertIntoSubReg = AArch64::ssub;
5547 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5548 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5560 .addImm(Cst->getSExtValue());
5565 if (InsertIntoSubReg) {
5567 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5568 .addUse(LdMI.getReg(1))
5569 .
addImm(InsertIntoSubReg);
5579 MI.eraseFromParent();
5584bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5585 MachineRegisterInfo &
MRI) {
5588 Register WriteBack = Ld.getWritebackReg();
5592 "Unexpected type for indexed load");
5593 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5596 return selectIndexedExtLoad(
MI,
MRI);
5600 static constexpr unsigned GPROpcodes[] = {
5601 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5603 static constexpr unsigned FPROpcodes[] = {
5604 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5607 ? FPROpcodes[
Log2_32(MemSize)]
5608 : GPROpcodes[
Log2_32(MemSize)];
5611 static constexpr unsigned GPROpcodes[] = {
5612 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5614 static constexpr unsigned FPROpcodes[] = {
5615 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5616 AArch64::LDRDpost, AArch64::LDRQpost};
5618 ? FPROpcodes[
Log2_32(MemSize)]
5619 : GPROpcodes[
Log2_32(MemSize)];
5629 MI.eraseFromParent();
5633bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5634 MachineRegisterInfo &
MRI) {
5640 "Unexpected type for indexed store");
5642 LocationSize MemSize =
I.getMMO().getSize();
5643 unsigned MemSizeInBytes = MemSize.
getValue();
5645 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5646 "Unexpected indexed store size");
5647 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5651 static constexpr unsigned GPROpcodes[] = {
5652 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5654 static constexpr unsigned FPROpcodes[] = {
5655 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5659 Opc = FPROpcodes[MemSizeLog2];
5661 Opc = GPROpcodes[MemSizeLog2];
5663 static constexpr unsigned GPROpcodes[] = {
5664 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5666 static constexpr unsigned FPROpcodes[] = {
5667 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5668 AArch64::STRDpost, AArch64::STRQpost};
5671 Opc = FPROpcodes[MemSizeLog2];
5673 Opc = GPROpcodes[MemSizeLog2];
5681 Str.cloneMemRefs(
I);
5683 I.eraseFromParent();
5688AArch64InstructionSelector::emitConstantMOVVector(DstOp Dst, APInt
Imm,
5689 MachineRegisterInfo &
MRI) {
5690 unsigned DstSize =
Imm.getBitWidth();
5691 assert((DstSize == 64 || DstSize == 128) &&
5692 "Unexpected vector constant size");
5696 for (AArch64_IMM::ImmInsnModel Insn : Insns) {
5697 switch (Insn.Opcode) {
5698 case AArch64::FMOVD0: {
5702 AArch64::MOVIv2d_ns,
5703 {DstSize == 128 ? Dst : DstOp(&AArch64::FPR128RegClass)}, {})
5706 if (DstSize != 128) {
5707 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5708 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5714 case AArch64::FMOVDi:
5715 case AArch64::FMOVv2f32_ns:
5716 case AArch64::FMOVv2f64_ns:
5717 case AArch64::FMOVv4f32_ns:
5718 case AArch64::FMOVv4f16_ns:
5719 case AArch64::FMOVv8f16_ns:
5720 case AArch64::MOVID:
5721 case AArch64::MOVIv16b_ns:
5722 case AArch64::MOVIv2d_ns:
5723 case AArch64::MOVIv2i32:
5724 case AArch64::MOVIv2s_msl:
5725 case AArch64::MOVIv4i16:
5726 case AArch64::MOVIv4i32:
5727 case AArch64::MOVIv4s_msl:
5728 case AArch64::MOVIv8b_ns:
5729 case AArch64::MOVIv8i16:
5730 case AArch64::MVNIv2i32:
5731 case AArch64::MVNIv2s_msl:
5732 case AArch64::MVNIv4i16:
5733 case AArch64::MVNIv4i32:
5734 case AArch64::MVNIv4s_msl:
5735 case AArch64::MVNIv8i16: {
5736 auto Mov = MIB.
buildInstr(Insn.Opcode, {Dst}, {});
5744 case AArch64::DUPM_ZI: {
5745 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5748 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5749 .addReg(Mov.getReg(0), {},
5750 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5752 DstSize == 64 ? AArch64::FPR64RegClass
5753 : AArch64::FPR128RegClass,
5757 case AArch64::DUP_ZI_D: {
5758 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5762 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5763 .addReg(Mov.getReg(0), {},
5764 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5766 DstSize == 64 ? AArch64::FPR64RegClass
5767 : AArch64::FPR128RegClass,
5779MachineInstr *AArch64InstructionSelector::emitConstantVector(
5780 Register Dst, Constant *CV, APInt
Imm, MachineRegisterInfo &
MRI) {
5781 if (
auto *MovI = emitConstantMOVVector(Dst,
Imm,
MRI))
5786 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5796bool AArch64InstructionSelector::tryOptConstantBuildVec(
5797 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5798 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5800 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5806 APInt
Imm(DstSize, 0);
5807 for (
unsigned Idx = 1;
Idx <
I.getNumOperands(); ++
Idx) {
5808 Register OpReg =
I.getOperand(Idx).getReg();
5820 std::move(AnyConst->Value)));
5833 if (!emitConstantVector(
I.getOperand(0).getReg(), CV,
Imm,
MRI))
5835 I.eraseFromParent();
5839bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5840 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5845 Register Dst =
I.getOperand(0).getReg();
5846 Register EltReg =
I.getOperand(1).getReg();
5855 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5863 getRegClassForTypeOnBank(
MRI.
getType(Dst), DstRB);
5868 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5871 I.eraseFromParent();
5876bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5877 MachineRegisterInfo &
MRI) {
5878 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5881 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
5882 const LLT EltTy =
MRI.
getType(
I.getOperand(1).getReg());
5885 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5887 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5890 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5895 MachineInstr *ScalarToVec =
5897 I.getOperand(1).getReg(), MIB);
5906 MachineInstr *PrevMI = ScalarToVec;
5907 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5910 Register OpReg =
I.getOperand(i).getReg();
5913 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5920 if (DstSize < 128) {
5926 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5931 unsigned SubReg = 0;
5934 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5935 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5941 Register DstReg =
I.getOperand(0).getReg();
5943 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5944 MachineOperand &RegOp =
I.getOperand(1);
5964 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5975bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5978 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5980 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5985 "Destination must be 64 bits or 128 bits?");
5986 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5987 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5992 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5993 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
5994 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5995 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6004bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6005 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6006 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6008 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6013 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6015 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6016 [](
auto MO) { return MO.getReg(); });
6020 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6035 .
addImm(LaneNo->getZExtValue())
6039 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6040 unsigned SubReg = AArch64::qsub0;
6041 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6042 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6043 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6046 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6051 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6057void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6060 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6062 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6065 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6066 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6075bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6076 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6077 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6082 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6083 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6087 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6097 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6100 .
addImm(LaneNo->getZExtValue())
6107bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6108 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6121 case Intrinsic::aarch64_ldxp:
6122 case Intrinsic::aarch64_ldaxp: {
6124 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6125 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6131 case Intrinsic::aarch64_neon_ld1x2: {
6135 Opc = AArch64::LD1Twov8b;
6137 Opc = AArch64::LD1Twov16b;
6139 Opc = AArch64::LD1Twov4h;
6141 Opc = AArch64::LD1Twov8h;
6143 Opc = AArch64::LD1Twov2s;
6145 Opc = AArch64::LD1Twov4s;
6147 Opc = AArch64::LD1Twov2d;
6148 else if (Ty ==
S64 || Ty == P0)
6149 Opc = AArch64::LD1Twov1d;
6152 selectVectorLoadIntrinsic(
Opc, 2,
I);
6155 case Intrinsic::aarch64_neon_ld1x3: {
6159 Opc = AArch64::LD1Threev8b;
6161 Opc = AArch64::LD1Threev16b;
6163 Opc = AArch64::LD1Threev4h;
6165 Opc = AArch64::LD1Threev8h;
6167 Opc = AArch64::LD1Threev2s;
6169 Opc = AArch64::LD1Threev4s;
6171 Opc = AArch64::LD1Threev2d;
6172 else if (Ty ==
S64 || Ty == P0)
6173 Opc = AArch64::LD1Threev1d;
6176 selectVectorLoadIntrinsic(
Opc, 3,
I);
6179 case Intrinsic::aarch64_neon_ld1x4: {
6183 Opc = AArch64::LD1Fourv8b;
6185 Opc = AArch64::LD1Fourv16b;
6187 Opc = AArch64::LD1Fourv4h;
6189 Opc = AArch64::LD1Fourv8h;
6191 Opc = AArch64::LD1Fourv2s;
6193 Opc = AArch64::LD1Fourv4s;
6195 Opc = AArch64::LD1Fourv2d;
6196 else if (Ty ==
S64 || Ty == P0)
6197 Opc = AArch64::LD1Fourv1d;
6200 selectVectorLoadIntrinsic(
Opc, 4,
I);
6203 case Intrinsic::aarch64_neon_ld2: {
6207 Opc = AArch64::LD2Twov8b;
6209 Opc = AArch64::LD2Twov16b;
6211 Opc = AArch64::LD2Twov4h;
6213 Opc = AArch64::LD2Twov8h;
6215 Opc = AArch64::LD2Twov2s;
6217 Opc = AArch64::LD2Twov4s;
6219 Opc = AArch64::LD2Twov2d;
6220 else if (Ty ==
S64 || Ty == P0)
6221 Opc = AArch64::LD1Twov1d;
6224 selectVectorLoadIntrinsic(
Opc, 2,
I);
6227 case Intrinsic::aarch64_neon_ld2lane: {
6231 Opc = AArch64::LD2i8;
6233 Opc = AArch64::LD2i16;
6235 Opc = AArch64::LD2i32;
6238 Opc = AArch64::LD2i64;
6241 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6245 case Intrinsic::aarch64_neon_ld2r: {
6249 Opc = AArch64::LD2Rv8b;
6251 Opc = AArch64::LD2Rv16b;
6253 Opc = AArch64::LD2Rv4h;
6255 Opc = AArch64::LD2Rv8h;
6257 Opc = AArch64::LD2Rv2s;
6259 Opc = AArch64::LD2Rv4s;
6261 Opc = AArch64::LD2Rv2d;
6262 else if (Ty ==
S64 || Ty == P0)
6263 Opc = AArch64::LD2Rv1d;
6266 selectVectorLoadIntrinsic(
Opc, 2,
I);
6269 case Intrinsic::aarch64_neon_ld3: {
6273 Opc = AArch64::LD3Threev8b;
6275 Opc = AArch64::LD3Threev16b;
6277 Opc = AArch64::LD3Threev4h;
6279 Opc = AArch64::LD3Threev8h;
6281 Opc = AArch64::LD3Threev2s;
6283 Opc = AArch64::LD3Threev4s;
6285 Opc = AArch64::LD3Threev2d;
6286 else if (Ty ==
S64 || Ty == P0)
6287 Opc = AArch64::LD1Threev1d;
6290 selectVectorLoadIntrinsic(
Opc, 3,
I);
6293 case Intrinsic::aarch64_neon_ld3lane: {
6297 Opc = AArch64::LD3i8;
6299 Opc = AArch64::LD3i16;
6301 Opc = AArch64::LD3i32;
6304 Opc = AArch64::LD3i64;
6307 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6311 case Intrinsic::aarch64_neon_ld3r: {
6315 Opc = AArch64::LD3Rv8b;
6317 Opc = AArch64::LD3Rv16b;
6319 Opc = AArch64::LD3Rv4h;
6321 Opc = AArch64::LD3Rv8h;
6323 Opc = AArch64::LD3Rv2s;
6325 Opc = AArch64::LD3Rv4s;
6327 Opc = AArch64::LD3Rv2d;
6328 else if (Ty ==
S64 || Ty == P0)
6329 Opc = AArch64::LD3Rv1d;
6332 selectVectorLoadIntrinsic(
Opc, 3,
I);
6335 case Intrinsic::aarch64_neon_ld4: {
6339 Opc = AArch64::LD4Fourv8b;
6341 Opc = AArch64::LD4Fourv16b;
6343 Opc = AArch64::LD4Fourv4h;
6345 Opc = AArch64::LD4Fourv8h;
6347 Opc = AArch64::LD4Fourv2s;
6349 Opc = AArch64::LD4Fourv4s;
6351 Opc = AArch64::LD4Fourv2d;
6352 else if (Ty ==
S64 || Ty == P0)
6353 Opc = AArch64::LD1Fourv1d;
6356 selectVectorLoadIntrinsic(
Opc, 4,
I);
6359 case Intrinsic::aarch64_neon_ld4lane: {
6363 Opc = AArch64::LD4i8;
6365 Opc = AArch64::LD4i16;
6367 Opc = AArch64::LD4i32;
6370 Opc = AArch64::LD4i64;
6373 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6377 case Intrinsic::aarch64_neon_ld4r: {
6381 Opc = AArch64::LD4Rv8b;
6383 Opc = AArch64::LD4Rv16b;
6385 Opc = AArch64::LD4Rv4h;
6387 Opc = AArch64::LD4Rv8h;
6389 Opc = AArch64::LD4Rv2s;
6391 Opc = AArch64::LD4Rv4s;
6393 Opc = AArch64::LD4Rv2d;
6394 else if (Ty ==
S64 || Ty == P0)
6395 Opc = AArch64::LD4Rv1d;
6398 selectVectorLoadIntrinsic(
Opc, 4,
I);
6401 case Intrinsic::aarch64_neon_st1x2: {
6405 Opc = AArch64::ST1Twov8b;
6407 Opc = AArch64::ST1Twov16b;
6409 Opc = AArch64::ST1Twov4h;
6411 Opc = AArch64::ST1Twov8h;
6413 Opc = AArch64::ST1Twov2s;
6415 Opc = AArch64::ST1Twov4s;
6417 Opc = AArch64::ST1Twov2d;
6418 else if (Ty ==
S64 || Ty == P0)
6419 Opc = AArch64::ST1Twov1d;
6422 selectVectorStoreIntrinsic(
I, 2,
Opc);
6425 case Intrinsic::aarch64_neon_st1x3: {
6429 Opc = AArch64::ST1Threev8b;
6431 Opc = AArch64::ST1Threev16b;
6433 Opc = AArch64::ST1Threev4h;
6435 Opc = AArch64::ST1Threev8h;
6437 Opc = AArch64::ST1Threev2s;
6439 Opc = AArch64::ST1Threev4s;
6441 Opc = AArch64::ST1Threev2d;
6442 else if (Ty ==
S64 || Ty == P0)
6443 Opc = AArch64::ST1Threev1d;
6446 selectVectorStoreIntrinsic(
I, 3,
Opc);
6449 case Intrinsic::aarch64_neon_st1x4: {
6453 Opc = AArch64::ST1Fourv8b;
6455 Opc = AArch64::ST1Fourv16b;
6457 Opc = AArch64::ST1Fourv4h;
6459 Opc = AArch64::ST1Fourv8h;
6461 Opc = AArch64::ST1Fourv2s;
6463 Opc = AArch64::ST1Fourv4s;
6465 Opc = AArch64::ST1Fourv2d;
6466 else if (Ty ==
S64 || Ty == P0)
6467 Opc = AArch64::ST1Fourv1d;
6470 selectVectorStoreIntrinsic(
I, 4,
Opc);
6473 case Intrinsic::aarch64_neon_st2: {
6477 Opc = AArch64::ST2Twov8b;
6479 Opc = AArch64::ST2Twov16b;
6481 Opc = AArch64::ST2Twov4h;
6483 Opc = AArch64::ST2Twov8h;
6485 Opc = AArch64::ST2Twov2s;
6487 Opc = AArch64::ST2Twov4s;
6489 Opc = AArch64::ST2Twov2d;
6490 else if (Ty ==
S64 || Ty == P0)
6491 Opc = AArch64::ST1Twov1d;
6494 selectVectorStoreIntrinsic(
I, 2,
Opc);
6497 case Intrinsic::aarch64_neon_st3: {
6501 Opc = AArch64::ST3Threev8b;
6503 Opc = AArch64::ST3Threev16b;
6505 Opc = AArch64::ST3Threev4h;
6507 Opc = AArch64::ST3Threev8h;
6509 Opc = AArch64::ST3Threev2s;
6511 Opc = AArch64::ST3Threev4s;
6513 Opc = AArch64::ST3Threev2d;
6514 else if (Ty ==
S64 || Ty == P0)
6515 Opc = AArch64::ST1Threev1d;
6518 selectVectorStoreIntrinsic(
I, 3,
Opc);
6521 case Intrinsic::aarch64_neon_st4: {
6525 Opc = AArch64::ST4Fourv8b;
6527 Opc = AArch64::ST4Fourv16b;
6529 Opc = AArch64::ST4Fourv4h;
6531 Opc = AArch64::ST4Fourv8h;
6533 Opc = AArch64::ST4Fourv2s;
6535 Opc = AArch64::ST4Fourv4s;
6537 Opc = AArch64::ST4Fourv2d;
6538 else if (Ty ==
S64 || Ty == P0)
6539 Opc = AArch64::ST1Fourv1d;
6542 selectVectorStoreIntrinsic(
I, 4,
Opc);
6545 case Intrinsic::aarch64_neon_st2lane: {
6549 Opc = AArch64::ST2i8;
6551 Opc = AArch64::ST2i16;
6553 Opc = AArch64::ST2i32;
6556 Opc = AArch64::ST2i64;
6559 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6563 case Intrinsic::aarch64_neon_st3lane: {
6567 Opc = AArch64::ST3i8;
6569 Opc = AArch64::ST3i16;
6571 Opc = AArch64::ST3i32;
6574 Opc = AArch64::ST3i64;
6577 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6581 case Intrinsic::aarch64_neon_st4lane: {
6585 Opc = AArch64::ST4i8;
6587 Opc = AArch64::ST4i16;
6589 Opc = AArch64::ST4i32;
6592 Opc = AArch64::ST4i64;
6595 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6599 case Intrinsic::aarch64_mops_memset_tag: {
6612 Register DstDef =
I.getOperand(0).getReg();
6614 Register DstUse =
I.getOperand(2).getReg();
6615 Register ValUse =
I.getOperand(3).getReg();
6616 Register SizeUse =
I.getOperand(4).getReg();
6623 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6624 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6630 case Intrinsic::ptrauth_resign_load_relative: {
6631 Register DstReg =
I.getOperand(0).getReg();
6632 Register ValReg =
I.getOperand(2).getReg();
6633 uint64_t AUTKey =
I.getOperand(3).getImm();
6634 Register AUTDisc =
I.getOperand(4).getReg();
6635 uint64_t PACKey =
I.getOperand(5).getImm();
6636 Register PACDisc =
I.getOperand(6).getReg();
6637 int64_t Addend =
I.getOperand(7).getImm();
6640 uint16_t AUTConstDiscC = 0;
6641 std::tie(AUTConstDiscC, AUTAddrDisc) =
6645 uint16_t PACConstDiscC = 0;
6646 std::tie(PACConstDiscC, PACAddrDisc) =
6649 MIB.
buildCopy({AArch64::X16}, {ValReg});
6665 I.eraseFromParent();
6670 I.eraseFromParent();
6674bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6675 MachineRegisterInfo &
MRI) {
6681 case Intrinsic::ptrauth_resign: {
6682 Register DstReg =
I.getOperand(0).getReg();
6683 Register ValReg =
I.getOperand(2).getReg();
6684 uint64_t AUTKey =
I.getOperand(3).getImm();
6685 Register AUTDisc =
I.getOperand(4).getReg();
6686 uint64_t PACKey =
I.getOperand(5).getImm();
6687 Register PACDisc =
I.getOperand(6).getReg();
6690 uint16_t AUTConstDiscC = 0;
6691 std::tie(AUTConstDiscC, AUTAddrDisc) =
6695 uint16_t PACConstDiscC = 0;
6696 std::tie(PACConstDiscC, PACAddrDisc) =
6699 MIB.
buildCopy({AArch64::X16}, {ValReg});
6713 I.eraseFromParent();
6716 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6717 Register DstReg =
I.getOperand(0).getReg();
6718 Register ValReg =
I.getOperand(2).getReg();
6719 uint64_t AUTKey =
I.getOperand(3).getImm();
6720 Register AUTDisc =
I.getOperand(4).getReg();
6721 Register AUTPC =
I.getOperand(5).getReg();
6722 uint64_t PACKey =
I.getOperand(6).getImm();
6723 Register PACDisc =
I.getOperand(7).getReg();
6726 "auth_with_pc_and_resign only supports IA and IB keys");
6728 uint16_t PACConstDiscC = 0;
6730 std::tie(PACConstDiscC, PACAddrDisc) =
6734 PACAddrDisc = AArch64::XZR;
6736 MIB.
buildCopy({AArch64::X17}, {ValReg});
6737 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6752 I.eraseFromParent();
6755 case Intrinsic::ptrauth_auth: {
6756 Register DstReg =
I.getOperand(0).getReg();
6757 Register ValReg =
I.getOperand(2).getReg();
6758 uint64_t AUTKey =
I.getOperand(3).getImm();
6759 Register AUTDisc =
I.getOperand(4).getReg();
6762 uint16_t AUTConstDiscC = 0;
6763 std::tie(AUTConstDiscC, AUTAddrDisc) =
6767 MIB.
buildCopy({AArch64::X16}, {ValReg});
6787 Auth.constrainAllUses(
TII,
TRI, RBI);
6791 I.eraseFromParent();
6794 case Intrinsic::frameaddress:
6795 case Intrinsic::returnaddress: {
6799 unsigned Depth =
I.getOperand(2).getImm();
6800 Register DstReg =
I.getOperand(0).getReg();
6803 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6804 if (!MFReturnAddr) {
6809 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6812 if (STI.hasPAuth()) {
6813 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6820 I.eraseFromParent();
6829 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6831 FrameAddr = NextFrame;
6834 if (IntrinID == Intrinsic::frameaddress)
6839 if (STI.hasPAuth()) {
6841 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6842 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6851 I.eraseFromParent();
6854 case Intrinsic::aarch64_neon_tbl2:
6855 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6857 case Intrinsic::aarch64_neon_tbl3:
6858 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6861 case Intrinsic::aarch64_neon_tbl4:
6862 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6864 case Intrinsic::aarch64_neon_tbx2:
6865 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6867 case Intrinsic::aarch64_neon_tbx3:
6868 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6870 case Intrinsic::aarch64_neon_tbx4:
6871 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6873 case Intrinsic::swift_async_context_addr:
6874 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6881 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6882 I.eraseFromParent();
6917bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6918 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6919 Register DefReg =
I.getOperand(0).getReg();
6920 Register Addr =
I.getOperand(1).getReg();
6922 Register AddrDisc =
I.getOperand(3).getReg();
6923 uint64_t Disc =
I.getOperand(4).getImm();
6933 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6949 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6961 const GlobalValue *GV;
6972 MachineIRBuilder MIB(
I);
6978 "unsupported non-GOT op flags on ptrauth global reference");
6980 "unsupported non-GOT reference to weak ptrauth global");
6983 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6990 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6993 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6998 I.eraseFromParent();
7010 "unsupported non-zero offset in weak ptrauth global reference");
7015 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7016 .addGlobalAddress(GV,
Offset)
7021 I.eraseFromParent();
7025void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7026 MachineRegisterInfo &
MRI,
7027 unsigned NumVec,
unsigned Opc1,
7028 unsigned Opc2,
bool isExt) {
7029 Register DstReg =
I.getOperand(0).getReg();
7034 for (
unsigned i = 0; i < NumVec; i++)
7035 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7038 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7039 MachineInstrBuilder
Instr;
7046 I.eraseFromParent();
7049InstructionSelector::ComplexRendererFns
7050AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7052 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7053 return std::nullopt;
7054 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7055 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7058InstructionSelector::ComplexRendererFns
7059AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7061 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7062 return std::nullopt;
7064 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7067InstructionSelector::ComplexRendererFns
7068AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7070 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7071 return std::nullopt;
7072 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7073 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7076InstructionSelector::ComplexRendererFns
7077AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7079 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7080 return std::nullopt;
7082 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7085template <
unsigned ShiftW
idth>
7086InstructionSelector::ComplexRendererFns
7087AArch64InstructionSelector::selectShiftMask(MachineOperand &Root)
const {
7089 return std::nullopt;
7091 MachineRegisterInfo &
MRI =
7098 if (ShiftWidth == 32) {
7101 ShAmtReg = ZExtSrcReg;
7110 ShAmtReg = AndSrcReg;
7122 (AddImm % ShiftWidth == 0)) {
7123 ShAmtReg = AddSrcReg;
7124 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7133 SubImm != 0 && (SubImm % ShiftWidth == 0)) {
7134 return {{[=](MachineInstrBuilder &MIB) {
7135 MachineInstr *
I = MIB.getInstr();
7138 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7139 unsigned SubOpc = ShiftWidth == 32 ? AArch64::SUBWrr : AArch64::SUBXrr;
7140 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7142 auto NegMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7143 TII.get(SubOpc), NegReg)
7157 (NotImm % ShiftWidth == ShiftWidth - 1)) {
7158 return {{[=](MachineInstrBuilder &MIB) {
7159 MachineInstr *
I = MIB.getInstr();
7162 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7163 unsigned NotOpc = ShiftWidth == 32 ? AArch64::ORNWrr : AArch64::ORNXrr;
7164 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7166 auto NotMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7167 TII.get(NotOpc), NotReg)
7177 if (ShAmtReg == Root.
getReg())
7178 return std::nullopt;
7180 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7188InstructionSelector::ComplexRendererFns
7189AArch64InstructionSelector::select12BitValueWithLeftShift(
7192 if (Immed >> 12 == 0) {
7194 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7196 Immed = Immed >> 12;
7198 return std::nullopt;
7202 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7203 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7210InstructionSelector::ComplexRendererFns
7211AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7218 if (MaybeImmed == std::nullopt)
7219 return std::nullopt;
7220 return select12BitValueWithLeftShift(*MaybeImmed);
7225InstructionSelector::ComplexRendererFns
7226AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7230 return std::nullopt;
7232 if (MaybeImmed == std::nullopt)
7233 return std::nullopt;
7240 return std::nullopt;
7246 Immed = ~((uint32_t)Immed) + 1;
7248 Immed = ~Immed + 1ULL;
7250 if (Immed & 0xFFFFFFFFFF000000ULL)
7251 return std::nullopt;
7253 Immed &= 0xFFFFFFULL;
7254 return select12BitValueWithLeftShift(Immed);
7271std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7272 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7273 if (
MI.getOpcode() == AArch64::G_SHL) {
7277 MI.getOperand(2).getReg(),
MRI)) {
7278 const APInt ShiftVal = ValAndVeg->Value;
7281 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7284 return std::nullopt;
7292bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7293 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7294 bool IsAddrOperand)
const {
7299 MI.getParent()->getParent()->getFunction().hasOptSize())
7302 if (IsAddrOperand) {
7304 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7308 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7309 MachineInstr *OffsetInst =
7315 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7326 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7329InstructionSelector::ComplexRendererFns
7330AArch64InstructionSelector::selectExtendedSHL(
7331 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7332 unsigned SizeInBytes,
bool WantsExt)
const {
7333 assert(
Base.isReg() &&
"Expected base to be a register operand");
7334 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7339 unsigned OffsetOpc = OffsetInst->
getOpcode();
7340 bool LookedThroughZExt =
false;
7341 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7343 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7344 return std::nullopt;
7348 LookedThroughZExt =
true;
7350 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7351 return std::nullopt;
7354 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7355 if (LegalShiftVal == 0)
7356 return std::nullopt;
7357 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7358 return std::nullopt;
7369 if (OffsetOpc == TargetOpcode::G_SHL)
7370 return std::nullopt;
7376 return std::nullopt;
7381 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7385 if (OffsetOpc == TargetOpcode::G_MUL) {
7387 return std::nullopt;
7393 if ((ImmVal & 0x7) != ImmVal)
7394 return std::nullopt;
7398 if (ImmVal != LegalShiftVal)
7399 return std::nullopt;
7401 unsigned SignExtend = 0;
7405 if (!LookedThroughZExt) {
7407 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7409 return std::nullopt;
7414 return std::nullopt;
7420 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7425 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7426 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7427 [=](MachineInstrBuilder &MIB) {
7430 MIB.addImm(SignExtend);
7443InstructionSelector::ComplexRendererFns
7444AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7445 MachineOperand &Root,
unsigned SizeInBytes)
const {
7447 return std::nullopt;
7462 MachineInstr *PtrAdd =
7464 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7465 return std::nullopt;
7469 MachineInstr *OffsetInst =
7471 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7484InstructionSelector::ComplexRendererFns
7485AArch64InstructionSelector::selectAddrModeRegisterOffset(
7486 MachineOperand &Root)
const {
7492 return std::nullopt;
7498 return std::nullopt;
7501 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7502 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7503 [=](MachineInstrBuilder &MIB) {
7513InstructionSelector::ComplexRendererFns
7514AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7515 unsigned SizeInBytes)
const {
7518 return std::nullopt;
7519 MachineInstr *PtrAdd =
7522 return std::nullopt;
7540 unsigned Scale =
Log2_32(SizeInBytes);
7541 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7545 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7546 ImmOff < (0x1000 << Scale))
7547 return std::nullopt;
7552 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7556 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7562 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7563 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7568 return std::nullopt;
7572 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7578 return selectAddrModeRegisterOffset(Root);
7587InstructionSelector::ComplexRendererFns
7588AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7589 unsigned SizeInBytes)
const {
7592 MachineInstr *PtrAdd =
7594 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7595 return std::nullopt;
7616 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7625 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7626 return std::nullopt;
7630 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7632 return std::nullopt;
7635 MachineIRBuilder MIB(*PtrAdd);
7637 AArch64::GPR32RegClass, MIB);
7641 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7642 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7643 [=](MachineInstrBuilder &MIB) {
7644 MIB.addImm(SignExtend);
7654InstructionSelector::ComplexRendererFns
7655AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7656 unsigned Size)
const {
7657 MachineRegisterInfo &
MRI =
7661 return std::nullopt;
7663 if (!isBaseWithConstantOffset(Root,
MRI))
7664 return std::nullopt;
7668 MachineOperand &OffImm = RootDef->
getOperand(2);
7669 if (!OffImm.
isReg())
7670 return std::nullopt;
7672 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7673 return std::nullopt;
7675 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7677 return std::nullopt;
7680 if (RHSC >= -256 && RHSC < 256) {
7683 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7684 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7687 return std::nullopt;
7690InstructionSelector::ComplexRendererFns
7691AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7693 MachineRegisterInfo &
MRI)
const {
7694 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7695 return std::nullopt;
7698 return std::nullopt;
7703 return std::nullopt;
7707 return std::nullopt;
7711 return std::nullopt;
7714 MachineIRBuilder MIRBuilder(RootDef);
7716 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7717 [=](MachineInstrBuilder &MIB) {
7718 MIB.addGlobalAddress(GV,
Offset,
7727InstructionSelector::ComplexRendererFns
7728AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7729 unsigned Size)
const {
7734 return std::nullopt;
7737 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7739 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7740 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7748 MachineInstr *RootParent = Root.
getParent();
7750 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7752 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7757 if (isBaseWithConstantOffset(Root,
MRI)) {
7765 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7766 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7768 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7769 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7773 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7774 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7781 if (selectAddrModeUnscaled(Root,
Size))
7782 return std::nullopt;
7785 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7786 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7793 switch (
MI.getOpcode()) {
7796 case TargetOpcode::G_SHL:
7798 case TargetOpcode::G_LSHR:
7800 case TargetOpcode::G_ASHR:
7802 case TargetOpcode::G_ROTR:
7809InstructionSelector::ComplexRendererFns
7810AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7811 bool AllowROR)
const {
7813 return std::nullopt;
7814 MachineRegisterInfo &
MRI =
7822 return std::nullopt;
7824 return std::nullopt;
7825 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7826 return std::nullopt;
7829 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7832 return std::nullopt;
7836 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7840 unsigned Val = *Immed & (NumBits - 1);
7843 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7844 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7848 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7849 unsigned Opc =
MI.getOpcode();
7852 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7854 if (
Opc == TargetOpcode::G_SEXT)
7857 Size =
MI.getOperand(2).getImm();
7858 assert(
Size != 64 &&
"Extend from 64 bits?");
7871 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7873 assert(
Size != 64 &&
"Extend from 64 bits?");
7888 if (
Opc != TargetOpcode::G_AND)
7907Register AArch64InstructionSelector::moveScalarRegClass(
7909 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7919 return Copy.getReg(0);
7924InstructionSelector::ComplexRendererFns
7925AArch64InstructionSelector::selectArithExtendedRegister(
7926 MachineOperand &Root)
const {
7928 return std::nullopt;
7929 MachineRegisterInfo &
MRI =
7937 return std::nullopt;
7939 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7940 return std::nullopt;
7943 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7948 return std::nullopt;
7949 ShiftVal = *MaybeShiftVal;
7951 return std::nullopt;
7956 return std::nullopt;
7957 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7959 return std::nullopt;
7963 Ext = getExtendTypeForInst(*RootDef,
MRI);
7965 return std::nullopt;
7974 if (isDef32(*ExtInst))
7975 return std::nullopt;
7981 MachineIRBuilder MIB(*RootDef);
7982 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7984 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7985 [=](MachineInstrBuilder &MIB) {
7986 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7990InstructionSelector::ComplexRendererFns
7991AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7993 return std::nullopt;
7994 MachineRegisterInfo &
MRI =
7998 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
8003 return std::nullopt;
8006 if (Unmerge->getNumDefs() == 2 &&
8008 Register ExtReg = Unmerge->getSourceReg();
8009 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8013 LLT SrcTy =
MRI.
getType(ExtElt->getVectorReg());
8017 LaneIdx->Value.getSExtValue() == 1) {
8018 Register ExtReg = ExtElt->getVectorReg();
8019 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8023 LLT SrcTy =
MRI.
getType(Subvec->getSrcVec());
8024 auto LaneIdx = Subvec->getIndexImm();
8026 Register ExtReg = Subvec->getSrcVec();
8027 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8031 return std::nullopt;
8034InstructionSelector::ComplexRendererFns
8035AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
8036 unsigned DstElemWidth,
8037 bool isReciprocal)
const {
8039 return std::nullopt;
8040 const MachineRegisterInfo &
MRI =
8046 if (Dup && Dup->
getOpcode() == TargetOpcode::G_SPLAT_VECTOR)
8049 std::optional<ValueAndVReg> CstVal =
8053 return std::nullopt;
8057 switch (CstElemWidth) {
8059 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value.trunc(CstElemWidth));
8062 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8065 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8068 return std::nullopt;
8070 if (
unsigned FBits =
8072 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8074 return std::nullopt;
8077unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8078 const MachineOperand &Root)
const {
8086template <
unsigned W
idth>
8087InstructionSelector::ComplexRendererFns
8088AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8089 return selectCVTFixedPointBase(Root, Width,
false);
8092template <
unsigned W
idth>
8093InstructionSelector::ComplexRendererFns
8094AArch64InstructionSelector::selectCVTFixedPosRecipOperand(
8095 MachineOperand &Root)
const {
8096 return selectCVTFixedPointBase(Root, Width,
true);
8099InstructionSelector::ComplexRendererFns
8100AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8101 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8105InstructionSelector::ComplexRendererFns
8106AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8107 MachineOperand &Root)
const {
8108 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8112void AArch64InstructionSelector::renderFixedPointScalarXForm(
8113 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8114 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8115 "Expected vecshift immediate operand");
8116 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8119void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8120 const MachineOperand &Root,
8122 bool isReciprocal)
const {
8126 InstructionSelector::ComplexRendererFns Renderer =
8127 selectCVTFixedPointBase(Root, Width, isReciprocal);
8128 assert((Renderer && Renderer->size() == 1) &&
8129 "Expected selectCVTFixedPointBase to provide a function\n");
8130 (Renderer->front())(MIB);
8133void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8134 const MachineInstr &
MI,
8136 const MachineOperand &Root =
MI.getOperand(OpIdx);
8137 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8141void AArch64InstructionSelector::renderFixedPointRecipXForm(
8142 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8143 const MachineOperand &Root =
MI.getOperand(OpIdx);
8144 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8148void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8149 const MachineInstr &
MI,
8151 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
8152 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8153 "Expected G_CONSTANT");
8154 std::optional<int64_t> CstVal =
8156 assert(CstVal &&
"Expected constant value");
8160void AArch64InstructionSelector::renderLogicalImm32(
8161 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8162 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8163 "Expected G_CONSTANT");
8164 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8169void AArch64InstructionSelector::renderLogicalImm64(
8170 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8171 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8172 "Expected G_CONSTANT");
8173 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8178void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8179 const MachineInstr &
MI,
8181 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8182 "Expected G_UBSANTRAP");
8183 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8186void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8187 const MachineInstr &
MI,
8189 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8190 "Expected G_FCONSTANT");
8195void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8196 const MachineInstr &
MI,
8198 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8199 "Expected G_FCONSTANT");
8204void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8205 const MachineInstr &
MI,
8207 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8208 "Expected G_FCONSTANT");
8213void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8214 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8215 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8216 "Expected G_FCONSTANT");
8224bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8225 const MachineInstr &
MI,
unsigned NumBytes)
const {
8226 if (!
MI.mayLoadOrStore())
8229 "Expected load/store to have only one mem op!");
8230 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8233bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8234 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
8242 switch (
MI.getOpcode()) {
8245 case TargetOpcode::COPY:
8246 case TargetOpcode::G_BITCAST:
8247 case TargetOpcode::G_TRUNC:
8248 case TargetOpcode::G_PHI:
8258 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8261 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8272 auto *OpDef =
MRI.getVRegDef(OpReg);
8273 const LLT &Ty =
MRI.getType(OpReg);
8279 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8283 MRI.setRegBank(Copy.getReg(0), *DstRB);
8284 MO.setReg(Copy.getReg(0));
8293 for (
auto &BB : MF) {
8294 for (
auto &
MI : BB) {
8295 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8300 for (
auto *
MI : Phis) {
8322 bool HasGPROp =
false, HasFPROp =
false;
8336 if (RB->
getID() == AArch64::GPRRegBankID)
8342 if (HasGPROp && HasFPROp)
8348InstructionSelector *
8352 return new AArch64InstructionSelector(TM,
Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
const AArch64Subtarget & Subtarget
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.
const TargetLowering & TLI
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static std::optional< APInt > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc, appropriate for the register ban...
static bool getSubRegForClass(const TargetRegisterClass *RC, const TargetRegisterInfo &TRI, unsigned &SubReg)
Returns the correct subregister to use for a given register class.
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI, Register SrcReg, const TargetRegisterClass *To, unsigned SubReg)
Helper function for selectCopy.
static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P, Register RHS={}, MachineRegisterInfo *MRI=nullptr)
static std::optional< uint64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, const AArch64RegisterBankInfo &RBI)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static MachineBasicBlock * emitSelect(MachineInstr &MI, MachineBasicBlock *BB, const TargetInstrInfo *TII, const PPCSubtarget &Subtarget)
Emit SELECT instruction, using ISEL if available, otherwise use branch-based control flow.
static StringRef getName(Value *V)
MachineRegisterInfo & MRI
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
bool hasELFSignedGOT() const
int getVarArgsFPRIndex() const
void incNumLocalDynamicTLSAccesses()
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
unsigned countr_one() const
Count the number of trailing one bits.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValue() const
const APFloat & getValueAPF() const
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & setOperandDead(unsigned OpIdx) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool isDebugInstr() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
void setImplicitPhysRegDefsDead()
Mark the implicit physreg defs named by the instruction description as dead.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
const MachineFunction & getMF() const
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
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 isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize=false) const
Returns true if the specified FP immediate can be materialized without a load from the constant pool.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
unsigned TLSSize
Bit size of immediate TLS offsets (0 == use the default).
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_HI12
MO_HI12 - This flag indicates that a symbol operand represents the bits 13-24 of a 64-bit address,...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
bool expandVectorMOVImm(APInt Imm, SmallVectorImpl< ImmInsnModel > &Insn, const AArch64Subtarget &ST)
TLSModel::Model getELFTLSModel(const GlobalValue *GV, const AArch64TargetMachine &TM, bool HasELFSignedGOT)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
auto m_PosZeroFP()
Matches a floating-point positive zero.
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
@ O1
Optimize quickly without destroying debuggability.
@ O0
Disable as many optimizations as possible.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI std::optional< Register > getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI)
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.