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:
3411 case TargetOpcode::G_SELECT: {
3413 const Register CondReg = Sel.getCondReg();
3415 const Register FReg = Sel.getFalseReg();
3417 if (tryOptSelect(Sel))
3423 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3428 Sel.eraseFromParent();
3431 case TargetOpcode::G_ICMP: {
3441 auto &PredOp =
I.getOperand(1);
3442 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3446 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3447 AArch64::WZR, InvCC, MIB);
3448 I.eraseFromParent();
3452 case TargetOpcode::G_FCMP: {
3455 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3457 !emitCSetForFCmp(
I.getOperand(0).getReg(),
Pred, MIB))
3459 I.eraseFromParent();
3462 case TargetOpcode::G_VASTART:
3464 : selectVaStartAAPCS(
I, MF,
MRI);
3465 case TargetOpcode::G_INTRINSIC:
3466 return selectIntrinsic(
I,
MRI);
3467 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3468 return selectIntrinsicWithSideEffects(
I,
MRI);
3469 case TargetOpcode::G_IMPLICIT_DEF: {
3470 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3471 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3472 const Register DstReg =
I.getOperand(0).getReg();
3478 case TargetOpcode::G_BLOCK_ADDR: {
3479 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3480 if (std::optional<uint16_t> BADisc =
3490 AArch64::GPR64RegClass,
MRI);
3491 I.eraseFromParent();
3495 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3496 I.eraseFromParent();
3499 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3500 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3501 I.getOperand(0).getReg())
3505 I.getOperand(1).getBlockAddress(), 0,
3507 I.eraseFromParent();
3512 case TargetOpcode::G_BUILD_VECTOR:
3513 return selectBuildVector(
I,
MRI);
3514 case TargetOpcode::G_MERGE_VALUES:
3516 case TargetOpcode::G_UNMERGE_VALUES:
3518 case TargetOpcode::G_SHUFFLE_VECTOR:
3519 return selectShuffleVector(
I,
MRI);
3520 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3521 return selectExtractElt(
I,
MRI);
3522 case TargetOpcode::G_CONCAT_VECTORS:
3523 return selectConcatVectors(
I,
MRI);
3524 case TargetOpcode::G_JUMP_TABLE:
3525 return selectJumpTable(
I,
MRI);
3526 case TargetOpcode::G_MEMCPY:
3527 case TargetOpcode::G_MEMCPY_INLINE:
3528 case TargetOpcode::G_MEMMOVE:
3529 case TargetOpcode::G_MEMSET:
3530 case TargetOpcode::G_MEMSET_INLINE:
3531 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3532 return selectMOPS(
I,
MRI);
3538bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3539 MachineIRBuilderState OldMIBState = MIB.
getState();
3545bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3546 MachineRegisterInfo &
MRI) {
3549 case TargetOpcode::G_MEMCPY:
3550 case TargetOpcode::G_MEMCPY_INLINE:
3551 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3553 case TargetOpcode::G_MEMMOVE:
3554 Mopcode = AArch64::MOPSMemoryMovePseudo;
3556 case TargetOpcode::G_MEMSET:
3557 case TargetOpcode::G_MEMSET_INLINE:
3559 Mopcode = AArch64::MOPSMemorySetPseudo;
3572 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3573 const auto &SrcValRegClass =
3574 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3592 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3593 {DstPtrCopy, SizeCopy, SrcValCopy})
3597 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3598 {DstPtrCopy, SrcValCopy, SizeCopy})
3606bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3607 MachineRegisterInfo &
MRI) {
3608 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3609 Register JTAddr =
I.getOperand(0).getReg();
3610 unsigned JTI =
I.getOperand(1).getIndex();
3613 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3625 "jump table hardening only supported on MachO/ELF");
3633 I.eraseFromParent();
3640 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3641 {TargetReg, ScratchReg}, {JTAddr,
Index})
3642 .addJumpTableIndex(JTI);
3644 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3645 {
static_cast<int64_t
>(JTI)});
3647 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3648 I.eraseFromParent();
3653bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3654 MachineRegisterInfo &
MRI) {
3655 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3656 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3658 Register DstReg =
I.getOperand(0).getReg();
3659 unsigned JTI =
I.getOperand(1).getIndex();
3662 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3665 I.eraseFromParent();
3670bool AArch64InstructionSelector::selectTLSLocalExecELF(
3671 const GlobalValue *GV, MachineInstr &
I, MachineRegisterInfo &
MRI) {
3672 auto ConstrainRegOps = [&](MachineInstrBuilder MIB) {
3676 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {}));
3684 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()},
3695 MIB.
buildInstr(AArch64::ADDXri, {Addr}, {ThreadBase})
3699 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()}, {Addr})
3716 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3721 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3722 {ThreadBase, Addr2}));
3736 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3742 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr3}, {Addr2})
3747 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3748 {ThreadBase, Addr3}));
3752 I.eraseFromParent();
3758bool AArch64InstructionSelector::selectTLSGlobalValueELF(
3759 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3760 const GlobalValue *GV =
I.
getOperand(1).getGlobal();
3761 auto *FuncInfo = MF->
getInfo<AArch64FunctionInfo>();
3768 return selectTLSLocalExecELF(GV,
I,
MRI);
3770 MIB.
buildInstr(AArch64::LOADgot, {TPOff}, {})
3776 SMEAttrs
Attrs = MF->
getInfo<AArch64FunctionInfo>()->getSMEFnAttrs();
3778 !
Attrs.hasStreamingCompatibleInterface() &&
3779 "unsupported SME features reached GlobalISel TLS lowering");
3782 ? AArch64::TLSDESC_AUTH_CALLSEQ
3783 : AArch64::TLSDESC_CALLSEQ;
3802 MIB.
buildInstr(AArch64::ADDXri, {TPOff}, {Add1.getReg(0)})
3803 .addGlobalAddress(GV, 0,
3812 MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {});
3813 auto Add = MIB.
buildInstr(AArch64::ADDXrr, {
I.getOperand(0).getReg()},
3814 {ThreadBase, TPOff});
3817 I.eraseFromParent();
3821bool AArch64InstructionSelector::selectTLSGlobalValueMachO(
3822 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3823 const auto &GlobalOp =
I.getOperand(1);
3824 assert(GlobalOp.getOffset() == 0 &&
3825 "Shouldn't have an offset on TLS globals!");
3827 const GlobalValue &GV = *GlobalOp.getGlobal();
3830 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3833 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3834 {LoadGOT.getReg(0)})
3845 assert(Opcode == AArch64::BLR);
3846 Opcode = AArch64::BLRAAZ;
3851 .
addUse(AArch64::X0, RegState::Implicit)
3852 .
addDef(AArch64::X0, RegState::Implicit)
3858 I.eraseFromParent();
3862bool AArch64InstructionSelector::selectTLSGlobalValue(
3863 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3869 return selectTLSGlobalValueELF(
I,
MRI);
3872 return selectTLSGlobalValueMachO(
I,
MRI);
3877MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3879 MachineIRBuilder &MIRBuilder)
const {
3880 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3882 auto BuildFn = [&](
unsigned SubregIndex) {
3886 .addImm(SubregIndex);
3894 return BuildFn(AArch64::bsub);
3896 return BuildFn(AArch64::hsub);
3898 return BuildFn(AArch64::ssub);
3900 return BuildFn(AArch64::dsub);
3907AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3908 MachineIRBuilder &MIB,
3909 MachineRegisterInfo &
MRI)
const {
3913 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3917 unsigned SubReg = 0;
3920 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3926 .addReg(SrcReg, {}, SubReg);
3931bool AArch64InstructionSelector::selectMergeValues(
3932 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3933 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3934 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3935 const LLT SrcTy =
MRI.
getType(
I.getOperand(1).getReg());
3939 if (
I.getNumOperands() != 3)
3946 Register DstReg =
I.getOperand(0).getReg();
3947 Register Src1Reg =
I.getOperand(1).getReg();
3948 Register Src2Reg =
I.getOperand(2).getReg();
3949 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3950 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3954 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3955 Src2Reg, 1, RB, MIB);
3960 I.eraseFromParent();
3964 if (RB.
getID() != AArch64::GPRRegBankID)
3970 auto *DstRC = &AArch64::GPR64RegClass;
3972 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3973 TII.get(TargetOpcode::SUBREG_TO_REG))
3975 .
addUse(
I.getOperand(1).getReg())
3976 .
addImm(AArch64::sub_32);
3979 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3980 TII.get(TargetOpcode::SUBREG_TO_REG))
3982 .
addUse(
I.getOperand(2).getReg())
3983 .
addImm(AArch64::sub_32);
3985 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3986 .
addDef(
I.getOperand(0).getReg())
3994 I.eraseFromParent();
3999 const unsigned EltSize) {
4004 CopyOpc = AArch64::DUPi8;
4005 ExtractSubReg = AArch64::bsub;
4008 CopyOpc = AArch64::DUPi16;
4009 ExtractSubReg = AArch64::hsub;
4012 CopyOpc = AArch64::DUPi32;
4013 ExtractSubReg = AArch64::ssub;
4016 CopyOpc = AArch64::DUPi64;
4017 ExtractSubReg = AArch64::dsub;
4021 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
4027MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
4028 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
4029 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
4030 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4031 unsigned CopyOpc = 0;
4032 unsigned ExtractSubReg = 0;
4035 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
4040 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
4042 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
4049 getRegClassForTypeOnBank(VecTy, VecRB,
true);
4051 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4061 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4062 .addReg(VecReg, {}, ExtractSubReg);
4071 MachineInstr *ScalarToVector = emitScalarToVector(
4072 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4073 if (!ScalarToVector)
4078 MachineInstr *LaneCopyMI =
4079 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4087bool AArch64InstructionSelector::selectExtractElt(
4088 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4089 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4090 "unexpected opcode!");
4091 Register DstReg =
I.getOperand(0).getReg();
4093 const Register SrcReg =
I.getOperand(1).getReg();
4096 "source register size too small!");
4097 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4100 MachineOperand &LaneIdxOp =
I.getOperand(2);
4101 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4107 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4110 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4114 Opcode = AArch64::UMOVvi8;
4117 Opcode = AArch64::UMOVvi16;
4120 Opcode = AArch64::UMOVvi32;
4127 MachineInstr *ScalarToVector = emitScalarToVector(
4128 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4129 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4133 I.setDesc(
TII.get(Opcode));
4134 I.getOperand(2).ChangeToImmediate(LaneIdx);
4139 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4144 I.eraseFromParent();
4148bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4149 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4150 unsigned NumElts =
I.getNumOperands() - 1;
4151 Register SrcReg =
I.getOperand(NumElts).getReg();
4152 const LLT NarrowTy =
MRI.
getType(
I.getOperand(0).getReg());
4155 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4157 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4163 const RegisterBank &DstRB =
4165 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4166 Register Dst =
I.getOperand(OpIdx).getReg();
4167 MachineInstr *Extract =
4168 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4172 I.eraseFromParent();
4176bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4177 MachineRegisterInfo &
MRI) {
4178 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4179 "unexpected opcode");
4183 unsigned NumElts =
I.getNumOperands() - 1;
4184 Register SrcReg =
I.getOperand(NumElts).getReg();
4185 Register LoReg =
I.getOperand(0).getReg();
4186 Register HiReg =
I.getOperand(1).getReg();
4195 LoRB.
getID() == AArch64::GPRRegBankID &&
4196 HiRB.
getID() == AArch64::GPRRegBankID &&
4197 SrcRB.
getID() == AArch64::FPRRegBankID) {
4198 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4199 TII.get(AArch64::UMOVvi64), LoReg)
4202 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4203 TII.get(AArch64::UMOVvi64), HiReg)
4208 I.eraseFromParent();
4213 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4214 HiRB.
getID() != AArch64::FPRRegBankID) {
4215 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4216 "currently unsupported.\n");
4221 "source register size too small!");
4224 return selectSplitVectorUnmerge(
I,
MRI);
4228 unsigned CopyOpc = 0;
4229 unsigned ExtractSubReg = 0;
4240 unsigned NumInsertRegs = NumElts - 1;
4246 InsertRegs.
assign(NumInsertRegs, SrcReg);
4255 unsigned SubReg = 0;
4258 assert(Found &&
"expected to find last operand's subeg idx");
4259 for (
unsigned Idx = 0;
Idx < NumInsertRegs; ++
Idx) {
4261 MachineInstr &ImpDefMI =
4262 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4267 MachineInstr &InsMI =
4269 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4286 Register CopyTo =
I.getOperand(0).getReg();
4287 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4288 .addReg(InsertRegs[0], {}, ExtractSubReg);
4292 unsigned LaneIdx = 1;
4293 for (
Register InsReg : InsertRegs) {
4294 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4295 MachineInstr &CopyInst =
4314 I.eraseFromParent();
4318bool AArch64InstructionSelector::selectConcatVectors(
4319 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4320 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4321 "Unexpected opcode");
4322 Register Dst =
I.getOperand(0).getReg();
4323 Register Op1 =
I.getOperand(1).getReg();
4324 Register Op2 =
I.getOperand(2).getReg();
4325 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4328 I.eraseFromParent();
4333AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4342MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4343 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4350 RC = &AArch64::FPR128RegClass;
4351 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4354 RC = &AArch64::FPR64RegClass;
4355 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4358 RC = &AArch64::FPR32RegClass;
4359 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4362 RC = &AArch64::FPR16RegClass;
4363 Opc = AArch64::LDRHui;
4366 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4371 MachineInstr *LoadMI =
nullptr;
4372 auto &MF = MIRBuilder.
getMF();
4373 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4374 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4376 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4379 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4383 .addConstantPoolIndex(
4399static std::pair<unsigned, unsigned>
4401 unsigned Opc, SubregIdx;
4402 if (RB.
getID() == AArch64::GPRRegBankID) {
4404 Opc = AArch64::INSvi8gpr;
4405 SubregIdx = AArch64::bsub;
4406 }
else if (EltSize == 16) {
4407 Opc = AArch64::INSvi16gpr;
4408 SubregIdx = AArch64::ssub;
4409 }
else if (EltSize == 32) {
4410 Opc = AArch64::INSvi32gpr;
4411 SubregIdx = AArch64::ssub;
4412 }
else if (EltSize == 64) {
4413 Opc = AArch64::INSvi64gpr;
4414 SubregIdx = AArch64::dsub;
4420 Opc = AArch64::INSvi8lane;
4421 SubregIdx = AArch64::bsub;
4422 }
else if (EltSize == 16) {
4423 Opc = AArch64::INSvi16lane;
4424 SubregIdx = AArch64::hsub;
4425 }
else if (EltSize == 32) {
4426 Opc = AArch64::INSvi32lane;
4427 SubregIdx = AArch64::ssub;
4428 }
else if (EltSize == 64) {
4429 Opc = AArch64::INSvi64lane;
4430 SubregIdx = AArch64::dsub;
4435 return std::make_pair(
Opc, SubregIdx);
4438MachineInstr *AArch64InstructionSelector::emitInstr(
4439 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4440 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4441 const ComplexRendererFns &RenderFns)
const {
4442 assert(Opcode &&
"Expected an opcode?");
4444 "Function should only be used to produce selected instructions!");
4445 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4447 for (
auto &Fn : *RenderFns)
4453MachineInstr *AArch64InstructionSelector::emitAddSub(
4454 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4456 MachineIRBuilder &MIRBuilder)
const {
4458 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4462 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4463 bool Is32Bit =
Size == 32;
4466 if (
auto Fns = selectArithImmed(
RHS))
4467 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4471 if (
auto Fns = selectNegArithImmed(
RHS))
4472 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4476 if (
auto Fns = selectArithExtendedRegister(
RHS))
4477 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4481 if (
auto Fns = selectShiftedRegister(
RHS))
4482 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4484 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4489AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4490 MachineOperand &
RHS,
4491 MachineIRBuilder &MIRBuilder)
const {
4492 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4493 {{AArch64::ADDXri, AArch64::ADDWri},
4494 {AArch64::ADDXrs, AArch64::ADDWrs},
4495 {AArch64::ADDXrr, AArch64::ADDWrr},
4496 {AArch64::SUBXri, AArch64::SUBWri},
4497 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4498 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4502AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4503 MachineOperand &
RHS,
4504 MachineIRBuilder &MIRBuilder)
const {
4505 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4506 {{AArch64::ADDSXri, AArch64::ADDSWri},
4507 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4508 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4509 {AArch64::SUBSXri, AArch64::SUBSWri},
4510 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4511 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4515AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4516 MachineOperand &
RHS,
4517 MachineIRBuilder &MIRBuilder)
const {
4518 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4519 {{AArch64::SUBSXri, AArch64::SUBSWri},
4520 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4521 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4522 {AArch64::ADDSXri, AArch64::ADDSWri},
4523 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4524 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4528AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4529 MachineOperand &
RHS,
4530 MachineIRBuilder &MIRBuilder)
const {
4531 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4532 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4534 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4535 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4539AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4540 MachineOperand &
RHS,
4541 MachineIRBuilder &MIRBuilder)
const {
4542 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4543 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4545 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4546 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4550AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4551 MachineIRBuilder &MIRBuilder)
const {
4554 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4559AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4560 MachineIRBuilder &MIRBuilder)
const {
4563 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4568AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4569 MachineIRBuilder &MIRBuilder)
const {
4570 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4574 bool Is32Bit = (
RegSize == 32);
4575 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4576 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4577 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4581 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4584 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4591 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4592 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4593 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4596MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4597 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4598 MachineIRBuilder &MIRBuilder)
const {
4599 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4606 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4608 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4610 return emitCMP(
LHS,
RHS, MIRBuilder);
4613MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4615 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4619 "Expected a 32-bit scalar register?");
4621 const Register ZReg = AArch64::WZR;
4626 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4632 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4633 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4634 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4639MachineInstr *AArch64InstructionSelector::emitFPCompare(
4641 std::optional<CmpInst::Predicate>
Pred)
const {
4642 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4647 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4657 if (!ShouldUseImm &&
Pred && IsEqualityPred(*
Pred)) {
4660 ShouldUseImm =
true;
4664 unsigned CmpOpcTbl[2][3] = {
4665 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4666 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4668 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4680MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4682 MachineIRBuilder &MIRBuilder)
const {
4692 if (Op1Ty != Op2Ty) {
4693 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4696 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4699 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4714 MachineInstr *WidenedOp1 =
4715 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4716 MachineInstr *WidenedOp2 =
4717 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4718 if (!WidenedOp1 || !WidenedOp2) {
4719 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4724 unsigned InsertOpc, InsSubRegIdx;
4725 std::tie(InsertOpc, InsSubRegIdx) =
4743 MachineIRBuilder &MIRBuilder)
const {
4750 Size =
TRI.getRegSizeInBits(*RC);
4754 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4755 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4756 unsigned Opc = OpcTable[
Size == 64];
4762MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4764 MachineRegisterInfo *
MRI = MIB.
getMRI();
4765 unsigned Opcode =
I.getOpcode();
4769 bool NeedsNegatedCarry =
4770 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4787 if (SrcMI == PrevMI) {
4789 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4790 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4791 CarrySrcMI->isUnsigned() &&
4792 CarrySrcMI->getCarryOutReg() == CarryReg &&
4793 selectAndRestoreState(*SrcMI))
4800 if (NeedsNegatedCarry) {
4803 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4807 auto Fns = select12BitValueWithLeftShift(1);
4808 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4811bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4812 MachineRegisterInfo &
MRI) {
4817 emitCarryIn(
I, CarryInMI->getCarryInReg());
4821 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4822 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4824 Register CarryOutReg = CarryMI.getCarryOutReg();
4828 OpAndCC.first->addRegisterDead(AArch64::NZCV, &
TRI);
4835 emitCSINC(CarryOutReg, ZReg, ZReg,
4836 getInvertedCondCode(OpAndCC.second), MIB);
4839 I.eraseFromParent();
4843std::pair<MachineInstr *, AArch64CC::CondCode>
4844AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4845 MachineOperand &
LHS,
4846 MachineOperand &
RHS,
4847 MachineIRBuilder &MIRBuilder)
const {
4851 case TargetOpcode::G_SADDO:
4853 case TargetOpcode::G_UADDO:
4855 case TargetOpcode::G_SSUBO:
4857 case TargetOpcode::G_USUBO:
4859 case TargetOpcode::G_SADDE:
4861 case TargetOpcode::G_UADDE:
4863 case TargetOpcode::G_SSUBE:
4865 case TargetOpcode::G_USUBE:
4886 unsigned Depth = 0) {
4887 if (!
MRI.hasOneNonDBGUse(Val))
4893 MustBeFirst =
false;
4899 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4900 bool IsOR = Opcode == TargetOpcode::G_OR;
4912 if (MustBeFirstL && MustBeFirstR)
4918 if (!CanNegateL && !CanNegateR)
4922 CanNegate = WillNegate && CanNegateL && CanNegateR;
4925 MustBeFirst = !CanNegate;
4927 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4930 MustBeFirst = MustBeFirstL || MustBeFirstR;
4937MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4940 MachineIRBuilder &MIB)
const {
4944 std::optional<ValueAndVReg>
C;
4948 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4949 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4950 else if (
C->Value.ule(31))
4951 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4953 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4959 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4960 CCmpOpc = AArch64::FCCMPHrr;
4963 CCmpOpc = AArch64::FCCMPSrr;
4966 CCmpOpc = AArch64::FCCMPDrr;
4976 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4977 CCmp.
addImm(
C->Value.getZExtValue());
4978 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4979 CCmp.
addImm(
C->Value.abs().getZExtValue());
4987MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
5009 MachineInstr *ExtraCmp;
5011 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB,
CC);
5023 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
5024 return emitFPCompare(
Cmp->getOperand(2).getReg(),
5025 Cmp->getOperand(3).getReg(), MIB);
5032 bool IsOR = Opcode == TargetOpcode::G_OR;
5038 assert(ValidL &&
"Valid conjunction/disjunction tree");
5045 assert(ValidR &&
"Valid conjunction/disjunction tree");
5050 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
5059 bool NegateAfterAll;
5060 if (Opcode == TargetOpcode::G_OR) {
5063 assert(CanNegateR &&
"at least one side must be negatable");
5064 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
5068 NegateAfterR =
true;
5071 NegateR = CanNegateR;
5072 NegateAfterR = !CanNegateR;
5075 NegateAfterAll = !Negate;
5077 assert(Opcode == TargetOpcode::G_AND &&
5078 "Valid conjunction/disjunction tree");
5079 assert(!Negate &&
"Valid conjunction/disjunction tree");
5083 NegateAfterR =
false;
5084 NegateAfterAll =
false;
5089 MachineInstr *CmpR =
5100MachineInstr *AArch64InstructionSelector::emitConjunction(
5102 bool DummyCanNegate;
5103 bool DummyMustBeFirst;
5110bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5111 MachineInstr &CondMI) {
5122bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5123 MachineRegisterInfo &
MRI = *MIB.
getMRI();
5142 MachineInstr *CondDef =
MRI.
getVRegDef(
I.getOperand(1).getReg());
5151 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5157 unsigned CondOpc = CondDef->
getOpcode();
5158 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5159 if (tryOptSelectConjunction(
I, *CondDef))
5165 if (CondOpc == TargetOpcode::G_ICMP) {
5194 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5195 I.getOperand(3).getReg(), CondCode, MIB);
5196 I.eraseFromParent();
5200MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5201 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5202 MachineIRBuilder &MIRBuilder)
const {
5204 "Unexpected MachineOperand");
5205 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5260 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5263 if (!ValAndVReg || ValAndVReg->Value != 0)
5273bool AArch64InstructionSelector::selectShuffleVector(
5274 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5275 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
5276 Register Src1Reg =
I.getOperand(1).getReg();
5277 Register Src2Reg =
I.getOperand(2).getReg();
5278 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5280 "Expected equal shuffle types during selection");
5289 SmallVector<int> NewMask;
5290 bool FirstUsed =
false;
5291 bool SecondUsed =
false;
5292 for (
int M : Mask) {
5294 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5297 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5302 FirstUsed |=
M < NumElts;
5303 SecondUsed |=
M >= NumElts;
5304 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5313 for (
int &M : NewMask) {
5315 assert(M >= ByteLanes && M < 2 * ByteLanes);
5325 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5326 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5339 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5346 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5350 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5355 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5356 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5358 I.eraseFromParent();
5363 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5366 I.eraseFromParent();
5374 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5377 I.eraseFromParent();
5381MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5383 unsigned LaneIdx,
const RegisterBank &RB,
5384 MachineIRBuilder &MIRBuilder)
const {
5385 MachineInstr *InsElt =
nullptr;
5387 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5396 if (RB.
getID() == AArch64::FPRRegBankID) {
5397 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5400 .
addUse(InsSub->getOperand(0).getReg())
5412bool AArch64InstructionSelector::selectUSMovFromExtend(
5413 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5414 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5415 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5416 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5418 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5419 const Register DefReg =
MI.getOperand(0).getReg();
5423 if (DstSize != 32 && DstSize != 64)
5426 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5427 MI.getOperand(1).getReg(),
MRI);
5438 const MachineInstr *ScalarToVector = emitScalarToVector(
5439 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5440 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5446 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5448 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5450 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5452 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5454 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5462 MachineInstr *ExtI =
nullptr;
5463 if (DstSize == 64 && !IsSigned) {
5466 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5468 .
addImm(AArch64::sub_32);
5474 MI.eraseFromParent();
5478bool AArch64InstructionSelector::selectIndexedExtLoad(
5479 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5482 Register WriteBack = ExtLd.getWritebackReg();
5487 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5488 bool IsPre = ExtLd.isPre();
5490 unsigned InsertIntoSubReg = 0;
5496 if ((IsSExt && IsFPR) || Ty.
isVector())
5504 if (MemSizeBits == 8) {
5507 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5509 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5510 NewLdDstTy = IsDst64 ? s64 : s32;
5512 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5513 InsertIntoSubReg = AArch64::bsub;
5516 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5517 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5520 }
else if (MemSizeBits == 16) {
5523 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5525 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5526 NewLdDstTy = IsDst64 ? s64 : s32;
5528 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5529 InsertIntoSubReg = AArch64::hsub;
5532 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5533 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5536 }
else if (MemSizeBits == 32) {
5538 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5541 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5542 InsertIntoSubReg = AArch64::ssub;
5545 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5546 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5558 .addImm(Cst->getSExtValue());
5563 if (InsertIntoSubReg) {
5565 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5566 .addUse(LdMI.getReg(1))
5567 .
addImm(InsertIntoSubReg);
5577 MI.eraseFromParent();
5582bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5583 MachineRegisterInfo &
MRI) {
5586 Register WriteBack = Ld.getWritebackReg();
5590 "Unexpected type for indexed load");
5591 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5594 return selectIndexedExtLoad(
MI,
MRI);
5598 static constexpr unsigned GPROpcodes[] = {
5599 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5601 static constexpr unsigned FPROpcodes[] = {
5602 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5605 ? FPROpcodes[
Log2_32(MemSize)]
5606 : GPROpcodes[
Log2_32(MemSize)];
5609 static constexpr unsigned GPROpcodes[] = {
5610 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5612 static constexpr unsigned FPROpcodes[] = {
5613 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5614 AArch64::LDRDpost, AArch64::LDRQpost};
5616 ? FPROpcodes[
Log2_32(MemSize)]
5617 : GPROpcodes[
Log2_32(MemSize)];
5627 MI.eraseFromParent();
5631bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5632 MachineRegisterInfo &
MRI) {
5638 "Unexpected type for indexed store");
5640 LocationSize MemSize =
I.getMMO().getSize();
5641 unsigned MemSizeInBytes = MemSize.
getValue();
5643 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5644 "Unexpected indexed store size");
5645 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5649 static constexpr unsigned GPROpcodes[] = {
5650 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5652 static constexpr unsigned FPROpcodes[] = {
5653 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5657 Opc = FPROpcodes[MemSizeLog2];
5659 Opc = GPROpcodes[MemSizeLog2];
5661 static constexpr unsigned GPROpcodes[] = {
5662 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5664 static constexpr unsigned FPROpcodes[] = {
5665 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5666 AArch64::STRDpost, AArch64::STRQpost};
5669 Opc = FPROpcodes[MemSizeLog2];
5671 Opc = GPROpcodes[MemSizeLog2];
5679 Str.cloneMemRefs(
I);
5681 I.eraseFromParent();
5686AArch64InstructionSelector::emitConstantMOVVector(DstOp Dst, APInt
Imm,
5687 MachineRegisterInfo &
MRI) {
5688 unsigned DstSize =
Imm.getBitWidth();
5689 assert((DstSize == 64 || DstSize == 128) &&
5690 "Unexpected vector constant size");
5694 for (AArch64_IMM::ImmInsnModel Insn : Insns) {
5695 switch (Insn.Opcode) {
5696 case AArch64::FMOVD0: {
5700 AArch64::MOVIv2d_ns,
5701 {DstSize == 128 ? Dst : DstOp(&AArch64::FPR128RegClass)}, {})
5704 if (DstSize != 128) {
5705 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5706 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5712 case AArch64::FMOVDi:
5713 case AArch64::FMOVv2f32_ns:
5714 case AArch64::FMOVv2f64_ns:
5715 case AArch64::FMOVv4f32_ns:
5716 case AArch64::FMOVv4f16_ns:
5717 case AArch64::FMOVv8f16_ns:
5718 case AArch64::MOVID:
5719 case AArch64::MOVIv16b_ns:
5720 case AArch64::MOVIv2d_ns:
5721 case AArch64::MOVIv2i32:
5722 case AArch64::MOVIv2s_msl:
5723 case AArch64::MOVIv4i16:
5724 case AArch64::MOVIv4i32:
5725 case AArch64::MOVIv4s_msl:
5726 case AArch64::MOVIv8b_ns:
5727 case AArch64::MOVIv8i16:
5728 case AArch64::MVNIv2i32:
5729 case AArch64::MVNIv2s_msl:
5730 case AArch64::MVNIv4i16:
5731 case AArch64::MVNIv4i32:
5732 case AArch64::MVNIv4s_msl:
5733 case AArch64::MVNIv8i16: {
5734 auto Mov = MIB.
buildInstr(Insn.Opcode, {Dst}, {});
5742 case AArch64::DUPM_ZI: {
5743 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5746 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5747 .addReg(Mov.getReg(0), {},
5748 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5750 DstSize == 64 ? AArch64::FPR64RegClass
5751 : AArch64::FPR128RegClass,
5755 case AArch64::DUP_ZI_D: {
5756 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5760 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5761 .addReg(Mov.getReg(0), {},
5762 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5764 DstSize == 64 ? AArch64::FPR64RegClass
5765 : AArch64::FPR128RegClass,
5777MachineInstr *AArch64InstructionSelector::emitConstantVector(
5778 Register Dst, Constant *CV, APInt
Imm, MachineRegisterInfo &
MRI) {
5779 if (
auto *MovI = emitConstantMOVVector(Dst,
Imm,
MRI))
5784 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5794bool AArch64InstructionSelector::tryOptConstantBuildVec(
5795 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5796 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5798 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5804 APInt
Imm(DstSize, 0);
5805 for (
unsigned Idx = 1;
Idx <
I.getNumOperands(); ++
Idx) {
5806 Register OpReg =
I.getOperand(Idx).getReg();
5818 std::move(AnyConst->Value)));
5831 if (!emitConstantVector(
I.getOperand(0).getReg(), CV,
Imm,
MRI))
5833 I.eraseFromParent();
5837bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5838 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5843 Register Dst =
I.getOperand(0).getReg();
5844 Register EltReg =
I.getOperand(1).getReg();
5853 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5861 getRegClassForTypeOnBank(
MRI.
getType(Dst), DstRB);
5866 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5869 I.eraseFromParent();
5874bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5875 MachineRegisterInfo &
MRI) {
5876 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5879 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
5880 const LLT EltTy =
MRI.
getType(
I.getOperand(1).getReg());
5883 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5885 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5888 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5893 MachineInstr *ScalarToVec =
5895 I.getOperand(1).getReg(), MIB);
5904 MachineInstr *PrevMI = ScalarToVec;
5905 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5908 Register OpReg =
I.getOperand(i).getReg();
5911 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5918 if (DstSize < 128) {
5924 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5929 unsigned SubReg = 0;
5932 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5933 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5939 Register DstReg =
I.getOperand(0).getReg();
5941 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5942 MachineOperand &RegOp =
I.getOperand(1);
5962 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5973bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5976 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5978 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5983 "Destination must be 64 bits or 128 bits?");
5984 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5985 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5990 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5991 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
5992 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5993 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6002bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6003 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6004 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6006 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6011 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6013 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6014 [](
auto MO) { return MO.getReg(); });
6018 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6033 .
addImm(LaneNo->getZExtValue())
6037 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6038 unsigned SubReg = AArch64::qsub0;
6039 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6040 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6041 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6044 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6049 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6055void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6058 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6060 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6063 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6064 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6073bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6074 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6075 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6080 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6081 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6085 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6095 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6098 .
addImm(LaneNo->getZExtValue())
6105bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6106 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6119 case Intrinsic::aarch64_ldxp:
6120 case Intrinsic::aarch64_ldaxp: {
6122 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6123 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6129 case Intrinsic::aarch64_neon_ld1x2: {
6133 Opc = AArch64::LD1Twov8b;
6135 Opc = AArch64::LD1Twov16b;
6137 Opc = AArch64::LD1Twov4h;
6139 Opc = AArch64::LD1Twov8h;
6141 Opc = AArch64::LD1Twov2s;
6143 Opc = AArch64::LD1Twov4s;
6145 Opc = AArch64::LD1Twov2d;
6146 else if (Ty ==
S64 || Ty == P0)
6147 Opc = AArch64::LD1Twov1d;
6150 selectVectorLoadIntrinsic(
Opc, 2,
I);
6153 case Intrinsic::aarch64_neon_ld1x3: {
6157 Opc = AArch64::LD1Threev8b;
6159 Opc = AArch64::LD1Threev16b;
6161 Opc = AArch64::LD1Threev4h;
6163 Opc = AArch64::LD1Threev8h;
6165 Opc = AArch64::LD1Threev2s;
6167 Opc = AArch64::LD1Threev4s;
6169 Opc = AArch64::LD1Threev2d;
6170 else if (Ty ==
S64 || Ty == P0)
6171 Opc = AArch64::LD1Threev1d;
6174 selectVectorLoadIntrinsic(
Opc, 3,
I);
6177 case Intrinsic::aarch64_neon_ld1x4: {
6181 Opc = AArch64::LD1Fourv8b;
6183 Opc = AArch64::LD1Fourv16b;
6185 Opc = AArch64::LD1Fourv4h;
6187 Opc = AArch64::LD1Fourv8h;
6189 Opc = AArch64::LD1Fourv2s;
6191 Opc = AArch64::LD1Fourv4s;
6193 Opc = AArch64::LD1Fourv2d;
6194 else if (Ty ==
S64 || Ty == P0)
6195 Opc = AArch64::LD1Fourv1d;
6198 selectVectorLoadIntrinsic(
Opc, 4,
I);
6201 case Intrinsic::aarch64_neon_ld2: {
6205 Opc = AArch64::LD2Twov8b;
6207 Opc = AArch64::LD2Twov16b;
6209 Opc = AArch64::LD2Twov4h;
6211 Opc = AArch64::LD2Twov8h;
6213 Opc = AArch64::LD2Twov2s;
6215 Opc = AArch64::LD2Twov4s;
6217 Opc = AArch64::LD2Twov2d;
6218 else if (Ty ==
S64 || Ty == P0)
6219 Opc = AArch64::LD1Twov1d;
6222 selectVectorLoadIntrinsic(
Opc, 2,
I);
6225 case Intrinsic::aarch64_neon_ld2lane: {
6229 Opc = AArch64::LD2i8;
6231 Opc = AArch64::LD2i16;
6233 Opc = AArch64::LD2i32;
6236 Opc = AArch64::LD2i64;
6239 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6243 case Intrinsic::aarch64_neon_ld2r: {
6247 Opc = AArch64::LD2Rv8b;
6249 Opc = AArch64::LD2Rv16b;
6251 Opc = AArch64::LD2Rv4h;
6253 Opc = AArch64::LD2Rv8h;
6255 Opc = AArch64::LD2Rv2s;
6257 Opc = AArch64::LD2Rv4s;
6259 Opc = AArch64::LD2Rv2d;
6260 else if (Ty ==
S64 || Ty == P0)
6261 Opc = AArch64::LD2Rv1d;
6264 selectVectorLoadIntrinsic(
Opc, 2,
I);
6267 case Intrinsic::aarch64_neon_ld3: {
6271 Opc = AArch64::LD3Threev8b;
6273 Opc = AArch64::LD3Threev16b;
6275 Opc = AArch64::LD3Threev4h;
6277 Opc = AArch64::LD3Threev8h;
6279 Opc = AArch64::LD3Threev2s;
6281 Opc = AArch64::LD3Threev4s;
6283 Opc = AArch64::LD3Threev2d;
6284 else if (Ty ==
S64 || Ty == P0)
6285 Opc = AArch64::LD1Threev1d;
6288 selectVectorLoadIntrinsic(
Opc, 3,
I);
6291 case Intrinsic::aarch64_neon_ld3lane: {
6295 Opc = AArch64::LD3i8;
6297 Opc = AArch64::LD3i16;
6299 Opc = AArch64::LD3i32;
6302 Opc = AArch64::LD3i64;
6305 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6309 case Intrinsic::aarch64_neon_ld3r: {
6313 Opc = AArch64::LD3Rv8b;
6315 Opc = AArch64::LD3Rv16b;
6317 Opc = AArch64::LD3Rv4h;
6319 Opc = AArch64::LD3Rv8h;
6321 Opc = AArch64::LD3Rv2s;
6323 Opc = AArch64::LD3Rv4s;
6325 Opc = AArch64::LD3Rv2d;
6326 else if (Ty ==
S64 || Ty == P0)
6327 Opc = AArch64::LD3Rv1d;
6330 selectVectorLoadIntrinsic(
Opc, 3,
I);
6333 case Intrinsic::aarch64_neon_ld4: {
6337 Opc = AArch64::LD4Fourv8b;
6339 Opc = AArch64::LD4Fourv16b;
6341 Opc = AArch64::LD4Fourv4h;
6343 Opc = AArch64::LD4Fourv8h;
6345 Opc = AArch64::LD4Fourv2s;
6347 Opc = AArch64::LD4Fourv4s;
6349 Opc = AArch64::LD4Fourv2d;
6350 else if (Ty ==
S64 || Ty == P0)
6351 Opc = AArch64::LD1Fourv1d;
6354 selectVectorLoadIntrinsic(
Opc, 4,
I);
6357 case Intrinsic::aarch64_neon_ld4lane: {
6361 Opc = AArch64::LD4i8;
6363 Opc = AArch64::LD4i16;
6365 Opc = AArch64::LD4i32;
6368 Opc = AArch64::LD4i64;
6371 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6375 case Intrinsic::aarch64_neon_ld4r: {
6379 Opc = AArch64::LD4Rv8b;
6381 Opc = AArch64::LD4Rv16b;
6383 Opc = AArch64::LD4Rv4h;
6385 Opc = AArch64::LD4Rv8h;
6387 Opc = AArch64::LD4Rv2s;
6389 Opc = AArch64::LD4Rv4s;
6391 Opc = AArch64::LD4Rv2d;
6392 else if (Ty ==
S64 || Ty == P0)
6393 Opc = AArch64::LD4Rv1d;
6396 selectVectorLoadIntrinsic(
Opc, 4,
I);
6399 case Intrinsic::aarch64_neon_st1x2: {
6403 Opc = AArch64::ST1Twov8b;
6405 Opc = AArch64::ST1Twov16b;
6407 Opc = AArch64::ST1Twov4h;
6409 Opc = AArch64::ST1Twov8h;
6411 Opc = AArch64::ST1Twov2s;
6413 Opc = AArch64::ST1Twov4s;
6415 Opc = AArch64::ST1Twov2d;
6416 else if (Ty ==
S64 || Ty == P0)
6417 Opc = AArch64::ST1Twov1d;
6420 selectVectorStoreIntrinsic(
I, 2,
Opc);
6423 case Intrinsic::aarch64_neon_st1x3: {
6427 Opc = AArch64::ST1Threev8b;
6429 Opc = AArch64::ST1Threev16b;
6431 Opc = AArch64::ST1Threev4h;
6433 Opc = AArch64::ST1Threev8h;
6435 Opc = AArch64::ST1Threev2s;
6437 Opc = AArch64::ST1Threev4s;
6439 Opc = AArch64::ST1Threev2d;
6440 else if (Ty ==
S64 || Ty == P0)
6441 Opc = AArch64::ST1Threev1d;
6444 selectVectorStoreIntrinsic(
I, 3,
Opc);
6447 case Intrinsic::aarch64_neon_st1x4: {
6451 Opc = AArch64::ST1Fourv8b;
6453 Opc = AArch64::ST1Fourv16b;
6455 Opc = AArch64::ST1Fourv4h;
6457 Opc = AArch64::ST1Fourv8h;
6459 Opc = AArch64::ST1Fourv2s;
6461 Opc = AArch64::ST1Fourv4s;
6463 Opc = AArch64::ST1Fourv2d;
6464 else if (Ty ==
S64 || Ty == P0)
6465 Opc = AArch64::ST1Fourv1d;
6468 selectVectorStoreIntrinsic(
I, 4,
Opc);
6471 case Intrinsic::aarch64_neon_st2: {
6475 Opc = AArch64::ST2Twov8b;
6477 Opc = AArch64::ST2Twov16b;
6479 Opc = AArch64::ST2Twov4h;
6481 Opc = AArch64::ST2Twov8h;
6483 Opc = AArch64::ST2Twov2s;
6485 Opc = AArch64::ST2Twov4s;
6487 Opc = AArch64::ST2Twov2d;
6488 else if (Ty ==
S64 || Ty == P0)
6489 Opc = AArch64::ST1Twov1d;
6492 selectVectorStoreIntrinsic(
I, 2,
Opc);
6495 case Intrinsic::aarch64_neon_st3: {
6499 Opc = AArch64::ST3Threev8b;
6501 Opc = AArch64::ST3Threev16b;
6503 Opc = AArch64::ST3Threev4h;
6505 Opc = AArch64::ST3Threev8h;
6507 Opc = AArch64::ST3Threev2s;
6509 Opc = AArch64::ST3Threev4s;
6511 Opc = AArch64::ST3Threev2d;
6512 else if (Ty ==
S64 || Ty == P0)
6513 Opc = AArch64::ST1Threev1d;
6516 selectVectorStoreIntrinsic(
I, 3,
Opc);
6519 case Intrinsic::aarch64_neon_st4: {
6523 Opc = AArch64::ST4Fourv8b;
6525 Opc = AArch64::ST4Fourv16b;
6527 Opc = AArch64::ST4Fourv4h;
6529 Opc = AArch64::ST4Fourv8h;
6531 Opc = AArch64::ST4Fourv2s;
6533 Opc = AArch64::ST4Fourv4s;
6535 Opc = AArch64::ST4Fourv2d;
6536 else if (Ty ==
S64 || Ty == P0)
6537 Opc = AArch64::ST1Fourv1d;
6540 selectVectorStoreIntrinsic(
I, 4,
Opc);
6543 case Intrinsic::aarch64_neon_st2lane: {
6547 Opc = AArch64::ST2i8;
6549 Opc = AArch64::ST2i16;
6551 Opc = AArch64::ST2i32;
6554 Opc = AArch64::ST2i64;
6557 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6561 case Intrinsic::aarch64_neon_st3lane: {
6565 Opc = AArch64::ST3i8;
6567 Opc = AArch64::ST3i16;
6569 Opc = AArch64::ST3i32;
6572 Opc = AArch64::ST3i64;
6575 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6579 case Intrinsic::aarch64_neon_st4lane: {
6583 Opc = AArch64::ST4i8;
6585 Opc = AArch64::ST4i16;
6587 Opc = AArch64::ST4i32;
6590 Opc = AArch64::ST4i64;
6593 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6597 case Intrinsic::aarch64_mops_memset_tag: {
6610 Register DstDef =
I.getOperand(0).getReg();
6612 Register DstUse =
I.getOperand(2).getReg();
6613 Register ValUse =
I.getOperand(3).getReg();
6614 Register SizeUse =
I.getOperand(4).getReg();
6621 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6622 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6628 case Intrinsic::ptrauth_resign_load_relative: {
6629 Register DstReg =
I.getOperand(0).getReg();
6630 Register ValReg =
I.getOperand(2).getReg();
6631 uint64_t AUTKey =
I.getOperand(3).getImm();
6632 Register AUTDisc =
I.getOperand(4).getReg();
6633 uint64_t PACKey =
I.getOperand(5).getImm();
6634 Register PACDisc =
I.getOperand(6).getReg();
6635 int64_t Addend =
I.getOperand(7).getImm();
6638 uint16_t AUTConstDiscC = 0;
6639 std::tie(AUTConstDiscC, AUTAddrDisc) =
6643 uint16_t PACConstDiscC = 0;
6644 std::tie(PACConstDiscC, PACAddrDisc) =
6647 MIB.
buildCopy({AArch64::X16}, {ValReg});
6663 I.eraseFromParent();
6668 I.eraseFromParent();
6672bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6673 MachineRegisterInfo &
MRI) {
6679 case Intrinsic::ptrauth_resign: {
6680 Register DstReg =
I.getOperand(0).getReg();
6681 Register ValReg =
I.getOperand(2).getReg();
6682 uint64_t AUTKey =
I.getOperand(3).getImm();
6683 Register AUTDisc =
I.getOperand(4).getReg();
6684 uint64_t PACKey =
I.getOperand(5).getImm();
6685 Register PACDisc =
I.getOperand(6).getReg();
6688 uint16_t AUTConstDiscC = 0;
6689 std::tie(AUTConstDiscC, AUTAddrDisc) =
6693 uint16_t PACConstDiscC = 0;
6694 std::tie(PACConstDiscC, PACAddrDisc) =
6697 MIB.
buildCopy({AArch64::X16}, {ValReg});
6711 I.eraseFromParent();
6714 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6715 Register DstReg =
I.getOperand(0).getReg();
6716 Register ValReg =
I.getOperand(2).getReg();
6717 uint64_t AUTKey =
I.getOperand(3).getImm();
6718 Register AUTDisc =
I.getOperand(4).getReg();
6719 Register AUTPC =
I.getOperand(5).getReg();
6720 uint64_t PACKey =
I.getOperand(6).getImm();
6721 Register PACDisc =
I.getOperand(7).getReg();
6724 "auth_with_pc_and_resign only supports IA and IB keys");
6726 uint16_t PACConstDiscC = 0;
6728 std::tie(PACConstDiscC, PACAddrDisc) =
6732 PACAddrDisc = AArch64::XZR;
6734 MIB.
buildCopy({AArch64::X17}, {ValReg});
6735 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6750 I.eraseFromParent();
6753 case Intrinsic::ptrauth_auth: {
6754 Register DstReg =
I.getOperand(0).getReg();
6755 Register ValReg =
I.getOperand(2).getReg();
6756 uint64_t AUTKey =
I.getOperand(3).getImm();
6757 Register AUTDisc =
I.getOperand(4).getReg();
6760 uint16_t AUTConstDiscC = 0;
6761 std::tie(AUTConstDiscC, AUTAddrDisc) =
6765 MIB.
buildCopy({AArch64::X16}, {ValReg});
6785 Auth.constrainAllUses(
TII,
TRI, RBI);
6789 I.eraseFromParent();
6792 case Intrinsic::frameaddress:
6793 case Intrinsic::returnaddress: {
6797 unsigned Depth =
I.getOperand(2).getImm();
6798 Register DstReg =
I.getOperand(0).getReg();
6801 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6802 if (!MFReturnAddr) {
6807 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6810 if (STI.hasPAuth()) {
6811 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6818 I.eraseFromParent();
6827 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6829 FrameAddr = NextFrame;
6832 if (IntrinID == Intrinsic::frameaddress)
6837 if (STI.hasPAuth()) {
6839 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6840 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6849 I.eraseFromParent();
6852 case Intrinsic::aarch64_neon_tbl2:
6853 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6855 case Intrinsic::aarch64_neon_tbl3:
6856 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6859 case Intrinsic::aarch64_neon_tbl4:
6860 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6862 case Intrinsic::aarch64_neon_tbx2:
6863 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6865 case Intrinsic::aarch64_neon_tbx3:
6866 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6868 case Intrinsic::aarch64_neon_tbx4:
6869 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6871 case Intrinsic::swift_async_context_addr:
6872 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6879 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6880 I.eraseFromParent();
6915bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6916 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6917 Register DefReg =
I.getOperand(0).getReg();
6918 Register Addr =
I.getOperand(1).getReg();
6920 Register AddrDisc =
I.getOperand(3).getReg();
6921 uint64_t Disc =
I.getOperand(4).getImm();
6931 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6947 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6959 const GlobalValue *GV;
6970 MachineIRBuilder MIB(
I);
6976 "unsupported non-GOT op flags on ptrauth global reference");
6978 "unsupported non-GOT reference to weak ptrauth global");
6981 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6988 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6991 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6996 I.eraseFromParent();
7008 "unsupported non-zero offset in weak ptrauth global reference");
7013 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7014 .addGlobalAddress(GV,
Offset)
7019 I.eraseFromParent();
7023void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7024 MachineRegisterInfo &
MRI,
7025 unsigned NumVec,
unsigned Opc1,
7026 unsigned Opc2,
bool isExt) {
7027 Register DstReg =
I.getOperand(0).getReg();
7032 for (
unsigned i = 0; i < NumVec; i++)
7033 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7036 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7037 MachineInstrBuilder
Instr;
7044 I.eraseFromParent();
7047InstructionSelector::ComplexRendererFns
7048AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7050 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7051 return std::nullopt;
7052 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7053 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7056InstructionSelector::ComplexRendererFns
7057AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7059 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7060 return std::nullopt;
7062 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7065InstructionSelector::ComplexRendererFns
7066AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7068 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7069 return std::nullopt;
7070 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7071 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7074InstructionSelector::ComplexRendererFns
7075AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7077 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7078 return std::nullopt;
7080 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7083template <
unsigned ShiftW
idth>
7084InstructionSelector::ComplexRendererFns
7085AArch64InstructionSelector::selectShiftMask(MachineOperand &Root)
const {
7087 return std::nullopt;
7089 MachineRegisterInfo &
MRI =
7096 if (ShiftWidth == 32) {
7099 ShAmtReg = ZExtSrcReg;
7108 ShAmtReg = AndSrcReg;
7120 (AddImm % ShiftWidth == 0)) {
7121 ShAmtReg = AddSrcReg;
7122 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7131 SubImm != 0 && (SubImm % ShiftWidth == 0)) {
7132 return {{[=](MachineInstrBuilder &MIB) {
7133 MachineInstr *
I = MIB.getInstr();
7136 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7137 unsigned SubOpc = ShiftWidth == 32 ? AArch64::SUBWrr : AArch64::SUBXrr;
7138 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7140 auto NegMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7141 TII.get(SubOpc), NegReg)
7155 (NotImm % ShiftWidth == ShiftWidth - 1)) {
7156 return {{[=](MachineInstrBuilder &MIB) {
7157 MachineInstr *
I = MIB.getInstr();
7160 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7161 unsigned NotOpc = ShiftWidth == 32 ? AArch64::ORNWrr : AArch64::ORNXrr;
7162 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7164 auto NotMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7165 TII.get(NotOpc), NotReg)
7175 if (ShAmtReg == Root.
getReg())
7176 return std::nullopt;
7178 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7186InstructionSelector::ComplexRendererFns
7187AArch64InstructionSelector::select12BitValueWithLeftShift(
7190 if (Immed >> 12 == 0) {
7192 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7194 Immed = Immed >> 12;
7196 return std::nullopt;
7200 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7201 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7208InstructionSelector::ComplexRendererFns
7209AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7216 if (MaybeImmed == std::nullopt)
7217 return std::nullopt;
7218 return select12BitValueWithLeftShift(*MaybeImmed);
7223InstructionSelector::ComplexRendererFns
7224AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7228 return std::nullopt;
7230 if (MaybeImmed == std::nullopt)
7231 return std::nullopt;
7238 return std::nullopt;
7244 Immed = ~((uint32_t)Immed) + 1;
7246 Immed = ~Immed + 1ULL;
7248 if (Immed & 0xFFFFFFFFFF000000ULL)
7249 return std::nullopt;
7251 Immed &= 0xFFFFFFULL;
7252 return select12BitValueWithLeftShift(Immed);
7269std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7270 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7271 if (
MI.getOpcode() == AArch64::G_SHL) {
7275 MI.getOperand(2).getReg(),
MRI)) {
7276 const APInt ShiftVal = ValAndVeg->Value;
7279 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7282 return std::nullopt;
7290bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7291 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7292 bool IsAddrOperand)
const {
7297 MI.getParent()->getParent()->getFunction().hasOptSize())
7300 if (IsAddrOperand) {
7302 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7306 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7307 MachineInstr *OffsetInst =
7313 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7324 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7327InstructionSelector::ComplexRendererFns
7328AArch64InstructionSelector::selectExtendedSHL(
7329 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7330 unsigned SizeInBytes,
bool WantsExt)
const {
7331 assert(
Base.isReg() &&
"Expected base to be a register operand");
7332 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7337 unsigned OffsetOpc = OffsetInst->
getOpcode();
7338 bool LookedThroughZExt =
false;
7339 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7341 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7342 return std::nullopt;
7346 LookedThroughZExt =
true;
7348 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7349 return std::nullopt;
7352 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7353 if (LegalShiftVal == 0)
7354 return std::nullopt;
7355 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7356 return std::nullopt;
7367 if (OffsetOpc == TargetOpcode::G_SHL)
7368 return std::nullopt;
7374 return std::nullopt;
7379 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7383 if (OffsetOpc == TargetOpcode::G_MUL) {
7385 return std::nullopt;
7391 if ((ImmVal & 0x7) != ImmVal)
7392 return std::nullopt;
7396 if (ImmVal != LegalShiftVal)
7397 return std::nullopt;
7399 unsigned SignExtend = 0;
7403 if (!LookedThroughZExt) {
7405 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7407 return std::nullopt;
7412 return std::nullopt;
7418 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7423 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7424 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7425 [=](MachineInstrBuilder &MIB) {
7428 MIB.addImm(SignExtend);
7441InstructionSelector::ComplexRendererFns
7442AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7443 MachineOperand &Root,
unsigned SizeInBytes)
const {
7445 return std::nullopt;
7460 MachineInstr *PtrAdd =
7462 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7463 return std::nullopt;
7467 MachineInstr *OffsetInst =
7469 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7482InstructionSelector::ComplexRendererFns
7483AArch64InstructionSelector::selectAddrModeRegisterOffset(
7484 MachineOperand &Root)
const {
7490 return std::nullopt;
7496 return std::nullopt;
7499 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7500 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7501 [=](MachineInstrBuilder &MIB) {
7511InstructionSelector::ComplexRendererFns
7512AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7513 unsigned SizeInBytes)
const {
7516 return std::nullopt;
7517 MachineInstr *PtrAdd =
7520 return std::nullopt;
7538 unsigned Scale =
Log2_32(SizeInBytes);
7539 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7543 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7544 ImmOff < (0x1000 << Scale))
7545 return std::nullopt;
7550 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7554 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7560 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7561 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7566 return std::nullopt;
7570 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7576 return selectAddrModeRegisterOffset(Root);
7585InstructionSelector::ComplexRendererFns
7586AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7587 unsigned SizeInBytes)
const {
7590 MachineInstr *PtrAdd =
7592 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7593 return std::nullopt;
7614 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7623 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7624 return std::nullopt;
7628 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7630 return std::nullopt;
7633 MachineIRBuilder MIB(*PtrAdd);
7635 AArch64::GPR32RegClass, MIB);
7639 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7640 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7641 [=](MachineInstrBuilder &MIB) {
7642 MIB.addImm(SignExtend);
7652InstructionSelector::ComplexRendererFns
7653AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7654 unsigned Size)
const {
7655 MachineRegisterInfo &
MRI =
7659 return std::nullopt;
7661 if (!isBaseWithConstantOffset(Root,
MRI))
7662 return std::nullopt;
7666 MachineOperand &OffImm = RootDef->
getOperand(2);
7667 if (!OffImm.
isReg())
7668 return std::nullopt;
7670 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7671 return std::nullopt;
7673 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7675 return std::nullopt;
7678 if (RHSC >= -256 && RHSC < 256) {
7681 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7682 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7685 return std::nullopt;
7688InstructionSelector::ComplexRendererFns
7689AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7691 MachineRegisterInfo &
MRI)
const {
7692 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7693 return std::nullopt;
7696 return std::nullopt;
7701 return std::nullopt;
7705 return std::nullopt;
7709 return std::nullopt;
7712 MachineIRBuilder MIRBuilder(RootDef);
7714 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7715 [=](MachineInstrBuilder &MIB) {
7716 MIB.addGlobalAddress(GV,
Offset,
7725InstructionSelector::ComplexRendererFns
7726AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7727 unsigned Size)
const {
7732 return std::nullopt;
7735 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7737 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7738 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7746 MachineInstr *RootParent = Root.
getParent();
7748 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7750 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7755 if (isBaseWithConstantOffset(Root,
MRI)) {
7763 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7764 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7766 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7767 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7771 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7772 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7779 if (selectAddrModeUnscaled(Root,
Size))
7780 return std::nullopt;
7783 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7784 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7791 switch (
MI.getOpcode()) {
7794 case TargetOpcode::G_SHL:
7796 case TargetOpcode::G_LSHR:
7798 case TargetOpcode::G_ASHR:
7800 case TargetOpcode::G_ROTR:
7807InstructionSelector::ComplexRendererFns
7808AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7809 bool AllowROR)
const {
7811 return std::nullopt;
7812 MachineRegisterInfo &
MRI =
7820 return std::nullopt;
7822 return std::nullopt;
7823 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7824 return std::nullopt;
7827 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7830 return std::nullopt;
7834 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7838 unsigned Val = *Immed & (NumBits - 1);
7841 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7842 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7846 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7847 unsigned Opc =
MI.getOpcode();
7850 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7852 if (
Opc == TargetOpcode::G_SEXT)
7855 Size =
MI.getOperand(2).getImm();
7856 assert(
Size != 64 &&
"Extend from 64 bits?");
7869 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7871 assert(
Size != 64 &&
"Extend from 64 bits?");
7886 if (
Opc != TargetOpcode::G_AND)
7905Register AArch64InstructionSelector::moveScalarRegClass(
7907 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7917 return Copy.getReg(0);
7922InstructionSelector::ComplexRendererFns
7923AArch64InstructionSelector::selectArithExtendedRegister(
7924 MachineOperand &Root)
const {
7926 return std::nullopt;
7927 MachineRegisterInfo &
MRI =
7935 return std::nullopt;
7937 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7938 return std::nullopt;
7941 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7946 return std::nullopt;
7947 ShiftVal = *MaybeShiftVal;
7949 return std::nullopt;
7954 return std::nullopt;
7955 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7957 return std::nullopt;
7961 Ext = getExtendTypeForInst(*RootDef,
MRI);
7963 return std::nullopt;
7972 if (isDef32(*ExtInst))
7973 return std::nullopt;
7979 MachineIRBuilder MIB(*RootDef);
7980 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7982 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7983 [=](MachineInstrBuilder &MIB) {
7984 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7988InstructionSelector::ComplexRendererFns
7989AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7991 return std::nullopt;
7992 MachineRegisterInfo &
MRI =
7996 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
8001 return std::nullopt;
8004 if (Unmerge->getNumDefs() == 2 &&
8006 Register ExtReg = Unmerge->getSourceReg();
8007 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8011 LLT SrcTy =
MRI.
getType(ExtElt->getVectorReg());
8015 LaneIdx->Value.getSExtValue() == 1) {
8016 Register ExtReg = ExtElt->getVectorReg();
8017 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8021 LLT SrcTy =
MRI.
getType(Subvec->getSrcVec());
8022 auto LaneIdx = Subvec->getIndexImm();
8024 Register ExtReg = Subvec->getSrcVec();
8025 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8029 return std::nullopt;
8032InstructionSelector::ComplexRendererFns
8033AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
8034 unsigned DstElemWidth,
8035 bool isReciprocal)
const {
8037 return std::nullopt;
8038 const MachineRegisterInfo &
MRI =
8044 if (Dup && Dup->
getOpcode() == TargetOpcode::G_SPLAT_VECTOR)
8047 std::optional<ValueAndVReg> CstVal =
8051 return std::nullopt;
8055 switch (CstElemWidth) {
8057 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value.trunc(CstElemWidth));
8060 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8063 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8066 return std::nullopt;
8068 if (
unsigned FBits =
8070 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8072 return std::nullopt;
8075unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8076 const MachineOperand &Root)
const {
8084template <
unsigned W
idth>
8085InstructionSelector::ComplexRendererFns
8086AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8087 return selectCVTFixedPointBase(Root, Width,
false);
8090template <
unsigned W
idth>
8091InstructionSelector::ComplexRendererFns
8092AArch64InstructionSelector::selectCVTFixedPosRecipOperand(
8093 MachineOperand &Root)
const {
8094 return selectCVTFixedPointBase(Root, Width,
true);
8097InstructionSelector::ComplexRendererFns
8098AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8099 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8103InstructionSelector::ComplexRendererFns
8104AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8105 MachineOperand &Root)
const {
8106 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8110void AArch64InstructionSelector::renderFixedPointScalarXForm(
8111 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8112 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8113 "Expected vecshift immediate operand");
8114 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8117void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8118 const MachineOperand &Root,
8120 bool isReciprocal)
const {
8124 InstructionSelector::ComplexRendererFns Renderer =
8125 selectCVTFixedPointBase(Root, Width, isReciprocal);
8126 assert((Renderer && Renderer->size() == 1) &&
8127 "Expected selectCVTFixedPointBase to provide a function\n");
8128 (Renderer->front())(MIB);
8131void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8132 const MachineInstr &
MI,
8134 const MachineOperand &Root =
MI.getOperand(OpIdx);
8135 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8139void AArch64InstructionSelector::renderFixedPointRecipXForm(
8140 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8141 const MachineOperand &Root =
MI.getOperand(OpIdx);
8142 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8146void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8147 const MachineInstr &
MI,
8149 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
8150 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8151 "Expected G_CONSTANT");
8152 std::optional<int64_t> CstVal =
8154 assert(CstVal &&
"Expected constant value");
8158void AArch64InstructionSelector::renderLogicalImm32(
8159 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8160 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8161 "Expected G_CONSTANT");
8162 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8167void AArch64InstructionSelector::renderLogicalImm64(
8168 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8169 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8170 "Expected G_CONSTANT");
8171 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8176void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8177 const MachineInstr &
MI,
8179 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8180 "Expected G_UBSANTRAP");
8181 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8184void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8185 const MachineInstr &
MI,
8187 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8188 "Expected G_FCONSTANT");
8193void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8194 const MachineInstr &
MI,
8196 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8197 "Expected G_FCONSTANT");
8202void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8203 const MachineInstr &
MI,
8205 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8206 "Expected G_FCONSTANT");
8211void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8212 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8213 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8214 "Expected G_FCONSTANT");
8222bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8223 const MachineInstr &
MI,
unsigned NumBytes)
const {
8224 if (!
MI.mayLoadOrStore())
8227 "Expected load/store to have only one mem op!");
8228 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8231bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8232 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
8240 switch (
MI.getOpcode()) {
8243 case TargetOpcode::COPY:
8244 case TargetOpcode::G_BITCAST:
8245 case TargetOpcode::G_TRUNC:
8246 case TargetOpcode::G_PHI:
8256 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8259 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8270 auto *OpDef =
MRI.getVRegDef(OpReg);
8271 const LLT &Ty =
MRI.getType(OpReg);
8277 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8281 MRI.setRegBank(Copy.getReg(0), *DstRB);
8282 MO.setReg(Copy.getReg(0));
8291 for (
auto &BB : MF) {
8292 for (
auto &
MI : BB) {
8293 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8298 for (
auto *
MI : Phis) {
8320 bool HasGPROp =
false, HasFPROp =
false;
8334 if (RB->
getID() == AArch64::GPRRegBankID)
8340 if (HasGPROp && HasFPROp)
8346InstructionSelector *
8350 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.