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();
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 * {
2437 MachineInstr *
Cmp = MatchCmp(AddRHS);
2441 Cmp = MatchCmp(AddRHS);
2445 auto &PredOp =
Cmp->getOperand(1);
2447 emitIntegerCompare(
Cmp->getOperand(2),
2448 Cmp->getOperand(3), PredOp, MIB);
2452 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2453 I.eraseFromParent();
2456 case TargetOpcode::G_OR: {
2460 Register Dst =
I.getOperand(0).getReg();
2480 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2483 int64_t Immr =
Size - ShiftImm;
2484 int64_t Imms =
Size - ShiftImm - 1;
2485 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2486 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2487 I.eraseFromParent();
2490 case TargetOpcode::G_FENCE: {
2491 if (
I.getOperand(1).getImm() == 0)
2495 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2496 I.eraseFromParent();
2499 case TargetOpcode::G_BRINDIRECT: {
2501 if (std::optional<uint16_t> BADisc =
2503 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2507 I.eraseFromParent();
2520bool AArch64InstructionSelector::select(MachineInstr &
I) {
2521 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2522 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2528 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2529 if (Subtarget->requiresStrictAlign()) {
2531 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2537 unsigned Opcode =
I.getOpcode();
2539 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2542 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2547 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2548 const Register DefReg =
I.getOperand(0).getReg();
2562 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2569 I.setDesc(
TII.get(TargetOpcode::PHI));
2581 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2583 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2590 if (preISelLower(
I)) {
2591 Opcode =
I.getOpcode();
2602 if (selectImpl(
I, *CoverageInfo))
2606 I.getOperand(0).isReg() ?
MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2609 case TargetOpcode::G_SBFX:
2610 case TargetOpcode::G_UBFX: {
2611 static const unsigned OpcTable[2][2] = {
2612 {AArch64::UBFMWri, AArch64::UBFMXri},
2613 {AArch64::SBFMWri, AArch64::SBFMXri}};
2614 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2616 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2619 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2622 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2623 auto LSB = Cst1->Value.getZExtValue();
2624 auto Width = Cst2->Value.getZExtValue();
2628 .
addImm(LSB + Width - 1);
2629 I.eraseFromParent();
2633 case TargetOpcode::G_BRCOND:
2634 return selectCompareBranch(
I, MF,
MRI);
2636 case TargetOpcode::G_BRJT:
2637 return selectBrJT(
I,
MRI);
2639 case AArch64::G_ADD_LOW: {
2645 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2646 I.setDesc(
TII.get(AArch64::ADDXri));
2652 "Expected small code model");
2654 auto Op2 =
I.getOperand(2);
2655 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2656 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2657 Op1.getTargetFlags())
2659 Op2.getTargetFlags());
2660 I.eraseFromParent();
2665 case TargetOpcode::G_FCONSTANT: {
2666 const Register DefReg =
I.getOperand(0).getReg();
2673 (DefSize == 16 || DefSize == 32 || DefSize == 64 || DefSize == 128) &&
2674 "Unexpected destination size for G_FCONSTANT?");
2677 const ConstantFP *FPImm =
I.getOperand(1).getFPImm();
2678 APInt
Imm = DefSize >= 64
2681 if (
auto *Mov = emitConstantMOVVector(
2682 DefSize >= 64 ? DstOp(DefReg) : DstOp(&AArch64::FPR64RegClass),
Imm,
2685 MIB.
buildInstr(TargetOpcode::COPY, {DefReg}, {})
2686 .addReg(Mov->getOperand(0).getReg(), {},
2687 DefSize == 16 ? AArch64::hsub : AArch64::ssub);
2690 I.eraseFromParent();
2696 bool OptForSize = shouldOptForSize(&MF);
2698 if ((DefSize == 32 || DefSize == 64) &&
2699 TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2703 DefSize == 64 ? &AArch64::GPR64RegClass : &AArch64::GPR32RegClass);
2704 MachineOperand &RegOp =
I.getOperand(0);
2710 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2714 MachineOperand &ImmOp =
I.getOperand(1);
2718 const unsigned MovOpc =
2719 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2720 I.setDesc(
TII.get(MovOpc));
2728 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2731 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2732 I.eraseFromParent();
2735 case TargetOpcode::G_EXTRACT: {
2736 Register DstReg =
I.getOperand(0).getReg();
2737 Register SrcReg =
I.getOperand(1).getReg();
2751 unsigned Offset =
I.getOperand(2).getImm();
2760 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2762 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2764 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2766 AArch64::GPR64RegClass, NewI->getOperand(0));
2767 I.eraseFromParent();
2773 unsigned LaneIdx =
Offset / 64;
2774 MachineInstr *Extract = emitExtractVectorElt(
2775 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2778 I.eraseFromParent();
2782 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2783 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2788 "unexpected G_EXTRACT types");
2795 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2796 .addReg(DstReg, {}, AArch64::sub_32);
2798 AArch64::GPR32RegClass,
MRI);
2799 I.getOperand(0).setReg(DstReg);
2805 case TargetOpcode::G_INSERT: {
2806 LLT SrcTy =
MRI.
getType(
I.getOperand(2).getReg());
2807 LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
2814 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2815 unsigned LSB =
I.getOperand(3).getImm();
2817 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2818 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2822 "unexpected G_INSERT types");
2829 TII.get(AArch64::SUBREG_TO_REG))
2831 .
addUse(
I.getOperand(2).getReg())
2832 .
addImm(AArch64::sub_32);
2834 AArch64::GPR32RegClass,
MRI);
2835 I.getOperand(2).setReg(SrcReg);
2840 case TargetOpcode::G_FRAME_INDEX: {
2847 I.setDesc(
TII.get(AArch64::ADDXri));
2857 case TargetOpcode::G_GLOBAL_VALUE: {
2858 const GlobalValue *GV =
nullptr;
2860 if (
I.getOperand(1).isSymbol()) {
2861 OpFlags =
I.getOperand(1).getTargetFlags();
2867 return selectTLSGlobalValue(
I,
MRI);
2873 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2874 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2875 I.getOperand(1).setTargetFlags(OpFlags);
2876 I.addImplicitDefUseOperands(MF);
2877 I.setImplicitPhysRegDefsDead();
2881 materializeLargeCMVal(
I, GV, OpFlags);
2882 I.eraseFromParent();
2885 I.setDesc(
TII.get(AArch64::ADR));
2886 I.getOperand(1).setTargetFlags(OpFlags);
2888 I.setDesc(
TII.get(AArch64::MOVaddr));
2890 MachineInstrBuilder MIB(MF,
I);
2891 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2898 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2899 return selectPtrAuthGlobalValue(
I,
MRI);
2901 case TargetOpcode::G_ZEXTLOAD:
2902 case TargetOpcode::G_LOAD:
2903 case TargetOpcode::G_STORE: {
2905 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2920 assert(MemSizeInBytes <= 8 &&
2921 "128-bit atomics should already be custom-legalized");
2924 static constexpr unsigned LDAPROpcodes[] = {
2925 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2926 static constexpr unsigned LDAROpcodes[] = {
2927 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2928 ArrayRef<unsigned> Opcodes =
2929 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2932 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2934 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2935 AArch64::STLRW, AArch64::STLRX};
2940 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2941 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2942 I.getOperand(0).setReg(NewVal);
2944 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2955 "Load/Store pointer operand isn't a GPR");
2957 "Load/Store pointer operand isn't a pointer");
2967 RB.
getID() == AArch64::FPRRegBankID) {
2970 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2976 .addReg(ValReg, {}, SubReg)
2983 if (RB.
getID() == AArch64::FPRRegBankID) {
2986 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2996 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
2999 auto SubRegRC = getRegClassForTypeOnBank(
MRI.
getType(OldDst), RB);
3008 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3010 const unsigned NewOpc =
3012 if (NewOpc ==
I.getOpcode())
3016 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3019 I.setDesc(
TII.get(NewOpc));
3025 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3026 Register CurValReg =
I.getOperand(0).getReg();
3027 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3028 NewInst.cloneMemRefs(
I);
3029 for (
auto &Fn : *AddrModeFns)
3031 I.eraseFromParent();
3035 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3040 if (Opcode == TargetOpcode::G_STORE) {
3043 if (CVal && CVal->Value == 0) {
3045 case AArch64::STRWui:
3046 case AArch64::STRHHui:
3047 case AArch64::STRBBui:
3048 LoadStore->getOperand(0).setReg(AArch64::WZR);
3050 case AArch64::STRXui:
3051 LoadStore->getOperand(0).setReg(AArch64::XZR);
3057 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3058 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3070 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3072 .
addImm(AArch64::sub_32);
3081 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3082 case TargetOpcode::G_INDEXED_SEXTLOAD:
3083 return selectIndexedExtLoad(
I,
MRI);
3084 case TargetOpcode::G_INDEXED_LOAD:
3085 return selectIndexedLoad(
I,
MRI);
3086 case TargetOpcode::G_INDEXED_STORE:
3089 case TargetOpcode::G_LSHR:
3090 case TargetOpcode::G_ASHR:
3092 return selectVectorAshrLshr(
I,
MRI);
3094 case TargetOpcode::G_SHL: {
3095 if (Opcode == TargetOpcode::G_SHL &&
3097 return selectVectorSHL(
I,
MRI);
3104 Register SrcReg =
I.getOperand(1).getReg();
3105 Register ShiftReg =
I.getOperand(2).getReg();
3112 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3113 .addReg(ShiftReg, {}, AArch64::sub_32);
3115 I.getOperand(2).setReg(Trunc.getReg(0));
3120 const Register DefReg =
I.getOperand(0).getReg();
3124 if (NewOpc ==
I.getOpcode())
3127 I.setDesc(
TII.get(NewOpc));
3135 case TargetOpcode::G_PTR_ADD: {
3136 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3137 I.eraseFromParent();
3141 case TargetOpcode::G_SADDE:
3142 case TargetOpcode::G_UADDE:
3143 case TargetOpcode::G_SSUBE:
3144 case TargetOpcode::G_USUBE:
3145 case TargetOpcode::G_SADDO:
3146 case TargetOpcode::G_UADDO:
3147 case TargetOpcode::G_SSUBO:
3148 case TargetOpcode::G_USUBO:
3149 return selectOverflowOp(
I,
MRI);
3151 case TargetOpcode::G_PTRMASK: {
3152 Register MaskReg =
I.getOperand(2).getReg();
3159 I.setDesc(
TII.get(AArch64::ANDXri));
3160 I.getOperand(2).ChangeToImmediate(
3166 case TargetOpcode::G_PTRTOINT:
3167 case TargetOpcode::G_TRUNC: {
3168 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3169 const LLT SrcTy =
MRI.
getType(
I.getOperand(1).getReg());
3171 const Register DstReg =
I.getOperand(0).getReg();
3172 const Register SrcReg =
I.getOperand(1).getReg();
3179 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3183 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3194 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3198 if (DstRC == SrcRC) {
3200 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3204 }
else if (DstRC == &AArch64::GPR32RegClass &&
3205 SrcRC == &AArch64::GPR64RegClass) {
3206 I.getOperand(1).setSubReg(AArch64::sub_32);
3209 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3213 I.setDesc(
TII.get(TargetOpcode::COPY));
3215 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3218 I.setDesc(
TII.get(AArch64::XTNv4i16));
3224 MachineInstr *Extract = emitExtractVectorElt(
3228 I.eraseFromParent();
3233 if (Opcode == TargetOpcode::G_PTRTOINT) {
3234 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3235 I.setDesc(
TII.get(TargetOpcode::COPY));
3243 case TargetOpcode::G_ANYEXT: {
3244 if (selectUSMovFromExtend(
I,
MRI))
3247 const Register DstReg =
I.getOperand(0).getReg();
3248 const Register SrcReg =
I.getOperand(1).getReg();
3251 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3253 <<
", expected: GPR\n");
3258 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3260 <<
", expected: GPR\n");
3267 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3271 if (DstSize != 64 && DstSize > 32) {
3273 <<
", expected: 32 or 64\n");
3283 .
addImm(AArch64::sub_32);
3284 I.getOperand(1).setReg(ExtSrc);
3289 case TargetOpcode::G_ZEXT:
3290 case TargetOpcode::G_SEXT_INREG:
3291 case TargetOpcode::G_SEXT: {
3292 if (selectUSMovFromExtend(
I,
MRI))
3295 unsigned Opcode =
I.getOpcode();
3296 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3297 const Register DefReg =
I.getOperand(0).getReg();
3298 Register SrcReg =
I.getOperand(1).getReg();
3306 if (Opcode == TargetOpcode::G_SEXT_INREG)
3307 SrcSize =
I.getOperand(2).getImm();
3313 AArch64::GPRRegBankID &&
3314 "Unexpected ext regbank");
3328 if (LoadMI && IsGPR) {
3329 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3330 unsigned BytesLoaded = MemOp->getSize().getValue();
3337 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3340 const Register ZReg = AArch64::WZR;
3341 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3344 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3345 .addUse(SubregToRegSrc)
3346 .
addImm(AArch64::sub_32);
3350 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3360 I.eraseFromParent();
3365 if (DstSize == 64) {
3366 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3374 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3375 {&AArch64::GPR64RegClass}, {})
3381 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3385 }
else if (DstSize <= 32) {
3386 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3395 I.eraseFromParent();
3399 case TargetOpcode::G_FREEZE:
3402 case TargetOpcode::G_INTTOPTR:
3407 case TargetOpcode::G_BITCAST:
3415 case TargetOpcode::G_SELECT: {
3417 const Register CondReg = Sel.getCondReg();
3419 const Register FReg = Sel.getFalseReg();
3421 if (tryOptSelect(Sel))
3427 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3432 Sel.eraseFromParent();
3435 case TargetOpcode::G_ICMP: {
3445 auto &PredOp =
I.getOperand(1);
3446 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3450 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3451 AArch64::WZR, InvCC, MIB);
3452 I.eraseFromParent();
3456 case TargetOpcode::G_FCMP: {
3459 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3461 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3463 I.eraseFromParent();
3466 case TargetOpcode::G_VASTART:
3468 : selectVaStartAAPCS(
I, MF,
MRI);
3469 case TargetOpcode::G_INTRINSIC:
3470 return selectIntrinsic(
I,
MRI);
3471 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3472 return selectIntrinsicWithSideEffects(
I,
MRI);
3473 case TargetOpcode::G_IMPLICIT_DEF: {
3474 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3475 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3476 const Register DstReg =
I.getOperand(0).getReg();
3482 case TargetOpcode::G_BLOCK_ADDR: {
3483 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3484 if (std::optional<uint16_t> BADisc =
3494 AArch64::GPR64RegClass,
MRI);
3495 I.eraseFromParent();
3499 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3500 I.eraseFromParent();
3503 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3504 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3505 I.getOperand(0).getReg())
3509 I.getOperand(1).getBlockAddress(), 0,
3511 I.eraseFromParent();
3516 case TargetOpcode::G_BUILD_VECTOR:
3517 return selectBuildVector(
I,
MRI);
3518 case TargetOpcode::G_MERGE_VALUES:
3520 case TargetOpcode::G_UNMERGE_VALUES:
3522 case TargetOpcode::G_SHUFFLE_VECTOR:
3523 return selectShuffleVector(
I,
MRI);
3524 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3525 return selectExtractElt(
I,
MRI);
3526 case TargetOpcode::G_CONCAT_VECTORS:
3527 return selectConcatVectors(
I,
MRI);
3528 case TargetOpcode::G_JUMP_TABLE:
3529 return selectJumpTable(
I,
MRI);
3530 case TargetOpcode::G_MEMCPY:
3531 case TargetOpcode::G_MEMCPY_INLINE:
3532 case TargetOpcode::G_MEMMOVE:
3533 case TargetOpcode::G_MEMSET:
3534 case TargetOpcode::G_MEMSET_INLINE:
3535 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3536 return selectMOPS(
I,
MRI);
3542bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3543 MachineIRBuilderState OldMIBState = MIB.
getState();
3549bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3550 MachineRegisterInfo &
MRI) {
3553 case TargetOpcode::G_MEMCPY:
3554 case TargetOpcode::G_MEMCPY_INLINE:
3555 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3557 case TargetOpcode::G_MEMMOVE:
3558 Mopcode = AArch64::MOPSMemoryMovePseudo;
3560 case TargetOpcode::G_MEMSET:
3561 case TargetOpcode::G_MEMSET_INLINE:
3563 Mopcode = AArch64::MOPSMemorySetPseudo;
3576 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3577 const auto &SrcValRegClass =
3578 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3596 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3597 {DstPtrCopy, SizeCopy, SrcValCopy})
3601 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3602 {DstPtrCopy, SrcValCopy, SizeCopy})
3610bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3611 MachineRegisterInfo &
MRI) {
3612 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3613 Register JTAddr =
I.getOperand(0).getReg();
3614 unsigned JTI =
I.getOperand(1).getIndex();
3617 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3629 "jump table hardening only supported on MachO/ELF");
3637 I.eraseFromParent();
3644 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3645 {TargetReg, ScratchReg}, {JTAddr,
Index})
3646 .addJumpTableIndex(JTI);
3648 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3649 {
static_cast<int64_t
>(JTI)});
3651 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3652 I.eraseFromParent();
3657bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3658 MachineRegisterInfo &
MRI) {
3659 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3660 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3662 Register DstReg =
I.getOperand(0).getReg();
3663 unsigned JTI =
I.getOperand(1).getIndex();
3666 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3669 I.eraseFromParent();
3674bool AArch64InstructionSelector::selectTLSLocalExecELF(
3675 const GlobalValue *GV, MachineInstr &
I, MachineRegisterInfo &
MRI) {
3676 auto ConstrainRegOps = [&](MachineInstrBuilder MIB) {
3680 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {}));
3688 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()},
3699 MIB.
buildInstr(AArch64::ADDXri, {Addr}, {ThreadBase})
3703 MIB.
buildInstr(AArch64::ADDXri, {I.getOperand(0).getReg()}, {Addr})
3720 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3725 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3726 {ThreadBase, Addr2}));
3740 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr2}, {Addr})
3746 ConstrainRegOps(MIB.
buildInstr(AArch64::MOVKXi, {Addr3}, {Addr2})
3751 ConstrainRegOps(MIB.
buildInstr(AArch64::ADDXrr, {I.getOperand(0).getReg()},
3752 {ThreadBase, Addr3}));
3756 I.eraseFromParent();
3762bool AArch64InstructionSelector::selectTLSGlobalValueELF(
3763 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3764 const GlobalValue *GV =
I.
getOperand(1).getGlobal();
3765 auto *FuncInfo = MF->
getInfo<AArch64FunctionInfo>();
3772 return selectTLSLocalExecELF(GV,
I,
MRI);
3774 MIB.
buildInstr(AArch64::LOADgot, {TPOff}, {})
3780 SMEAttrs
Attrs = MF->
getInfo<AArch64FunctionInfo>()->getSMEFnAttrs();
3782 !
Attrs.hasStreamingCompatibleInterface() &&
3783 "unsupported SME features reached GlobalISel TLS lowering");
3786 ? AArch64::TLSDESC_AUTH_CALLSEQ
3787 : AArch64::TLSDESC_CALLSEQ;
3806 MIB.
buildInstr(AArch64::ADDXri, {TPOff}, {Add1.getReg(0)})
3807 .addGlobalAddress(GV, 0,
3816 MIB.
buildInstr(AArch64::MOVbaseTLS, {ThreadBase}, {});
3817 auto Add = MIB.
buildInstr(AArch64::ADDXrr, {
I.getOperand(0).getReg()},
3818 {ThreadBase, TPOff});
3821 I.eraseFromParent();
3825bool AArch64InstructionSelector::selectTLSGlobalValueMachO(
3826 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3827 const auto &GlobalOp =
I.getOperand(1);
3828 assert(GlobalOp.getOffset() == 0 &&
3829 "Shouldn't have an offset on TLS globals!");
3831 const GlobalValue &GV = *GlobalOp.getGlobal();
3834 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3837 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3838 {LoadGOT.getReg(0)})
3849 assert(Opcode == AArch64::BLR);
3850 Opcode = AArch64::BLRAAZ;
3855 .
addUse(AArch64::X0, RegState::Implicit)
3856 .
addDef(AArch64::X0, RegState::Implicit)
3862 I.eraseFromParent();
3866bool AArch64InstructionSelector::selectTLSGlobalValue(
3867 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3873 return selectTLSGlobalValueELF(
I,
MRI);
3876 return selectTLSGlobalValueMachO(
I,
MRI);
3881MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3883 MachineIRBuilder &MIRBuilder)
const {
3884 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3886 auto BuildFn = [&](
unsigned SubregIndex) {
3890 .addImm(SubregIndex);
3898 return BuildFn(AArch64::bsub);
3900 return BuildFn(AArch64::hsub);
3902 return BuildFn(AArch64::ssub);
3904 return BuildFn(AArch64::dsub);
3911AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3912 MachineIRBuilder &MIB,
3913 MachineRegisterInfo &
MRI)
const {
3917 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3921 unsigned SubReg = 0;
3924 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3930 .addReg(SrcReg, {}, SubReg);
3935bool AArch64InstructionSelector::selectMergeValues(
3936 MachineInstr &
I, MachineRegisterInfo &
MRI) {
3937 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3938 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
3939 const LLT SrcTy =
MRI.
getType(
I.getOperand(1).getReg());
3943 if (
I.getNumOperands() != 3)
3950 Register DstReg =
I.getOperand(0).getReg();
3951 Register Src1Reg =
I.getOperand(1).getReg();
3952 Register Src2Reg =
I.getOperand(2).getReg();
3953 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3954 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3958 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3959 Src2Reg, 1, RB, MIB);
3964 I.eraseFromParent();
3968 if (RB.
getID() != AArch64::GPRRegBankID)
3974 auto *DstRC = &AArch64::GPR64RegClass;
3976 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3977 TII.get(TargetOpcode::SUBREG_TO_REG))
3979 .
addUse(
I.getOperand(1).getReg())
3980 .
addImm(AArch64::sub_32);
3983 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3984 TII.get(TargetOpcode::SUBREG_TO_REG))
3986 .
addUse(
I.getOperand(2).getReg())
3987 .
addImm(AArch64::sub_32);
3989 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3990 .
addDef(
I.getOperand(0).getReg())
3998 I.eraseFromParent();
4003 const unsigned EltSize) {
4008 CopyOpc = AArch64::DUPi8;
4009 ExtractSubReg = AArch64::bsub;
4012 CopyOpc = AArch64::DUPi16;
4013 ExtractSubReg = AArch64::hsub;
4016 CopyOpc = AArch64::DUPi32;
4017 ExtractSubReg = AArch64::ssub;
4020 CopyOpc = AArch64::DUPi64;
4021 ExtractSubReg = AArch64::dsub;
4025 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
4031MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
4032 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
4033 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
4034 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4035 unsigned CopyOpc = 0;
4036 unsigned ExtractSubReg = 0;
4039 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
4044 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
4046 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
4053 getRegClassForTypeOnBank(VecTy, VecRB,
true);
4055 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4065 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4066 .addReg(VecReg, {}, ExtractSubReg);
4075 MachineInstr *ScalarToVector = emitScalarToVector(
4076 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4077 if (!ScalarToVector)
4082 MachineInstr *LaneCopyMI =
4083 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4091bool AArch64InstructionSelector::selectExtractElt(
4092 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4093 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4094 "unexpected opcode!");
4095 Register DstReg =
I.getOperand(0).getReg();
4097 const Register SrcReg =
I.getOperand(1).getReg();
4100 "source register size too small!");
4101 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4104 MachineOperand &LaneIdxOp =
I.getOperand(2);
4105 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4111 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4114 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4118 Opcode = AArch64::UMOVvi8;
4121 Opcode = AArch64::UMOVvi16;
4124 Opcode = AArch64::UMOVvi32;
4131 MachineInstr *ScalarToVector = emitScalarToVector(
4132 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4133 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4137 I.setDesc(
TII.get(Opcode));
4138 I.getOperand(2).ChangeToImmediate(LaneIdx);
4143 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4148 I.eraseFromParent();
4152bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4153 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4154 unsigned NumElts =
I.getNumOperands() - 1;
4155 Register SrcReg =
I.getOperand(NumElts).getReg();
4156 const LLT NarrowTy =
MRI.
getType(
I.getOperand(0).getReg());
4159 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4161 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4167 const RegisterBank &DstRB =
4169 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4170 Register Dst =
I.getOperand(OpIdx).getReg();
4171 MachineInstr *Extract =
4172 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4176 I.eraseFromParent();
4180bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4181 MachineRegisterInfo &
MRI) {
4182 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4183 "unexpected opcode");
4187 unsigned NumElts =
I.getNumOperands() - 1;
4188 Register SrcReg =
I.getOperand(NumElts).getReg();
4189 Register LoReg =
I.getOperand(0).getReg();
4190 Register HiReg =
I.getOperand(1).getReg();
4199 LoRB.
getID() == AArch64::GPRRegBankID &&
4200 HiRB.
getID() == AArch64::GPRRegBankID &&
4201 SrcRB.
getID() == AArch64::FPRRegBankID) {
4202 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4203 TII.get(AArch64::UMOVvi64), LoReg)
4206 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4207 TII.get(AArch64::UMOVvi64), HiReg)
4212 I.eraseFromParent();
4217 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4218 HiRB.
getID() != AArch64::FPRRegBankID) {
4219 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4220 "currently unsupported.\n");
4225 "source register size too small!");
4228 return selectSplitVectorUnmerge(
I,
MRI);
4232 unsigned CopyOpc = 0;
4233 unsigned ExtractSubReg = 0;
4244 unsigned NumInsertRegs = NumElts - 1;
4250 InsertRegs.
assign(NumInsertRegs, SrcReg);
4259 unsigned SubReg = 0;
4262 assert(Found &&
"expected to find last operand's subeg idx");
4263 for (
unsigned Idx = 0;
Idx < NumInsertRegs; ++
Idx) {
4265 MachineInstr &ImpDefMI =
4266 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4271 MachineInstr &InsMI =
4273 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4290 Register CopyTo =
I.getOperand(0).getReg();
4291 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4292 .addReg(InsertRegs[0], {}, ExtractSubReg);
4296 unsigned LaneIdx = 1;
4297 for (
Register InsReg : InsertRegs) {
4298 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4299 MachineInstr &CopyInst =
4318 I.eraseFromParent();
4322bool AArch64InstructionSelector::selectConcatVectors(
4323 MachineInstr &
I, MachineRegisterInfo &
MRI) {
4324 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4325 "Unexpected opcode");
4326 Register Dst =
I.getOperand(0).getReg();
4327 Register Op1 =
I.getOperand(1).getReg();
4328 Register Op2 =
I.getOperand(2).getReg();
4329 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4332 I.eraseFromParent();
4337AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4346MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4347 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4354 RC = &AArch64::FPR128RegClass;
4355 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4358 RC = &AArch64::FPR64RegClass;
4359 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4362 RC = &AArch64::FPR32RegClass;
4363 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4366 RC = &AArch64::FPR16RegClass;
4367 Opc = AArch64::LDRHui;
4370 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4375 MachineInstr *LoadMI =
nullptr;
4376 auto &MF = MIRBuilder.
getMF();
4377 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4378 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4380 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4383 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4387 .addConstantPoolIndex(
4403static std::pair<unsigned, unsigned>
4405 unsigned Opc, SubregIdx;
4406 if (RB.
getID() == AArch64::GPRRegBankID) {
4408 Opc = AArch64::INSvi8gpr;
4409 SubregIdx = AArch64::bsub;
4410 }
else if (EltSize == 16) {
4411 Opc = AArch64::INSvi16gpr;
4412 SubregIdx = AArch64::ssub;
4413 }
else if (EltSize == 32) {
4414 Opc = AArch64::INSvi32gpr;
4415 SubregIdx = AArch64::ssub;
4416 }
else if (EltSize == 64) {
4417 Opc = AArch64::INSvi64gpr;
4418 SubregIdx = AArch64::dsub;
4424 Opc = AArch64::INSvi8lane;
4425 SubregIdx = AArch64::bsub;
4426 }
else if (EltSize == 16) {
4427 Opc = AArch64::INSvi16lane;
4428 SubregIdx = AArch64::hsub;
4429 }
else if (EltSize == 32) {
4430 Opc = AArch64::INSvi32lane;
4431 SubregIdx = AArch64::ssub;
4432 }
else if (EltSize == 64) {
4433 Opc = AArch64::INSvi64lane;
4434 SubregIdx = AArch64::dsub;
4439 return std::make_pair(
Opc, SubregIdx);
4442MachineInstr *AArch64InstructionSelector::emitInstr(
4443 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4444 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4445 const ComplexRendererFns &RenderFns)
const {
4446 assert(Opcode &&
"Expected an opcode?");
4448 "Function should only be used to produce selected instructions!");
4449 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4451 for (
auto &Fn : *RenderFns)
4457MachineInstr *AArch64InstructionSelector::emitAddSub(
4458 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4460 MachineIRBuilder &MIRBuilder)
const {
4462 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4466 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4467 bool Is32Bit =
Size == 32;
4470 if (
auto Fns = selectArithImmed(
RHS))
4471 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4475 if (
auto Fns = selectNegArithImmed(
RHS))
4476 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4480 if (
auto Fns = selectArithExtendedRegister(
RHS))
4481 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4485 if (
auto Fns = selectShiftedRegister(
RHS))
4486 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4488 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4493AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4494 MachineOperand &
RHS,
4495 MachineIRBuilder &MIRBuilder)
const {
4496 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4497 {{AArch64::ADDXri, AArch64::ADDWri},
4498 {AArch64::ADDXrs, AArch64::ADDWrs},
4499 {AArch64::ADDXrr, AArch64::ADDWrr},
4500 {AArch64::SUBXri, AArch64::SUBWri},
4501 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4502 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4506AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4507 MachineOperand &
RHS,
4508 MachineIRBuilder &MIRBuilder)
const {
4509 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4510 {{AArch64::ADDSXri, AArch64::ADDSWri},
4511 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4512 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4513 {AArch64::SUBSXri, AArch64::SUBSWri},
4514 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4515 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4519AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4520 MachineOperand &
RHS,
4521 MachineIRBuilder &MIRBuilder)
const {
4522 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4523 {{AArch64::SUBSXri, AArch64::SUBSWri},
4524 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4525 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4526 {AArch64::ADDSXri, AArch64::ADDSWri},
4527 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4528 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4532AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4533 MachineOperand &
RHS,
4534 MachineIRBuilder &MIRBuilder)
const {
4535 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4536 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4538 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4539 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4543AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4544 MachineOperand &
RHS,
4545 MachineIRBuilder &MIRBuilder)
const {
4546 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4547 MachineRegisterInfo *
MRI = MIRBuilder.
getMRI();
4549 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4550 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4554AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4555 MachineIRBuilder &MIRBuilder)
const {
4558 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4563AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4564 MachineIRBuilder &MIRBuilder)
const {
4567 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4572AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4573 MachineIRBuilder &MIRBuilder)
const {
4574 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4578 bool Is32Bit = (
RegSize == 32);
4579 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4580 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4581 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4585 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4588 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4595 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4596 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4597 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4600MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4601 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4602 MachineIRBuilder &MIRBuilder)
const {
4603 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4610 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4612 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4614 return emitCMP(
LHS,
RHS, MIRBuilder);
4617MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4619 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4623 "Expected a 32-bit scalar register?");
4625 const Register ZReg = AArch64::WZR;
4630 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4636 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4637 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4638 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4643MachineInstr *AArch64InstructionSelector::emitFPCompare(
4645 std::optional<CmpInst::Predicate> Pred)
const {
4646 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
4651 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4661 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4664 ShouldUseImm =
true;
4668 unsigned CmpOpcTbl[2][3] = {
4669 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4670 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4672 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4684MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4686 MachineIRBuilder &MIRBuilder)
const {
4696 if (Op1Ty != Op2Ty) {
4697 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4700 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4703 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4718 MachineInstr *WidenedOp1 =
4719 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4720 MachineInstr *WidenedOp2 =
4721 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4722 if (!WidenedOp1 || !WidenedOp2) {
4723 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4728 unsigned InsertOpc, InsSubRegIdx;
4729 std::tie(InsertOpc, InsSubRegIdx) =
4747 MachineIRBuilder &MIRBuilder)
const {
4754 Size =
TRI.getRegSizeInBits(*RC);
4758 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4759 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4760 unsigned Opc = OpcTable[
Size == 64];
4766MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4768 MachineRegisterInfo *
MRI = MIB.
getMRI();
4769 unsigned Opcode =
I.getOpcode();
4773 bool NeedsNegatedCarry =
4774 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4791 if (SrcMI == PrevMI) {
4793 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4794 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4795 CarrySrcMI->isUnsigned() &&
4796 CarrySrcMI->getCarryOutReg() == CarryReg &&
4797 selectAndRestoreState(*SrcMI))
4804 if (NeedsNegatedCarry) {
4807 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4811 auto Fns = select12BitValueWithLeftShift(1);
4812 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4815bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4816 MachineRegisterInfo &
MRI) {
4821 emitCarryIn(
I, CarryInMI->getCarryInReg());
4825 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4826 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4828 Register CarryOutReg = CarryMI.getCarryOutReg();
4832 OpAndCC.first->addRegisterDead(AArch64::NZCV, &
TRI);
4839 emitCSINC(CarryOutReg, ZReg, ZReg,
4840 getInvertedCondCode(OpAndCC.second), MIB);
4843 I.eraseFromParent();
4847std::pair<MachineInstr *, AArch64CC::CondCode>
4848AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4849 MachineOperand &
LHS,
4850 MachineOperand &
RHS,
4851 MachineIRBuilder &MIRBuilder)
const {
4855 case TargetOpcode::G_SADDO:
4857 case TargetOpcode::G_UADDO:
4859 case TargetOpcode::G_SSUBO:
4861 case TargetOpcode::G_USUBO:
4863 case TargetOpcode::G_SADDE:
4865 case TargetOpcode::G_UADDE:
4867 case TargetOpcode::G_SSUBE:
4869 case TargetOpcode::G_USUBE:
4890 unsigned Depth = 0) {
4891 if (!
MRI.hasOneNonDBGUse(Val))
4897 MustBeFirst =
false;
4903 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4904 bool IsOR = Opcode == TargetOpcode::G_OR;
4916 if (MustBeFirstL && MustBeFirstR)
4922 if (!CanNegateL && !CanNegateR)
4926 CanNegate = WillNegate && CanNegateL && CanNegateR;
4929 MustBeFirst = !CanNegate;
4931 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4934 MustBeFirst = MustBeFirstL || MustBeFirstR;
4941MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4944 MachineIRBuilder &MIB)
const {
4948 std::optional<ValueAndVReg>
C;
4952 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4953 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4954 else if (
C->Value.ule(31))
4955 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4957 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4963 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4964 CCmpOpc = AArch64::FCCMPHrr;
4967 CCmpOpc = AArch64::FCCMPSrr;
4970 CCmpOpc = AArch64::FCCMPDrr;
4980 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4981 CCmp.
addImm(
C->Value.getZExtValue());
4982 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4983 CCmp.
addImm(
C->Value.abs().getZExtValue());
4991MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
5013 MachineInstr *ExtraCmp;
5015 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB,
CC);
5027 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
5028 return emitFPCompare(
Cmp->getOperand(2).getReg(),
5029 Cmp->getOperand(3).getReg(), MIB);
5036 bool IsOR = Opcode == TargetOpcode::G_OR;
5042 assert(ValidL &&
"Valid conjunction/disjunction tree");
5049 assert(ValidR &&
"Valid conjunction/disjunction tree");
5054 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
5063 bool NegateAfterAll;
5064 if (Opcode == TargetOpcode::G_OR) {
5067 assert(CanNegateR &&
"at least one side must be negatable");
5068 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
5072 NegateAfterR =
true;
5075 NegateR = CanNegateR;
5076 NegateAfterR = !CanNegateR;
5079 NegateAfterAll = !Negate;
5081 assert(Opcode == TargetOpcode::G_AND &&
5082 "Valid conjunction/disjunction tree");
5083 assert(!Negate &&
"Valid conjunction/disjunction tree");
5087 NegateAfterR =
false;
5088 NegateAfterAll =
false;
5093 MachineInstr *CmpR =
5104MachineInstr *AArch64InstructionSelector::emitConjunction(
5106 bool DummyCanNegate;
5107 bool DummyMustBeFirst;
5114bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5115 MachineInstr &CondMI) {
5126bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5127 MachineRegisterInfo &
MRI = *MIB.
getMRI();
5146 MachineInstr *CondDef =
MRI.
getVRegDef(
I.getOperand(1).getReg());
5155 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5161 unsigned CondOpc = CondDef->
getOpcode();
5162 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5163 if (tryOptSelectConjunction(
I, *CondDef))
5169 if (CondOpc == TargetOpcode::G_ICMP) {
5198 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5199 I.getOperand(3).getReg(), CondCode, MIB);
5200 I.eraseFromParent();
5204MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5205 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5206 MachineIRBuilder &MIRBuilder)
const {
5208 "Unexpected MachineOperand");
5209 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5264 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5267 if (!ValAndVReg || ValAndVReg->Value != 0)
5277bool AArch64InstructionSelector::selectShuffleVector(
5278 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5279 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
5280 Register Src1Reg =
I.getOperand(1).getReg();
5281 Register Src2Reg =
I.getOperand(2).getReg();
5282 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5284 "Expected equal shuffle types during selection");
5293 SmallVector<int> NewMask;
5294 bool FirstUsed =
false;
5295 bool SecondUsed =
false;
5296 for (
int M : Mask) {
5298 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5301 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5306 FirstUsed |=
M < NumElts;
5307 SecondUsed |=
M >= NumElts;
5308 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5317 for (
int &M : NewMask) {
5319 assert(M >= ByteLanes && M < 2 * ByteLanes);
5329 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5330 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5343 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5350 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5354 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5359 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5360 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5362 I.eraseFromParent();
5367 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5370 I.eraseFromParent();
5378 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5381 I.eraseFromParent();
5385MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5387 unsigned LaneIdx,
const RegisterBank &RB,
5388 MachineIRBuilder &MIRBuilder)
const {
5389 MachineInstr *InsElt =
nullptr;
5391 MachineRegisterInfo &
MRI = *MIRBuilder.
getMRI();
5400 if (RB.
getID() == AArch64::FPRRegBankID) {
5401 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5404 .
addUse(InsSub->getOperand(0).getReg())
5416bool AArch64InstructionSelector::selectUSMovFromExtend(
5417 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5418 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5419 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5420 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5422 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5423 const Register DefReg =
MI.getOperand(0).getReg();
5427 if (DstSize != 32 && DstSize != 64)
5430 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5431 MI.getOperand(1).getReg(),
MRI);
5442 const MachineInstr *ScalarToVector = emitScalarToVector(
5443 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5444 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5450 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5452 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5454 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5456 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5458 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5466 MachineInstr *ExtI =
nullptr;
5467 if (DstSize == 64 && !IsSigned) {
5470 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5472 .
addImm(AArch64::sub_32);
5478 MI.eraseFromParent();
5482bool AArch64InstructionSelector::selectIndexedExtLoad(
5483 MachineInstr &
MI, MachineRegisterInfo &
MRI) {
5486 Register WriteBack = ExtLd.getWritebackReg();
5491 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5492 bool IsPre = ExtLd.isPre();
5494 unsigned InsertIntoSubReg = 0;
5500 if ((IsSExt && IsFPR) || Ty.
isVector())
5508 if (MemSizeBits == 8) {
5511 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5513 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5514 NewLdDstTy = IsDst64 ? s64 : s32;
5516 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5517 InsertIntoSubReg = AArch64::bsub;
5520 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5521 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5524 }
else if (MemSizeBits == 16) {
5527 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5529 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5530 NewLdDstTy = IsDst64 ? s64 : s32;
5532 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5533 InsertIntoSubReg = AArch64::hsub;
5536 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5537 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5540 }
else if (MemSizeBits == 32) {
5542 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5545 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5546 InsertIntoSubReg = AArch64::ssub;
5549 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5550 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5562 .addImm(Cst->getSExtValue());
5567 if (InsertIntoSubReg) {
5569 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5570 .addUse(LdMI.getReg(1))
5571 .
addImm(InsertIntoSubReg);
5581 MI.eraseFromParent();
5586bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5587 MachineRegisterInfo &
MRI) {
5590 Register WriteBack = Ld.getWritebackReg();
5594 "Unexpected type for indexed load");
5595 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5598 return selectIndexedExtLoad(
MI,
MRI);
5602 static constexpr unsigned GPROpcodes[] = {
5603 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5605 static constexpr unsigned FPROpcodes[] = {
5606 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5609 ? FPROpcodes[
Log2_32(MemSize)]
5610 : GPROpcodes[
Log2_32(MemSize)];
5613 static constexpr unsigned GPROpcodes[] = {
5614 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5616 static constexpr unsigned FPROpcodes[] = {
5617 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5618 AArch64::LDRDpost, AArch64::LDRQpost};
5620 ? FPROpcodes[
Log2_32(MemSize)]
5621 : GPROpcodes[
Log2_32(MemSize)];
5631 MI.eraseFromParent();
5635bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5636 MachineRegisterInfo &
MRI) {
5642 "Unexpected type for indexed store");
5644 LocationSize MemSize =
I.getMMO().getSize();
5645 unsigned MemSizeInBytes = MemSize.
getValue();
5647 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5648 "Unexpected indexed store size");
5649 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5653 static constexpr unsigned GPROpcodes[] = {
5654 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5656 static constexpr unsigned FPROpcodes[] = {
5657 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5661 Opc = FPROpcodes[MemSizeLog2];
5663 Opc = GPROpcodes[MemSizeLog2];
5665 static constexpr unsigned GPROpcodes[] = {
5666 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5668 static constexpr unsigned FPROpcodes[] = {
5669 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5670 AArch64::STRDpost, AArch64::STRQpost};
5673 Opc = FPROpcodes[MemSizeLog2];
5675 Opc = GPROpcodes[MemSizeLog2];
5683 Str.cloneMemRefs(
I);
5685 I.eraseFromParent();
5690AArch64InstructionSelector::emitConstantMOVVector(DstOp Dst, APInt
Imm,
5691 MachineRegisterInfo &
MRI) {
5692 unsigned DstSize =
Imm.getBitWidth();
5693 assert((DstSize == 64 || DstSize == 128) &&
5694 "Unexpected vector constant size");
5698 for (AArch64_IMM::ImmInsnModel Insn : Insns) {
5699 switch (Insn.Opcode) {
5700 case AArch64::FMOVD0: {
5704 AArch64::MOVIv2d_ns,
5705 {DstSize == 128 ? Dst : DstOp(&AArch64::FPR128RegClass)}, {})
5708 if (DstSize != 128) {
5709 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5710 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5716 case AArch64::FMOVDi:
5717 case AArch64::FMOVv2f32_ns:
5718 case AArch64::FMOVv2f64_ns:
5719 case AArch64::FMOVv4f32_ns:
5720 case AArch64::FMOVv4f16_ns:
5721 case AArch64::FMOVv8f16_ns:
5722 case AArch64::MOVID:
5723 case AArch64::MOVIv16b_ns:
5724 case AArch64::MOVIv2d_ns:
5725 case AArch64::MOVIv2i32:
5726 case AArch64::MOVIv2s_msl:
5727 case AArch64::MOVIv4i16:
5728 case AArch64::MOVIv4i32:
5729 case AArch64::MOVIv4s_msl:
5730 case AArch64::MOVIv8b_ns:
5731 case AArch64::MOVIv8i16:
5732 case AArch64::MVNIv2i32:
5733 case AArch64::MVNIv2s_msl:
5734 case AArch64::MVNIv4i16:
5735 case AArch64::MVNIv4i32:
5736 case AArch64::MVNIv4s_msl:
5737 case AArch64::MVNIv8i16: {
5738 auto Mov = MIB.
buildInstr(Insn.Opcode, {Dst}, {});
5746 case AArch64::DUPM_ZI: {
5747 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5750 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5751 .addReg(Mov.getReg(0), {},
5752 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5754 DstSize == 64 ? AArch64::FPR64RegClass
5755 : AArch64::FPR128RegClass,
5759 case AArch64::DUP_ZI_D: {
5760 auto Mov = MIB.
buildInstr(Insn.Opcode, {&AArch64::ZPRRegClass}, {})
5764 Mov = MIB.
buildInstr(TargetOpcode::COPY, {Dst}, {})
5765 .addReg(Mov.getReg(0), {},
5766 DstSize == 64 ? AArch64::dsub : AArch64::zsub);
5768 DstSize == 64 ? AArch64::FPR64RegClass
5769 : AArch64::FPR128RegClass,
5781MachineInstr *AArch64InstructionSelector::emitConstantVector(
5782 Register Dst, Constant *CV, APInt
Imm, MachineRegisterInfo &
MRI) {
5783 if (
auto *MovI = emitConstantMOVVector(Dst,
Imm,
MRI))
5788 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5798bool AArch64InstructionSelector::tryOptConstantBuildVec(
5799 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &
MRI) {
5800 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5802 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5808 APInt
Imm(DstSize, 0);
5809 for (
unsigned Idx = 1;
Idx <
I.getNumOperands(); ++
Idx) {
5810 Register OpReg =
I.getOperand(Idx).getReg();
5822 std::move(AnyConst->Value)));
5835 if (!emitConstantVector(
I.getOperand(0).getReg(), CV,
Imm,
MRI))
5837 I.eraseFromParent();
5841bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5842 MachineInstr &
I, MachineRegisterInfo &
MRI) {
5847 Register Dst =
I.getOperand(0).getReg();
5848 Register EltReg =
I.getOperand(1).getReg();
5857 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5865 getRegClassForTypeOnBank(
MRI.
getType(Dst), DstRB);
5870 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5873 I.eraseFromParent();
5878bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5879 MachineRegisterInfo &
MRI) {
5880 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5883 const LLT DstTy =
MRI.
getType(
I.getOperand(0).getReg());
5884 const LLT EltTy =
MRI.
getType(
I.getOperand(1).getReg());
5887 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5889 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5892 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5897 MachineInstr *ScalarToVec =
5899 I.getOperand(1).getReg(), MIB);
5908 MachineInstr *PrevMI = ScalarToVec;
5909 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5912 Register OpReg =
I.getOperand(i).getReg();
5915 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5922 if (DstSize < 128) {
5928 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5933 unsigned SubReg = 0;
5936 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5937 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5943 Register DstReg =
I.getOperand(0).getReg();
5945 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
5946 MachineOperand &RegOp =
I.getOperand(1);
5966 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5977bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5980 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5982 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5987 "Destination must be 64 bits or 128 bits?");
5988 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5989 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5994 Register SelectedLoadDst =
Load->getOperand(0).getReg();
5995 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
5996 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
5997 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6006bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6007 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6008 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6010 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6015 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6017 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6018 [](
auto MO) { return MO.getReg(); });
6022 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6037 .
addImm(LaneNo->getZExtValue())
6041 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6042 unsigned SubReg = AArch64::qsub0;
6043 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6044 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6045 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6048 .addReg(SelectedLoadDst, {}, SubReg +
Idx);
6053 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB,
MRI))
6059void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6062 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6064 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6067 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6068 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6077bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6078 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6079 MachineRegisterInfo &
MRI =
I.getParent()->getParent()->getRegInfo();
6084 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6085 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6089 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6099 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6102 .
addImm(LaneNo->getZExtValue())
6109bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6110 MachineInstr &
I, MachineRegisterInfo &
MRI) {
6123 case Intrinsic::aarch64_ldxp:
6124 case Intrinsic::aarch64_ldaxp: {
6126 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6127 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6133 case Intrinsic::aarch64_neon_ld1x2: {
6137 Opc = AArch64::LD1Twov8b;
6139 Opc = AArch64::LD1Twov16b;
6141 Opc = AArch64::LD1Twov4h;
6143 Opc = AArch64::LD1Twov8h;
6145 Opc = AArch64::LD1Twov2s;
6147 Opc = AArch64::LD1Twov4s;
6149 Opc = AArch64::LD1Twov2d;
6150 else if (Ty ==
S64 || Ty == P0)
6151 Opc = AArch64::LD1Twov1d;
6154 selectVectorLoadIntrinsic(
Opc, 2,
I);
6157 case Intrinsic::aarch64_neon_ld1x3: {
6161 Opc = AArch64::LD1Threev8b;
6163 Opc = AArch64::LD1Threev16b;
6165 Opc = AArch64::LD1Threev4h;
6167 Opc = AArch64::LD1Threev8h;
6169 Opc = AArch64::LD1Threev2s;
6171 Opc = AArch64::LD1Threev4s;
6173 Opc = AArch64::LD1Threev2d;
6174 else if (Ty ==
S64 || Ty == P0)
6175 Opc = AArch64::LD1Threev1d;
6178 selectVectorLoadIntrinsic(
Opc, 3,
I);
6181 case Intrinsic::aarch64_neon_ld1x4: {
6185 Opc = AArch64::LD1Fourv8b;
6187 Opc = AArch64::LD1Fourv16b;
6189 Opc = AArch64::LD1Fourv4h;
6191 Opc = AArch64::LD1Fourv8h;
6193 Opc = AArch64::LD1Fourv2s;
6195 Opc = AArch64::LD1Fourv4s;
6197 Opc = AArch64::LD1Fourv2d;
6198 else if (Ty ==
S64 || Ty == P0)
6199 Opc = AArch64::LD1Fourv1d;
6202 selectVectorLoadIntrinsic(
Opc, 4,
I);
6205 case Intrinsic::aarch64_neon_ld2: {
6209 Opc = AArch64::LD2Twov8b;
6211 Opc = AArch64::LD2Twov16b;
6213 Opc = AArch64::LD2Twov4h;
6215 Opc = AArch64::LD2Twov8h;
6217 Opc = AArch64::LD2Twov2s;
6219 Opc = AArch64::LD2Twov4s;
6221 Opc = AArch64::LD2Twov2d;
6222 else if (Ty ==
S64 || Ty == P0)
6223 Opc = AArch64::LD1Twov1d;
6226 selectVectorLoadIntrinsic(
Opc, 2,
I);
6229 case Intrinsic::aarch64_neon_ld2lane: {
6233 Opc = AArch64::LD2i8;
6235 Opc = AArch64::LD2i16;
6237 Opc = AArch64::LD2i32;
6240 Opc = AArch64::LD2i64;
6243 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6247 case Intrinsic::aarch64_neon_ld2r: {
6251 Opc = AArch64::LD2Rv8b;
6253 Opc = AArch64::LD2Rv16b;
6255 Opc = AArch64::LD2Rv4h;
6257 Opc = AArch64::LD2Rv8h;
6259 Opc = AArch64::LD2Rv2s;
6261 Opc = AArch64::LD2Rv4s;
6263 Opc = AArch64::LD2Rv2d;
6264 else if (Ty ==
S64 || Ty == P0)
6265 Opc = AArch64::LD2Rv1d;
6268 selectVectorLoadIntrinsic(
Opc, 2,
I);
6271 case Intrinsic::aarch64_neon_ld3: {
6275 Opc = AArch64::LD3Threev8b;
6277 Opc = AArch64::LD3Threev16b;
6279 Opc = AArch64::LD3Threev4h;
6281 Opc = AArch64::LD3Threev8h;
6283 Opc = AArch64::LD3Threev2s;
6285 Opc = AArch64::LD3Threev4s;
6287 Opc = AArch64::LD3Threev2d;
6288 else if (Ty ==
S64 || Ty == P0)
6289 Opc = AArch64::LD1Threev1d;
6292 selectVectorLoadIntrinsic(
Opc, 3,
I);
6295 case Intrinsic::aarch64_neon_ld3lane: {
6299 Opc = AArch64::LD3i8;
6301 Opc = AArch64::LD3i16;
6303 Opc = AArch64::LD3i32;
6306 Opc = AArch64::LD3i64;
6309 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6313 case Intrinsic::aarch64_neon_ld3r: {
6317 Opc = AArch64::LD3Rv8b;
6319 Opc = AArch64::LD3Rv16b;
6321 Opc = AArch64::LD3Rv4h;
6323 Opc = AArch64::LD3Rv8h;
6325 Opc = AArch64::LD3Rv2s;
6327 Opc = AArch64::LD3Rv4s;
6329 Opc = AArch64::LD3Rv2d;
6330 else if (Ty ==
S64 || Ty == P0)
6331 Opc = AArch64::LD3Rv1d;
6334 selectVectorLoadIntrinsic(
Opc, 3,
I);
6337 case Intrinsic::aarch64_neon_ld4: {
6341 Opc = AArch64::LD4Fourv8b;
6343 Opc = AArch64::LD4Fourv16b;
6345 Opc = AArch64::LD4Fourv4h;
6347 Opc = AArch64::LD4Fourv8h;
6349 Opc = AArch64::LD4Fourv2s;
6351 Opc = AArch64::LD4Fourv4s;
6353 Opc = AArch64::LD4Fourv2d;
6354 else if (Ty ==
S64 || Ty == P0)
6355 Opc = AArch64::LD1Fourv1d;
6358 selectVectorLoadIntrinsic(
Opc, 4,
I);
6361 case Intrinsic::aarch64_neon_ld4lane: {
6365 Opc = AArch64::LD4i8;
6367 Opc = AArch64::LD4i16;
6369 Opc = AArch64::LD4i32;
6372 Opc = AArch64::LD4i64;
6375 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6379 case Intrinsic::aarch64_neon_ld4r: {
6383 Opc = AArch64::LD4Rv8b;
6385 Opc = AArch64::LD4Rv16b;
6387 Opc = AArch64::LD4Rv4h;
6389 Opc = AArch64::LD4Rv8h;
6391 Opc = AArch64::LD4Rv2s;
6393 Opc = AArch64::LD4Rv4s;
6395 Opc = AArch64::LD4Rv2d;
6396 else if (Ty ==
S64 || Ty == P0)
6397 Opc = AArch64::LD4Rv1d;
6400 selectVectorLoadIntrinsic(
Opc, 4,
I);
6403 case Intrinsic::aarch64_neon_st1x2: {
6407 Opc = AArch64::ST1Twov8b;
6409 Opc = AArch64::ST1Twov16b;
6411 Opc = AArch64::ST1Twov4h;
6413 Opc = AArch64::ST1Twov8h;
6415 Opc = AArch64::ST1Twov2s;
6417 Opc = AArch64::ST1Twov4s;
6419 Opc = AArch64::ST1Twov2d;
6420 else if (Ty ==
S64 || Ty == P0)
6421 Opc = AArch64::ST1Twov1d;
6424 selectVectorStoreIntrinsic(
I, 2,
Opc);
6427 case Intrinsic::aarch64_neon_st1x3: {
6431 Opc = AArch64::ST1Threev8b;
6433 Opc = AArch64::ST1Threev16b;
6435 Opc = AArch64::ST1Threev4h;
6437 Opc = AArch64::ST1Threev8h;
6439 Opc = AArch64::ST1Threev2s;
6441 Opc = AArch64::ST1Threev4s;
6443 Opc = AArch64::ST1Threev2d;
6444 else if (Ty ==
S64 || Ty == P0)
6445 Opc = AArch64::ST1Threev1d;
6448 selectVectorStoreIntrinsic(
I, 3,
Opc);
6451 case Intrinsic::aarch64_neon_st1x4: {
6455 Opc = AArch64::ST1Fourv8b;
6457 Opc = AArch64::ST1Fourv16b;
6459 Opc = AArch64::ST1Fourv4h;
6461 Opc = AArch64::ST1Fourv8h;
6463 Opc = AArch64::ST1Fourv2s;
6465 Opc = AArch64::ST1Fourv4s;
6467 Opc = AArch64::ST1Fourv2d;
6468 else if (Ty ==
S64 || Ty == P0)
6469 Opc = AArch64::ST1Fourv1d;
6472 selectVectorStoreIntrinsic(
I, 4,
Opc);
6475 case Intrinsic::aarch64_neon_st2: {
6479 Opc = AArch64::ST2Twov8b;
6481 Opc = AArch64::ST2Twov16b;
6483 Opc = AArch64::ST2Twov4h;
6485 Opc = AArch64::ST2Twov8h;
6487 Opc = AArch64::ST2Twov2s;
6489 Opc = AArch64::ST2Twov4s;
6491 Opc = AArch64::ST2Twov2d;
6492 else if (Ty ==
S64 || Ty == P0)
6493 Opc = AArch64::ST1Twov1d;
6496 selectVectorStoreIntrinsic(
I, 2,
Opc);
6499 case Intrinsic::aarch64_neon_st3: {
6503 Opc = AArch64::ST3Threev8b;
6505 Opc = AArch64::ST3Threev16b;
6507 Opc = AArch64::ST3Threev4h;
6509 Opc = AArch64::ST3Threev8h;
6511 Opc = AArch64::ST3Threev2s;
6513 Opc = AArch64::ST3Threev4s;
6515 Opc = AArch64::ST3Threev2d;
6516 else if (Ty ==
S64 || Ty == P0)
6517 Opc = AArch64::ST1Threev1d;
6520 selectVectorStoreIntrinsic(
I, 3,
Opc);
6523 case Intrinsic::aarch64_neon_st4: {
6527 Opc = AArch64::ST4Fourv8b;
6529 Opc = AArch64::ST4Fourv16b;
6531 Opc = AArch64::ST4Fourv4h;
6533 Opc = AArch64::ST4Fourv8h;
6535 Opc = AArch64::ST4Fourv2s;
6537 Opc = AArch64::ST4Fourv4s;
6539 Opc = AArch64::ST4Fourv2d;
6540 else if (Ty ==
S64 || Ty == P0)
6541 Opc = AArch64::ST1Fourv1d;
6544 selectVectorStoreIntrinsic(
I, 4,
Opc);
6547 case Intrinsic::aarch64_neon_st2lane: {
6551 Opc = AArch64::ST2i8;
6553 Opc = AArch64::ST2i16;
6555 Opc = AArch64::ST2i32;
6558 Opc = AArch64::ST2i64;
6561 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6565 case Intrinsic::aarch64_neon_st3lane: {
6569 Opc = AArch64::ST3i8;
6571 Opc = AArch64::ST3i16;
6573 Opc = AArch64::ST3i32;
6576 Opc = AArch64::ST3i64;
6579 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6583 case Intrinsic::aarch64_neon_st4lane: {
6587 Opc = AArch64::ST4i8;
6589 Opc = AArch64::ST4i16;
6591 Opc = AArch64::ST4i32;
6594 Opc = AArch64::ST4i64;
6597 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6601 case Intrinsic::aarch64_mops_memset_tag: {
6614 Register DstDef =
I.getOperand(0).getReg();
6616 Register DstUse =
I.getOperand(2).getReg();
6617 Register ValUse =
I.getOperand(3).getReg();
6618 Register SizeUse =
I.getOperand(4).getReg();
6625 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6626 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6632 case Intrinsic::ptrauth_resign_load_relative: {
6633 Register DstReg =
I.getOperand(0).getReg();
6634 Register ValReg =
I.getOperand(2).getReg();
6635 uint64_t AUTKey =
I.getOperand(3).getImm();
6636 Register AUTDisc =
I.getOperand(4).getReg();
6637 uint64_t PACKey =
I.getOperand(5).getImm();
6638 Register PACDisc =
I.getOperand(6).getReg();
6639 int64_t Addend =
I.getOperand(7).getImm();
6642 uint16_t AUTConstDiscC = 0;
6643 std::tie(AUTConstDiscC, AUTAddrDisc) =
6647 uint16_t PACConstDiscC = 0;
6648 std::tie(PACConstDiscC, PACAddrDisc) =
6651 MIB.
buildCopy({AArch64::X16}, {ValReg});
6667 I.eraseFromParent();
6672 I.eraseFromParent();
6676bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6677 MachineRegisterInfo &
MRI) {
6683 case Intrinsic::ptrauth_resign: {
6684 Register DstReg =
I.getOperand(0).getReg();
6685 Register ValReg =
I.getOperand(2).getReg();
6686 uint64_t AUTKey =
I.getOperand(3).getImm();
6687 Register AUTDisc =
I.getOperand(4).getReg();
6688 uint64_t PACKey =
I.getOperand(5).getImm();
6689 Register PACDisc =
I.getOperand(6).getReg();
6692 uint16_t AUTConstDiscC = 0;
6693 std::tie(AUTConstDiscC, AUTAddrDisc) =
6697 uint16_t PACConstDiscC = 0;
6698 std::tie(PACConstDiscC, PACAddrDisc) =
6701 MIB.
buildCopy({AArch64::X16}, {ValReg});
6715 I.eraseFromParent();
6718 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6719 Register DstReg =
I.getOperand(0).getReg();
6720 Register ValReg =
I.getOperand(2).getReg();
6721 uint64_t AUTKey =
I.getOperand(3).getImm();
6722 Register AUTDisc =
I.getOperand(4).getReg();
6723 Register AUTPC =
I.getOperand(5).getReg();
6724 uint64_t PACKey =
I.getOperand(6).getImm();
6725 Register PACDisc =
I.getOperand(7).getReg();
6728 "auth_with_pc_and_resign only supports IA and IB keys");
6730 uint16_t PACConstDiscC = 0;
6732 std::tie(PACConstDiscC, PACAddrDisc) =
6736 PACAddrDisc = AArch64::XZR;
6738 MIB.
buildCopy({AArch64::X17}, {ValReg});
6739 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6754 I.eraseFromParent();
6757 case Intrinsic::ptrauth_auth: {
6758 Register DstReg =
I.getOperand(0).getReg();
6759 Register ValReg =
I.getOperand(2).getReg();
6760 uint64_t AUTKey =
I.getOperand(3).getImm();
6761 Register AUTDisc =
I.getOperand(4).getReg();
6764 uint16_t AUTConstDiscC = 0;
6765 std::tie(AUTConstDiscC, AUTAddrDisc) =
6769 MIB.
buildCopy({AArch64::X16}, {ValReg});
6789 Auth.constrainAllUses(
TII,
TRI, RBI);
6793 I.eraseFromParent();
6796 case Intrinsic::frameaddress:
6797 case Intrinsic::returnaddress: {
6801 unsigned Depth =
I.getOperand(2).getImm();
6802 Register DstReg =
I.getOperand(0).getReg();
6805 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6806 if (!MFReturnAddr) {
6811 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6814 if (STI.hasPAuth()) {
6815 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6822 I.eraseFromParent();
6831 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6833 FrameAddr = NextFrame;
6836 if (IntrinID == Intrinsic::frameaddress)
6841 if (STI.hasPAuth()) {
6843 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6844 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6853 I.eraseFromParent();
6856 case Intrinsic::aarch64_neon_tbl2:
6857 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6859 case Intrinsic::aarch64_neon_tbl3:
6860 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6863 case Intrinsic::aarch64_neon_tbl4:
6864 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6866 case Intrinsic::aarch64_neon_tbx2:
6867 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6869 case Intrinsic::aarch64_neon_tbx3:
6870 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6872 case Intrinsic::aarch64_neon_tbx4:
6873 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6875 case Intrinsic::swift_async_context_addr:
6876 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6883 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6884 I.eraseFromParent();
6919bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6920 MachineInstr &
I, MachineRegisterInfo &
MRI)
const {
6921 Register DefReg =
I.getOperand(0).getReg();
6922 Register Addr =
I.getOperand(1).getReg();
6924 Register AddrDisc =
I.getOperand(3).getReg();
6925 uint64_t Disc =
I.getOperand(4).getImm();
6935 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6951 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6963 const GlobalValue *GV;
6974 MachineIRBuilder MIB(
I);
6980 "unsupported non-GOT op flags on ptrauth global reference");
6982 "unsupported non-GOT reference to weak ptrauth global");
6985 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6992 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6995 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7000 I.eraseFromParent();
7012 "unsupported non-zero offset in weak ptrauth global reference");
7017 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7018 .addGlobalAddress(GV,
Offset)
7023 I.eraseFromParent();
7027void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7028 MachineRegisterInfo &
MRI,
7029 unsigned NumVec,
unsigned Opc1,
7030 unsigned Opc2,
bool isExt) {
7031 Register DstReg =
I.getOperand(0).getReg();
7036 for (
unsigned i = 0; i < NumVec; i++)
7037 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7040 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7041 MachineInstrBuilder
Instr;
7048 I.eraseFromParent();
7051InstructionSelector::ComplexRendererFns
7052AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7054 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7055 return std::nullopt;
7056 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7057 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7060InstructionSelector::ComplexRendererFns
7061AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7063 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7064 return std::nullopt;
7066 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7069InstructionSelector::ComplexRendererFns
7070AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7072 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7073 return std::nullopt;
7074 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7075 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7078InstructionSelector::ComplexRendererFns
7079AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7081 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7082 return std::nullopt;
7084 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7087template <
unsigned ShiftW
idth>
7088InstructionSelector::ComplexRendererFns
7089AArch64InstructionSelector::selectShiftMask(MachineOperand &Root)
const {
7091 return std::nullopt;
7093 MachineRegisterInfo &
MRI =
7100 if (ShiftWidth == 32) {
7103 ShAmtReg = ZExtSrcReg;
7112 ShAmtReg = AndSrcReg;
7124 (AddImm % ShiftWidth == 0)) {
7125 ShAmtReg = AddSrcReg;
7126 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7135 SubImm != 0 && (SubImm % ShiftWidth == 0)) {
7136 return {{[=](MachineInstrBuilder &MIB) {
7137 MachineInstr *
I = MIB.getInstr();
7140 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7141 unsigned SubOpc = ShiftWidth == 32 ? AArch64::SUBWrr : AArch64::SUBXrr;
7142 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7144 auto NegMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7145 TII.get(SubOpc), NegReg)
7159 (NotImm % ShiftWidth == ShiftWidth - 1)) {
7160 return {{[=](MachineInstrBuilder &MIB) {
7161 MachineInstr *
I = MIB.getInstr();
7164 ShiftWidth == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
7165 unsigned NotOpc = ShiftWidth == 32 ? AArch64::ORNWrr : AArch64::ORNXrr;
7166 Register ZeroReg = ShiftWidth == 32 ? AArch64::WZR : AArch64::XZR;
7168 auto NotMI =
BuildMI(*
I->getParent(), *
I,
I->getDebugLoc(),
7169 TII.get(NotOpc), NotReg)
7179 if (ShAmtReg == Root.
getReg())
7180 return std::nullopt;
7182 return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
7190InstructionSelector::ComplexRendererFns
7191AArch64InstructionSelector::select12BitValueWithLeftShift(
7194 if (Immed >> 12 == 0) {
7196 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7198 Immed = Immed >> 12;
7200 return std::nullopt;
7204 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7205 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7212InstructionSelector::ComplexRendererFns
7213AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7220 if (MaybeImmed == std::nullopt)
7221 return std::nullopt;
7222 return select12BitValueWithLeftShift(*MaybeImmed);
7227InstructionSelector::ComplexRendererFns
7228AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7232 return std::nullopt;
7234 if (MaybeImmed == std::nullopt)
7235 return std::nullopt;
7242 return std::nullopt;
7248 Immed = ~((uint32_t)Immed) + 1;
7250 Immed = ~Immed + 1ULL;
7252 if (Immed & 0xFFFFFFFFFF000000ULL)
7253 return std::nullopt;
7255 Immed &= 0xFFFFFFULL;
7256 return select12BitValueWithLeftShift(Immed);
7273std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7274 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI)
const {
7275 if (
MI.getOpcode() == AArch64::G_SHL) {
7279 MI.getOperand(2).getReg(),
MRI)) {
7280 const APInt ShiftVal = ValAndVeg->Value;
7283 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7286 return std::nullopt;
7294bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7295 const MachineInstr &
MI,
const MachineRegisterInfo &
MRI,
7296 bool IsAddrOperand)
const {
7301 MI.getParent()->getParent()->getFunction().hasOptSize())
7304 if (IsAddrOperand) {
7306 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7310 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7311 MachineInstr *OffsetInst =
7317 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7328 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7331InstructionSelector::ComplexRendererFns
7332AArch64InstructionSelector::selectExtendedSHL(
7333 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7334 unsigned SizeInBytes,
bool WantsExt)
const {
7335 assert(
Base.isReg() &&
"Expected base to be a register operand");
7336 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7341 unsigned OffsetOpc = OffsetInst->
getOpcode();
7342 bool LookedThroughZExt =
false;
7343 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7345 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7346 return std::nullopt;
7350 LookedThroughZExt =
true;
7352 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7353 return std::nullopt;
7356 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7357 if (LegalShiftVal == 0)
7358 return std::nullopt;
7359 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7360 return std::nullopt;
7371 if (OffsetOpc == TargetOpcode::G_SHL)
7372 return std::nullopt;
7378 return std::nullopt;
7383 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7387 if (OffsetOpc == TargetOpcode::G_MUL) {
7389 return std::nullopt;
7395 if ((ImmVal & 0x7) != ImmVal)
7396 return std::nullopt;
7400 if (ImmVal != LegalShiftVal)
7401 return std::nullopt;
7403 unsigned SignExtend = 0;
7407 if (!LookedThroughZExt) {
7409 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7411 return std::nullopt;
7416 return std::nullopt;
7422 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7427 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7428 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7429 [=](MachineInstrBuilder &MIB) {
7432 MIB.addImm(SignExtend);
7445InstructionSelector::ComplexRendererFns
7446AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7447 MachineOperand &Root,
unsigned SizeInBytes)
const {
7449 return std::nullopt;
7464 MachineInstr *PtrAdd =
7466 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7467 return std::nullopt;
7471 MachineInstr *OffsetInst =
7473 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7486InstructionSelector::ComplexRendererFns
7487AArch64InstructionSelector::selectAddrModeRegisterOffset(
7488 MachineOperand &Root)
const {
7494 return std::nullopt;
7500 return std::nullopt;
7503 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7504 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7505 [=](MachineInstrBuilder &MIB) {
7515InstructionSelector::ComplexRendererFns
7516AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7517 unsigned SizeInBytes)
const {
7520 return std::nullopt;
7521 MachineInstr *PtrAdd =
7524 return std::nullopt;
7542 unsigned Scale =
Log2_32(SizeInBytes);
7543 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7547 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7548 ImmOff < (0x1000 << Scale))
7549 return std::nullopt;
7554 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7558 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7564 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7565 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7570 return std::nullopt;
7574 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7580 return selectAddrModeRegisterOffset(Root);
7589InstructionSelector::ComplexRendererFns
7590AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7591 unsigned SizeInBytes)
const {
7594 MachineInstr *PtrAdd =
7596 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7597 return std::nullopt;
7618 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7627 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7628 return std::nullopt;
7632 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7634 return std::nullopt;
7637 MachineIRBuilder MIB(*PtrAdd);
7639 AArch64::GPR32RegClass, MIB);
7643 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7644 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7645 [=](MachineInstrBuilder &MIB) {
7646 MIB.addImm(SignExtend);
7656InstructionSelector::ComplexRendererFns
7657AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7658 unsigned Size)
const {
7659 MachineRegisterInfo &
MRI =
7663 return std::nullopt;
7665 if (!isBaseWithConstantOffset(Root,
MRI))
7666 return std::nullopt;
7670 MachineOperand &OffImm = RootDef->
getOperand(2);
7671 if (!OffImm.
isReg())
7672 return std::nullopt;
7674 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7675 return std::nullopt;
7677 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7679 return std::nullopt;
7682 if (RHSC >= -256 && RHSC < 256) {
7685 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7686 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7689 return std::nullopt;
7692InstructionSelector::ComplexRendererFns
7693AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7695 MachineRegisterInfo &
MRI)
const {
7696 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7697 return std::nullopt;
7700 return std::nullopt;
7705 return std::nullopt;
7709 return std::nullopt;
7713 return std::nullopt;
7716 MachineIRBuilder MIRBuilder(RootDef);
7718 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7719 [=](MachineInstrBuilder &MIB) {
7720 MIB.addGlobalAddress(GV,
Offset,
7729InstructionSelector::ComplexRendererFns
7730AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7731 unsigned Size)
const {
7736 return std::nullopt;
7739 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7741 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7742 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7750 MachineInstr *RootParent = Root.
getParent();
7752 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7754 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7759 if (isBaseWithConstantOffset(Root,
MRI)) {
7767 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7768 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7770 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7771 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7775 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7776 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7783 if (selectAddrModeUnscaled(Root,
Size))
7784 return std::nullopt;
7787 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7788 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7795 switch (
MI.getOpcode()) {
7798 case TargetOpcode::G_SHL:
7800 case TargetOpcode::G_LSHR:
7802 case TargetOpcode::G_ASHR:
7804 case TargetOpcode::G_ROTR:
7811InstructionSelector::ComplexRendererFns
7812AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7813 bool AllowROR)
const {
7815 return std::nullopt;
7816 MachineRegisterInfo &
MRI =
7824 return std::nullopt;
7826 return std::nullopt;
7827 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7828 return std::nullopt;
7831 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7834 return std::nullopt;
7838 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7842 unsigned Val = *Immed & (NumBits - 1);
7845 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7846 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7850 MachineInstr &
MI, MachineRegisterInfo &
MRI,
bool IsLoadStore)
const {
7851 unsigned Opc =
MI.getOpcode();
7854 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7856 if (
Opc == TargetOpcode::G_SEXT)
7859 Size =
MI.getOperand(2).getImm();
7860 assert(
Size != 64 &&
"Extend from 64 bits?");
7873 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7875 assert(
Size != 64 &&
"Extend from 64 bits?");
7890 if (
Opc != TargetOpcode::G_AND)
7909Register AArch64InstructionSelector::moveScalarRegClass(
7911 MachineRegisterInfo &
MRI = *MIB.
getMRI();
7921 return Copy.getReg(0);
7926InstructionSelector::ComplexRendererFns
7927AArch64InstructionSelector::selectArithExtendedRegister(
7928 MachineOperand &Root)
const {
7930 return std::nullopt;
7931 MachineRegisterInfo &
MRI =
7939 return std::nullopt;
7941 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7942 return std::nullopt;
7945 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7950 return std::nullopt;
7951 ShiftVal = *MaybeShiftVal;
7953 return std::nullopt;
7958 return std::nullopt;
7959 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7961 return std::nullopt;
7965 Ext = getExtendTypeForInst(*RootDef,
MRI);
7967 return std::nullopt;
7976 if (isDef32(*ExtInst))
7977 return std::nullopt;
7983 MachineIRBuilder MIB(*RootDef);
7984 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7986 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7987 [=](MachineInstrBuilder &MIB) {
7988 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7992InstructionSelector::ComplexRendererFns
7993AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7995 return std::nullopt;
7996 MachineRegisterInfo &
MRI =
8000 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
8005 return std::nullopt;
8008 if (Unmerge->getNumDefs() == 2 &&
8010 Register ExtReg = Unmerge->getSourceReg();
8011 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8015 LLT SrcTy =
MRI.
getType(ExtElt->getVectorReg());
8019 LaneIdx->Value.getSExtValue() == 1) {
8020 Register ExtReg = ExtElt->getVectorReg();
8021 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8025 LLT SrcTy =
MRI.
getType(Subvec->getSrcVec());
8026 auto LaneIdx = Subvec->getIndexImm();
8028 Register ExtReg = Subvec->getSrcVec();
8029 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
8033 return std::nullopt;
8036InstructionSelector::ComplexRendererFns
8037AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
8038 unsigned DstElemWidth,
8039 bool isReciprocal)
const {
8041 return std::nullopt;
8042 const MachineRegisterInfo &
MRI =
8048 if (Dup && Dup->
getOpcode() == TargetOpcode::G_SPLAT_VECTOR)
8051 std::optional<ValueAndVReg> CstVal =
8055 return std::nullopt;
8059 switch (CstElemWidth) {
8061 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value.trunc(CstElemWidth));
8064 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8067 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8070 return std::nullopt;
8072 if (
unsigned FBits =
8074 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8076 return std::nullopt;
8079unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8080 const MachineOperand &Root)
const {
8088template <
unsigned W
idth>
8089InstructionSelector::ComplexRendererFns
8090AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8091 return selectCVTFixedPointBase(Root, Width,
false);
8094template <
unsigned W
idth>
8095InstructionSelector::ComplexRendererFns
8096AArch64InstructionSelector::selectCVTFixedPosRecipOperand(
8097 MachineOperand &Root)
const {
8098 return selectCVTFixedPointBase(Root, Width,
true);
8101InstructionSelector::ComplexRendererFns
8102AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8103 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8107InstructionSelector::ComplexRendererFns
8108AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8109 MachineOperand &Root)
const {
8110 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8114void AArch64InstructionSelector::renderFixedPointScalarXForm(
8115 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8116 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8117 "Expected vecshift immediate operand");
8118 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8121void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8122 const MachineOperand &Root,
8124 bool isReciprocal)
const {
8128 InstructionSelector::ComplexRendererFns Renderer =
8129 selectCVTFixedPointBase(Root, Width, isReciprocal);
8130 assert((Renderer && Renderer->size() == 1) &&
8131 "Expected selectCVTFixedPointBase to provide a function\n");
8132 (Renderer->front())(MIB);
8135void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8136 const MachineInstr &
MI,
8138 const MachineOperand &Root =
MI.getOperand(OpIdx);
8139 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8143void AArch64InstructionSelector::renderFixedPointRecipXForm(
8144 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8145 const MachineOperand &Root =
MI.getOperand(OpIdx);
8146 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8150void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8151 const MachineInstr &
MI,
8153 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
8154 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8155 "Expected G_CONSTANT");
8156 std::optional<int64_t> CstVal =
8158 assert(CstVal &&
"Expected constant value");
8162void AArch64InstructionSelector::renderLogicalImm32(
8163 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8164 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8165 "Expected G_CONSTANT");
8166 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8171void AArch64InstructionSelector::renderLogicalImm64(
8172 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8173 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8174 "Expected G_CONSTANT");
8175 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8180void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8181 const MachineInstr &
MI,
8183 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8184 "Expected G_UBSANTRAP");
8185 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8188void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8189 const MachineInstr &
MI,
8191 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8192 "Expected G_FCONSTANT");
8197void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8198 const MachineInstr &
MI,
8200 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8201 "Expected G_FCONSTANT");
8206void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8207 const MachineInstr &
MI,
8209 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8210 "Expected G_FCONSTANT");
8215void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8216 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8217 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8218 "Expected G_FCONSTANT");
8226bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8227 const MachineInstr &
MI,
unsigned NumBytes)
const {
8228 if (!
MI.mayLoadOrStore())
8231 "Expected load/store to have only one mem op!");
8232 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8235bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8236 const MachineRegisterInfo &
MRI =
MI.getParent()->getParent()->getRegInfo();
8244 switch (
MI.getOpcode()) {
8247 case TargetOpcode::COPY:
8248 case TargetOpcode::G_BITCAST:
8249 case TargetOpcode::G_TRUNC:
8250 case TargetOpcode::G_PHI:
8260 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8263 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8274 auto *OpDef =
MRI.getVRegDef(OpReg);
8275 const LLT &Ty =
MRI.getType(OpReg);
8281 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8285 MRI.setRegBank(Copy.getReg(0), *DstRB);
8286 MO.setReg(Copy.getReg(0));
8295 for (
auto &BB : MF) {
8296 for (
auto &
MI : BB) {
8297 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8302 for (
auto *
MI : Phis) {
8324 bool HasGPROp =
false, HasFPROp =
false;
8338 if (RB->
getID() == AArch64::GPRRegBankID)
8344 if (HasGPROp && HasFPROp)
8350InstructionSelector *
8354 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.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue 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.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
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)
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
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)
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.