45#include "llvm/IR/IntrinsicsAArch64.h"
52#define DEBUG_TYPE "aarch64-isel"
65#define GET_GLOBALISEL_PREDICATE_BITSET
66#include "AArch64GenGlobalISel.inc"
67#undef GET_GLOBALISEL_PREDICATE_BITSET
87 ProduceNonFlagSettingCondBr =
135 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
213 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
215 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
217 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
219 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
233 unsigned Opc1,
unsigned Opc2,
bool isExt);
239 unsigned emitConstantPoolEntry(
const Constant *CPVal,
258 std::optional<CmpInst::Predicate> = std::nullopt)
const;
261 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
262 std::initializer_list<llvm::SrcOp> SrcOps,
264 const ComplexRendererFns &RenderFns = std::nullopt)
const;
299 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
322 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
344 std::pair<MachineInstr *, AArch64CC::CondCode>
379 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
380 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
381 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
382 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
384 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
386 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
389 unsigned Size)
const;
391 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
392 return selectAddrModeUnscaled(Root, 1);
394 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
395 return selectAddrModeUnscaled(Root, 2);
397 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
398 return selectAddrModeUnscaled(Root, 4);
400 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
401 return selectAddrModeUnscaled(Root, 8);
403 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
404 return selectAddrModeUnscaled(Root, 16);
409 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
413 unsigned Size)
const;
415 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
416 return selectAddrModeIndexed(Root, Width / 8);
425 bool IsAddrOperand)
const;
428 unsigned SizeInBytes)
const;
436 bool WantsExt)
const;
437 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
439 unsigned SizeInBytes)
const;
441 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
442 return selectAddrModeXRO(Root, Width / 8);
446 unsigned SizeInBytes)
const;
448 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
449 return selectAddrModeWRO(Root, Width / 8);
453 bool AllowROR =
false)
const;
455 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
456 return selectShiftedRegister(Root);
459 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
460 return selectShiftedRegister(Root,
true);
470 bool IsLoadStore =
false)
const;
481 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
484 template <
unsigned W
idth>
485 ComplexRendererFns selectCVTFixedPoint(
MachineOperand &Root)
const;
486 ComplexRendererFns selectCVTFixedPointBase(
const MachineOperand &Root,
488 bool isReciprocal =
false)
const;
489 ComplexRendererFns selectCVTFixedPointVec(
MachineOperand &Root)
const;
494 unsigned getFixedPointWidthFromOperand(
const MachineOperand &Root)
const;
496 int OpIdx = -1)
const;
500 unsigned Width,
bool isReciprocal)
const;
502 int OpIdx = -1)
const;
504 int OpIdx = -1)
const;
506 int OpIdx = -1)
const;
510 int OpIdx = -1)
const;
512 int OpIdx = -1)
const;
514 int OpIdx = -1)
const;
517 int OpIdx = -1)
const;
523 bool tryOptSelect(
GSelect &Sel);
530 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
543 bool ProduceNonFlagSettingCondBr =
false;
552#define GET_GLOBALISEL_PREDICATES_DECL
553#include "AArch64GenGlobalISel.inc"
554#undef GET_GLOBALISEL_PREDICATES_DECL
558#define GET_GLOBALISEL_TEMPORARIES_DECL
559#include "AArch64GenGlobalISel.inc"
560#undef GET_GLOBALISEL_TEMPORARIES_DECL
565#define GET_GLOBALISEL_IMPL
566#include "AArch64GenGlobalISel.inc"
567#undef GET_GLOBALISEL_IMPL
569AArch64InstructionSelector::AArch64InstructionSelector(
572 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
575#include
"AArch64GenGlobalISel.inc"
578#include
"AArch64GenGlobalISel.inc"
590 bool GetAllRegSet =
false) {
591 if (RB.
getID() == AArch64::GPRRegBankID) {
592 if (Ty.getSizeInBits() <= 32)
593 return GetAllRegSet ? &AArch64::GPR32allRegClass
594 : &AArch64::GPR32RegClass;
595 if (Ty.getSizeInBits() == 64)
596 return GetAllRegSet ? &AArch64::GPR64allRegClass
597 : &AArch64::GPR64RegClass;
598 if (Ty.getSizeInBits() == 128)
599 return &AArch64::XSeqPairsClassRegClass;
603 if (RB.
getID() == AArch64::FPRRegBankID) {
604 switch (Ty.getSizeInBits()) {
606 return &AArch64::FPR8RegClass;
608 return &AArch64::FPR16RegClass;
610 return &AArch64::FPR32RegClass;
612 return &AArch64::FPR64RegClass;
614 return &AArch64::FPR128RegClass;
626 bool GetAllRegSet =
false) {
629 "Expected FPR regbank for scalable type size");
630 return &AArch64::ZPRRegClass;
633 unsigned RegBankID = RB.
getID();
635 if (RegBankID == AArch64::GPRRegBankID) {
637 if (SizeInBits <= 32)
638 return GetAllRegSet ? &AArch64::GPR32allRegClass
639 : &AArch64::GPR32RegClass;
640 if (SizeInBits == 64)
641 return GetAllRegSet ? &AArch64::GPR64allRegClass
642 : &AArch64::GPR64RegClass;
643 if (SizeInBits == 128)
644 return &AArch64::XSeqPairsClassRegClass;
647 if (RegBankID == AArch64::FPRRegBankID) {
650 "Unexpected scalable register size");
651 return &AArch64::ZPRRegClass;
654 switch (SizeInBits) {
658 return &AArch64::FPR8RegClass;
660 return &AArch64::FPR16RegClass;
662 return &AArch64::FPR32RegClass;
664 return &AArch64::FPR64RegClass;
666 return &AArch64::FPR128RegClass;
676 switch (
TRI.getRegSizeInBits(*RC)) {
678 SubReg = AArch64::bsub;
681 SubReg = AArch64::hsub;
684 if (RC != &AArch64::FPR32RegClass)
685 SubReg = AArch64::sub_32;
687 SubReg = AArch64::ssub;
690 SubReg = AArch64::dsub;
694 dbgs() <<
"Couldn't find appropriate subregister for register class.");
703 switch (RB.
getID()) {
704 case AArch64::GPRRegBankID:
706 case AArch64::FPRRegBankID:
729 const unsigned RegClassIDs[],
731 unsigned NumRegs = Regs.
size();
734 assert(NumRegs >= 2 && NumRegs <= 4 &&
735 "Only support between two and 4 registers in a tuple!");
737 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
739 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
740 for (
unsigned I = 0,
E = Regs.
size();
I <
E; ++
I) {
741 RegSequence.addUse(Regs[
I]);
742 RegSequence.addImm(SubRegs[
I]);
744 return RegSequence.getReg(0);
749 static const unsigned RegClassIDs[] = {
750 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
751 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
752 AArch64::dsub2, AArch64::dsub3};
753 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
758 static const unsigned RegClassIDs[] = {
759 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
760 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
761 AArch64::qsub2, AArch64::qsub3};
762 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
767 auto &
MBB = *
MI.getParent();
768 auto &MF = *
MBB.getParent();
769 auto &MRI = MF.getRegInfo();
775 else if (Root.
isReg()) {
780 Immed = ValAndVReg->Value.getSExtValue();
791 if (RegBankID == AArch64::GPRRegBankID) {
793 switch (GenericOpc) {
794 case TargetOpcode::G_SHL:
795 return AArch64::LSLVWr;
796 case TargetOpcode::G_LSHR:
797 return AArch64::LSRVWr;
798 case TargetOpcode::G_ASHR:
799 return AArch64::ASRVWr;
803 }
else if (OpSize == 64) {
804 switch (GenericOpc) {
805 case TargetOpcode::G_SHL:
806 return AArch64::LSLVXr;
807 case TargetOpcode::G_LSHR:
808 return AArch64::LSRVXr;
809 case TargetOpcode::G_ASHR:
810 return AArch64::ASRVXr;
826 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
828 case AArch64::GPRRegBankID:
831 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
833 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
835 return isStore ? AArch64::STRWui : AArch64::LDRWui;
837 return isStore ? AArch64::STRXui : AArch64::LDRXui;
840 case AArch64::FPRRegBankID:
843 return isStore ? AArch64::STRBui : AArch64::LDRBui;
845 return isStore ? AArch64::STRHui : AArch64::LDRHui;
847 return isStore ? AArch64::STRSui : AArch64::LDRSui;
849 return isStore ? AArch64::STRDui : AArch64::LDRDui;
851 return isStore ? AArch64::STRQui : AArch64::LDRQui;
865 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
866 assert(To &&
"Destination register class cannot be null");
867 assert(SubReg &&
"Expected a valid subregister");
871 MIB.
buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, {}, SubReg);
873 RegOp.
setReg(SubRegCopy.getReg(0));
877 if (!
I.getOperand(0).getReg().isPhysical())
894 if (
Reg.isPhysical())
902 RC = getRegClassForTypeOnBank(Ty, RB);
905 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
918 Register DstReg =
I.getOperand(0).getReg();
919 Register SrcReg =
I.getOperand(1).getReg();
950 if (
I.getOpcode() == TargetOpcode::G_BITCAST &&
952 if (DstRegBank.
getID() == AArch64::FPRRegBankID &&
953 SrcRegBank.
getID() == AArch64::GPRRegBankID) {
962 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::FMOVWSr))
965 I.setDesc(
TII.get(TargetOpcode::COPY));
966 I.getOperand(1).setReg(FPR32);
967 I.getOperand(1).setSubReg(AArch64::hsub);
971 if (DstRegBank.
getID() == AArch64::GPRRegBankID &&
972 SrcRegBank.
getID() == AArch64::FPRRegBankID) {
982 TII.get(TargetOpcode::SUBREG_TO_REG))
986 I.setDesc(
TII.get(AArch64::FMOVSWr));
987 I.getOperand(1).setReg(FPR32);
996 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1000 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1001 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1002 unsigned SrcSubReg =
I.getOperand(1).getSubReg();
1016 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1017 copySubReg(
I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
1018 }
else if (SrcSize > DstSize) {
1025 }
else if (DstSize > SrcSize) {
1034 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1038 RegOp.
setReg(PromoteReg);
1057 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1058 I.setDesc(
TII.get(AArch64::COPY));
1059 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1063 I.setDesc(
TII.get(AArch64::COPY));
1071 MachineRegisterInfo &MRI = *MIB.
getMRI();
1074 "Expected both select operands to have the same regbank?");
1080 "Expected 32 bit or 64 bit select only?");
1081 const bool Is32Bit =
Size == 32;
1083 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1084 auto FCSel = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1090 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1092 auto TryFoldBinOpIntoSelect = [&
Opc, Is32Bit, &CC, &MRI,
1107 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1124 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1143 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1159 auto TryOptSelectCst = [&
Opc, &True, &False, &CC, Is32Bit, &MRI,
1165 if (!TrueCst && !FalseCst)
1168 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1169 if (TrueCst && FalseCst) {
1170 int64_t
T = TrueCst->Value.getSExtValue();
1171 int64_t
F = FalseCst->Value.getSExtValue();
1173 if (
T == 0 &&
F == 1) {
1175 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1181 if (
T == 0 &&
F == -1) {
1183 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1191 int64_t
T = TrueCst->Value.getSExtValue();
1194 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1203 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1212 int64_t
F = FalseCst->Value.getSExtValue();
1215 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1222 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1230 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1231 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1233 auto SelectInst = MIB.
buildInstr(
Opc, {Dst}, {True, False}).addImm(CC);
1235 return &*SelectInst;
1240 MachineRegisterInfo *MRI =
nullptr) {
1253 if (ValAndVReg && ValAndVReg->Value == 0)
1260 if (ValAndVReg && ValAndVReg->Value == 0)
1364 assert(
Reg.isValid() &&
"Expected valid register!");
1365 bool HasZext =
false;
1367 unsigned Opc =
MI->getOpcode();
1369 if (!
MI->getOperand(0).isReg() ||
1378 if (
Opc == TargetOpcode::G_ANYEXT ||
Opc == TargetOpcode::G_ZEXT ||
1379 Opc == TargetOpcode::G_TRUNC) {
1380 if (
Opc == TargetOpcode::G_ZEXT)
1383 Register NextReg =
MI->getOperand(1).getReg();
1397 std::optional<uint64_t>
C;
1402 case TargetOpcode::G_AND:
1403 case TargetOpcode::G_XOR: {
1404 TestReg =
MI->getOperand(1).getReg();
1405 Register ConstantReg =
MI->getOperand(2).getReg();
1416 C = VRegAndVal->Value.getZExtValue();
1418 C = VRegAndVal->Value.getSExtValue();
1422 case TargetOpcode::G_ASHR:
1423 case TargetOpcode::G_LSHR:
1424 case TargetOpcode::G_SHL: {
1425 TestReg =
MI->getOperand(1).getReg();
1429 C = VRegAndVal->Value.getSExtValue();
1445 case TargetOpcode::G_AND:
1447 if ((*
C >> Bit) & 1)
1450 case TargetOpcode::G_SHL:
1453 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1458 case TargetOpcode::G_ASHR:
1463 if (Bit >= TestRegSize)
1464 Bit = TestRegSize - 1;
1466 case TargetOpcode::G_LSHR:
1468 if ((Bit + *
C) < TestRegSize) {
1473 case TargetOpcode::G_XOR:
1482 if ((*
C >> Bit) & 1)
1497MachineInstr *AArch64InstructionSelector::emitTestBit(
1498 Register TestReg,
uint64_t Bit,
bool IsNegative, MachineBasicBlock *DstMBB,
1499 MachineIRBuilder &MIB)
const {
1501 assert(ProduceNonFlagSettingCondBr &&
1502 "Cannot emit TB(N)Z with speculation tracking!");
1503 MachineRegisterInfo &MRI = *MIB.
getMRI();
1507 LLT Ty = MRI.
getType(TestReg);
1510 assert(Bit < 64 &&
"Bit is too large!");
1514 bool UseWReg =
Bit < 32;
1515 unsigned NecessarySize = UseWReg ? 32 : 64;
1516 if (
Size != NecessarySize)
1517 TestReg = moveScalarRegClass(
1518 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1521 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1522 {AArch64::TBZW, AArch64::TBNZW}};
1523 unsigned Opc = OpcTable[UseWReg][IsNegative];
1530bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1531 MachineInstr &AndInst,
bool Invert, MachineBasicBlock *DstMBB,
1532 MachineIRBuilder &MIB)
const {
1533 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1560 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1567 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1571MachineInstr *AArch64InstructionSelector::emitCBZ(
Register CompareReg,
1573 MachineBasicBlock *DestMBB,
1574 MachineIRBuilder &MIB)
const {
1575 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1576 MachineRegisterInfo &MRI = *MIB.
getMRI();
1578 AArch64::GPRRegBankID &&
1579 "Expected GPRs only?");
1580 auto Ty = MRI.
getType(CompareReg);
1583 assert(Width <= 64 &&
"Expected width to be at most 64?");
1584 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1585 {AArch64::CBNZW, AArch64::CBNZX}};
1586 unsigned Opc = OpcTable[IsNegative][Width == 64];
1587 auto BranchMI = MIB.
buildInstr(
Opc, {}, {CompareReg}).addMBB(DestMBB);
1592bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1593 MachineInstr &
I, MachineInstr &FCmp, MachineIRBuilder &MIB)
const {
1595 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1603 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1607 I.eraseFromParent();
1611bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1612 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1614 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1620 if (!ProduceNonFlagSettingCondBr)
1623 MachineRegisterInfo &MRI = *MIB.
getMRI();
1624 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1639 if (VRegAndVal && !AndInst) {
1640 int64_t
C = VRegAndVal->Value.getSExtValue();
1646 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1647 I.eraseFromParent();
1655 emitTestBit(
LHS, Bit,
true, DestMBB, MIB);
1656 I.eraseFromParent();
1664 emitTestBit(
LHS, Bit,
false, DestMBB, MIB);
1665 I.eraseFromParent();
1679 if (VRegAndVal && VRegAndVal->Value == 0) {
1687 tryOptAndIntoCompareBranch(
1689 I.eraseFromParent();
1695 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1697 I.eraseFromParent();
1706bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1707 MachineInstr &
I, MachineInstr &ICmp, MachineIRBuilder &MIB)
const {
1709 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1710 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1714 MachineBasicBlock *DestMBB =
I.getOperand(1).getMBB();
1721 I.eraseFromParent();
1725bool AArch64InstructionSelector::selectCompareBranch(
1727 Register CondReg =
I.getOperand(0).getReg();
1728 MachineInstr *CCMI = MRI.
getVRegDef(CondReg);
1732 if (CCMIOpc == TargetOpcode::G_FCMP)
1733 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1734 if (CCMIOpc == TargetOpcode::G_ICMP)
1735 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1740 if (ProduceNonFlagSettingCondBr) {
1741 emitTestBit(CondReg, 0,
true,
1742 I.getOperand(1).getMBB(), MIB);
1743 I.eraseFromParent();
1753 .
addMBB(
I.getOperand(1).getMBB());
1754 I.eraseFromParent();
1774 return std::nullopt;
1776 int64_t
Imm = *ShiftImm;
1778 return std::nullopt;
1779 switch (SrcTy.getElementType().getSizeInBits()) {
1782 return std::nullopt;
1785 return std::nullopt;
1789 return std::nullopt;
1793 return std::nullopt;
1797 return std::nullopt;
1803bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &
I,
1804 MachineRegisterInfo &MRI) {
1805 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1806 Register DstReg =
I.getOperand(0).getReg();
1807 const LLT Ty = MRI.
getType(DstReg);
1808 Register Src1Reg =
I.getOperand(1).getReg();
1809 Register Src2Reg =
I.getOperand(2).getReg();
1820 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1822 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1824 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1826 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1828 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1830 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1832 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1844 I.eraseFromParent();
1848bool AArch64InstructionSelector::selectVectorAshrLshr(
1849 MachineInstr &
I, MachineRegisterInfo &MRI) {
1850 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1851 I.getOpcode() == TargetOpcode::G_LSHR);
1852 Register DstReg =
I.getOperand(0).getReg();
1853 const LLT Ty = MRI.
getType(DstReg);
1854 Register Src1Reg =
I.getOperand(1).getReg();
1855 Register Src2Reg =
I.getOperand(2).getReg();
1860 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1870 unsigned NegOpc = 0;
1872 getRegClassForTypeOnBank(Ty, RBI.
getRegBank(AArch64::FPRRegBankID));
1874 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1875 NegOpc = AArch64::NEGv2i64;
1877 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1878 NegOpc = AArch64::NEGv4i32;
1880 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1881 NegOpc = AArch64::NEGv2i32;
1883 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1884 NegOpc = AArch64::NEGv4i16;
1886 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1887 NegOpc = AArch64::NEGv8i16;
1889 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1890 NegOpc = AArch64::NEGv16i8;
1892 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1893 NegOpc = AArch64::NEGv8i8;
1899 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1903 I.eraseFromParent();
1907bool AArch64InstructionSelector::selectVaStartAAPCS(
1917 const AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
1919 const auto *PtrRegClass =
1920 STI.
isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
1922 const MCInstrDesc &MCIDAddAddr =
1924 const MCInstrDesc &MCIDStoreAddr =
1936 const auto VAList =
I.getOperand(0).getReg();
1939 unsigned OffsetBytes = 0;
1943 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
1945 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
1952 const auto *MMO = *
I.memoperands_begin();
1953 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
1956 .
addImm(OffsetBytes / PtrSize)
1958 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1962 OffsetBytes += PtrSize;
1978 const auto PushIntConstant = [&](
const int32_t
Value) {
1979 constexpr int IntSize = 4;
1982 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
1987 const auto *MMO = *
I.memoperands_begin();
1988 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
1991 .
addImm(OffsetBytes / IntSize)
1993 MMO->getPointerInfo().getWithOffset(OffsetBytes),
1996 OffsetBytes += IntSize;
2000 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2003 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2007 I.eraseFromParent();
2011bool AArch64InstructionSelector::selectVaStartDarwin(
2013 AArch64FunctionInfo *FuncInfo = MF.
getInfo<AArch64FunctionInfo>();
2014 Register ListReg =
I.getOperand(0).getReg();
2019 if (MF.
getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2027 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2035 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2042 I.eraseFromParent();
2046void AArch64InstructionSelector::materializeLargeCMVal(
2047 MachineInstr &
I,
const Value *V,
unsigned OpFlags) {
2052 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2067 GV, MovZ->getOperand(1).getOffset(), Flags));
2071 MovZ->getOperand(1).getOffset(), Flags));
2077 Register DstReg = BuildMovK(MovZ.getReg(0),
2083bool AArch64InstructionSelector::preISelLower(MachineInstr &
I) {
2088 switch (
I.getOpcode()) {
2089 case TargetOpcode::G_CONSTANT: {
2090 Register DefReg =
I.getOperand(0).getReg();
2091 const LLT DefTy = MRI.
getType(DefReg);
2097 APInt Val =
I.getOperand(1).getCImm()->getValue().zext(32);
2098 I.getOperand(1).setCImm(
2103 I.getOperand(0).setReg(WideReg);
2112 if (PtrSize != 32 && PtrSize != 64)
2118 case TargetOpcode::G_STORE: {
2119 bool Changed = contractCrossBankCopyIntoStore(
I, MRI);
2120 MachineOperand &SrcOp =
I.getOperand(0);
2133 case TargetOpcode::G_PTR_ADD: {
2137 if (TL->shouldPreservePtrArith(MF.
getFunction(), EVT()))
2139 return convertPtrAddToAdd(
I, MRI);
2141 case TargetOpcode::G_LOAD: {
2146 Register DstReg =
I.getOperand(0).getReg();
2147 const LLT DstTy = MRI.
getType(DstReg);
2153 case TargetOpcode::G_VECREDUCE_ADD:
2154 case TargetOpcode::G_VECREDUCE_SMAX:
2155 case TargetOpcode::G_VECREDUCE_SMIN:
2156 case TargetOpcode::G_VECREDUCE_UMAX:
2157 case TargetOpcode::G_VECREDUCE_UMIN: {
2160 Register DstReg =
I.getOperand(0).getReg();
2161 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2162 if (DstRB.
getID() != AArch64::GPRRegBankID)
2165 LLT DstTy = MRI.
getType(DstReg);
2167 getRegClassForTypeOnBank(DstTy, DstRB,
true);
2173 I.getOperand(0).setReg(FPRDst);
2175 BuildMI(
MBB, std::next(
I.getIterator()), MIMetadata(
I),
2176 TII.get(TargetOpcode::COPY), DstReg)
2180 case AArch64::G_DUP: {
2182 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2186 MRI.
setType(
I.getOperand(0).getReg(),
2188 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2189 I.getOperand(1).setReg(NewSrc.getReg(0));
2192 case AArch64::G_INSERT_VECTOR_ELT: {
2193 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2194 LLT SrcVecTy = MRI.
getType(
I.getOperand(1).getReg());
2198 MRI.
setType(
I.getOperand(1).getReg(),
2200 MRI.
setType(
I.getOperand(0).getReg(),
2202 MRI.
setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2203 I.getOperand(2).setReg(NewSrc.getReg(0));
2207 Register EltReg =
I.getOperand(2).getReg();
2208 LLT EltTy = MRI.
getType(EltReg);
2214 MRI.
setRegClass(NewElt.getReg(0), &AArch64::GPR32RegClass);
2215 I.getOperand(2).setReg(NewElt.getReg(0));
2220 case TargetOpcode::G_UITOFP:
2221 case TargetOpcode::G_SITOFP: {
2226 Register SrcReg =
I.getOperand(1).getReg();
2227 LLT SrcTy = MRI.
getType(SrcReg);
2228 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2237 I.getOperand(1).setReg(
Copy.getReg(0));
2239 getRegClassForTypeOnBank(
2240 SrcTy, RBI.
getRegBank(AArch64::FPRRegBankID)));
2242 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2243 I.setDesc(
TII.get(AArch64::G_SITOF));
2245 I.setDesc(
TII.get(AArch64::G_UITOF));
2263bool AArch64InstructionSelector::convertPtrAddToAdd(
2264 MachineInstr &
I, MachineRegisterInfo &MRI) {
2265 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2266 Register DstReg =
I.getOperand(0).getReg();
2267 Register AddOp1Reg =
I.getOperand(1).getReg();
2268 const LLT PtrTy = MRI.
getType(DstReg);
2272 const LLT CastPtrTy = PtrTy.
isVector()
2284 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2285 MRI.
setType(DstReg, CastPtrTy);
2286 I.getOperand(1).setReg(PtrToInt.getReg(0));
2287 if (!select(*PtrToInt)) {
2288 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2297 I.getOperand(2).setReg(NegatedReg);
2298 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2302bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &
I,
2303 MachineRegisterInfo &MRI) {
2307 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2308 const auto &MO =
I.getOperand(2);
2313 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2317 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2318 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2320 if (!Imm1Fn || !Imm2Fn)
2324 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2325 {
I.getOperand(0).getReg()}, {
I.getOperand(1).getReg()});
2327 for (
auto &RenderFn : *Imm1Fn)
2329 for (
auto &RenderFn : *Imm2Fn)
2332 I.eraseFromParent();
2337bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2338 MachineInstr &
I, MachineRegisterInfo &MRI) {
2339 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2357 LLT DefDstTy = MRI.
getType(DefDstReg);
2358 Register StoreSrcReg =
I.getOperand(0).getReg();
2359 LLT StoreSrcTy = MRI.
getType(StoreSrcReg);
2375 I.getOperand(0).setReg(DefDstReg);
2379bool AArch64InstructionSelector::earlySelect(MachineInstr &
I) {
2380 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2381 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2387 switch (
I.getOpcode()) {
2388 case AArch64::G_DUP: {
2391 Register Src =
I.getOperand(1).getReg();
2393 Src, MRI,
true,
true);
2397 Register Dst =
I.getOperand(0).getReg();
2403 if (!emitConstantVector(Dst, CV, MIB, MRI))
2405 I.eraseFromParent();
2408 case TargetOpcode::G_SEXT:
2411 if (selectUSMovFromExtend(
I, MRI))
2414 case TargetOpcode::G_BR:
2416 case TargetOpcode::G_SHL:
2417 return earlySelectSHL(
I, MRI);
2418 case TargetOpcode::G_CONSTANT: {
2419 bool IsZero =
false;
2420 if (
I.getOperand(1).isCImm())
2421 IsZero =
I.getOperand(1).getCImm()->isZero();
2422 else if (
I.getOperand(1).isImm())
2423 IsZero =
I.getOperand(1).getImm() == 0;
2428 Register DefReg =
I.getOperand(0).getReg();
2431 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2434 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2439 I.setDesc(
TII.get(TargetOpcode::COPY));
2443 case TargetOpcode::G_ADD: {
2452 Register AddDst =
I.getOperand(0).getReg();
2453 Register AddLHS =
I.getOperand(1).getReg();
2454 Register AddRHS =
I.getOperand(2).getReg();
2464 auto MatchCmp = [&](
Register Reg) -> MachineInstr * {
2485 MachineInstr *
Cmp = MatchCmp(AddRHS);
2489 Cmp = MatchCmp(AddRHS);
2493 auto &PredOp =
Cmp->getOperand(1);
2495 emitIntegerCompare(
Cmp->getOperand(2),
2496 Cmp->getOperand(3), PredOp, MIB);
2500 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2501 I.eraseFromParent();
2504 case TargetOpcode::G_OR: {
2508 Register Dst =
I.getOperand(0).getReg();
2528 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2531 int64_t Immr =
Size - ShiftImm;
2532 int64_t Imms =
Size - ShiftImm - 1;
2533 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2534 emitInstr(
Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2535 I.eraseFromParent();
2538 case TargetOpcode::G_FENCE: {
2539 if (
I.getOperand(1).getImm() == 0)
2543 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2544 I.eraseFromParent();
2552bool AArch64InstructionSelector::select(MachineInstr &
I) {
2553 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2554 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2560 const AArch64Subtarget *Subtarget = &MF.
getSubtarget<AArch64Subtarget>();
2561 if (Subtarget->requiresStrictAlign()) {
2563 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2569 unsigned Opcode =
I.getOpcode();
2571 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2574 if (Opcode == TargetOpcode::LOAD_STACK_GUARD) {
2579 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2580 const Register DefReg =
I.getOperand(0).getReg();
2581 const LLT DefTy = MRI.
getType(DefReg);
2594 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2601 I.setDesc(
TII.get(TargetOpcode::PHI));
2609 if (
I.isDebugInstr())
2616 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2618 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2625 if (preISelLower(
I)) {
2626 Opcode =
I.getOpcode();
2637 if (selectImpl(
I, *CoverageInfo))
2641 I.getOperand(0).isReg() ? MRI.
getType(
I.getOperand(0).getReg()) : LLT{};
2644 case TargetOpcode::G_SBFX:
2645 case TargetOpcode::G_UBFX: {
2646 static const unsigned OpcTable[2][2] = {
2647 {AArch64::UBFMWri, AArch64::UBFMXri},
2648 {AArch64::SBFMWri, AArch64::SBFMXri}};
2649 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2651 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2654 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2657 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2658 auto LSB = Cst1->Value.getZExtValue();
2659 auto Width = Cst2->Value.getZExtValue();
2663 .
addImm(LSB + Width - 1);
2664 I.eraseFromParent();
2668 case TargetOpcode::G_BRCOND:
2669 return selectCompareBranch(
I, MF, MRI);
2671 case TargetOpcode::G_BRINDIRECT: {
2673 if (std::optional<uint16_t> BADisc =
2675 auto MI = MIB.
buildInstr(AArch64::BRA, {}, {
I.getOperand(0).getReg()});
2679 I.eraseFromParent();
2683 I.setDesc(
TII.get(AArch64::BR));
2688 case TargetOpcode::G_BRJT:
2689 return selectBrJT(
I, MRI);
2691 case AArch64::G_ADD_LOW: {
2696 MachineInstr *BaseMI = MRI.
getVRegDef(
I.getOperand(1).getReg());
2697 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2698 I.setDesc(
TII.get(AArch64::ADDXri));
2704 "Expected small code model");
2706 auto Op2 =
I.getOperand(2);
2707 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2708 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2709 Op1.getTargetFlags())
2711 Op2.getTargetFlags());
2712 I.eraseFromParent();
2717 case TargetOpcode::G_FCONSTANT: {
2718 const Register DefReg =
I.getOperand(0).getReg();
2719 const LLT DefTy = MRI.
getType(DefReg);
2730 bool OptForSize = shouldOptForSize(&MF);
2734 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2741 auto *FPImm =
I.getOperand(1).getFPImm();
2744 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2747 MIB.
buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
2748 I.eraseFromParent();
2753 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2756 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2757 MachineOperand &RegOp =
I.getOperand(0);
2763 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2767 MachineOperand &ImmOp =
I.getOperand(1);
2771 const unsigned MovOpc =
2772 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2773 I.setDesc(
TII.get(MovOpc));
2777 case TargetOpcode::G_EXTRACT: {
2778 Register DstReg =
I.getOperand(0).getReg();
2779 Register SrcReg =
I.getOperand(1).getReg();
2780 LLT SrcTy = MRI.
getType(SrcReg);
2781 LLT DstTy = MRI.
getType(DstReg);
2793 unsigned Offset =
I.getOperand(2).getImm();
2798 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
2799 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
2802 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2804 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2806 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2808 AArch64::GPR64RegClass, NewI->getOperand(0));
2809 I.eraseFromParent();
2815 unsigned LaneIdx =
Offset / 64;
2816 MachineInstr *Extract = emitExtractVectorElt(
2817 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2820 I.eraseFromParent();
2824 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2825 MachineInstrBuilder(MF,
I).addImm(
I.getOperand(2).getImm() +
2830 "unexpected G_EXTRACT types");
2837 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
2838 .addReg(DstReg, {}, AArch64::sub_32);
2840 AArch64::GPR32RegClass, MRI);
2841 I.getOperand(0).setReg(DstReg);
2847 case TargetOpcode::G_INSERT: {
2848 LLT SrcTy = MRI.
getType(
I.getOperand(2).getReg());
2849 LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
2856 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2857 unsigned LSB =
I.getOperand(3).getImm();
2859 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2860 MachineInstrBuilder(MF,
I).addImm(Width - 1);
2864 "unexpected G_INSERT types");
2871 TII.get(AArch64::SUBREG_TO_REG))
2873 .
addUse(
I.getOperand(2).getReg())
2874 .
addImm(AArch64::sub_32);
2876 AArch64::GPR32RegClass, MRI);
2877 I.getOperand(2).setReg(SrcReg);
2882 case TargetOpcode::G_FRAME_INDEX: {
2889 I.setDesc(
TII.get(AArch64::ADDXri));
2899 case TargetOpcode::G_GLOBAL_VALUE: {
2900 const GlobalValue *GV =
nullptr;
2902 if (
I.getOperand(1).isSymbol()) {
2903 OpFlags =
I.getOperand(1).getTargetFlags();
2912 return selectTLSGlobalValue(
I, MRI);
2918 bool IsGOTSigned = MF.
getInfo<AArch64FunctionInfo>()->hasELFSignedGOT();
2919 I.setDesc(
TII.get(IsGOTSigned ? AArch64::LOADgotAUTH : AArch64::LOADgot));
2920 I.getOperand(1).setTargetFlags(OpFlags);
2921 I.addImplicitDefUseOperands(MF);
2925 materializeLargeCMVal(
I, GV, OpFlags);
2926 I.eraseFromParent();
2929 I.setDesc(
TII.get(AArch64::ADR));
2930 I.getOperand(1).setTargetFlags(OpFlags);
2932 I.setDesc(
TII.get(AArch64::MOVaddr));
2934 MachineInstrBuilder MIB(MF,
I);
2935 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2942 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2943 return selectPtrAuthGlobalValue(
I, MRI);
2945 case TargetOpcode::G_ZEXTLOAD:
2946 case TargetOpcode::G_LOAD:
2947 case TargetOpcode::G_STORE: {
2949 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2964 assert(MemSizeInBytes <= 8 &&
2965 "128-bit atomics should already be custom-legalized");
2968 static constexpr unsigned LDAPROpcodes[] = {
2969 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
2970 static constexpr unsigned LDAROpcodes[] = {
2971 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
2972 ArrayRef<unsigned> Opcodes =
2973 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
2976 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2978 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2979 AArch64::STLRW, AArch64::STLRX};
2984 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
2985 .addReg(
I.getOperand(0).getReg(), {}, AArch64::sub_32);
2986 I.getOperand(0).setReg(NewVal);
2988 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
2996 const RegisterBank &PtrRB = *RBI.
getRegBank(PtrReg, MRI,
TRI);
2999 "Load/Store pointer operand isn't a GPR");
3001 "Load/Store pointer operand isn't a pointer");
3006 LLT ValTy = MRI.
getType(ValReg);
3011 RB.
getID() == AArch64::FPRRegBankID) {
3014 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3020 .addReg(ValReg, {}, SubReg)
3027 if (RB.
getID() == AArch64::FPRRegBankID) {
3030 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3040 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3043 auto SubRegRC = getRegClassForTypeOnBank(MRI.
getType(OldDst), RB);
3052 auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
3054 const unsigned NewOpc =
3056 if (NewOpc ==
I.getOpcode())
3060 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3063 I.setDesc(
TII.get(NewOpc));
3069 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3070 Register CurValReg =
I.getOperand(0).getReg();
3071 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3072 NewInst.cloneMemRefs(
I);
3073 for (
auto &Fn : *AddrModeFns)
3075 I.eraseFromParent();
3079 MachineInstr *
LoadStore = SelectLoadStoreAddressingMode();
3084 if (Opcode == TargetOpcode::G_STORE) {
3086 LoadStore->getOperand(0).getReg(), MRI);
3087 if (CVal && CVal->Value == 0) {
3089 case AArch64::STRWui:
3090 case AArch64::STRHHui:
3091 case AArch64::STRBBui:
3092 LoadStore->getOperand(0).setReg(AArch64::WZR);
3094 case AArch64::STRXui:
3095 LoadStore->getOperand(0).setReg(AArch64::XZR);
3101 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3102 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3114 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3116 .
addImm(AArch64::sub_32);
3125 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3126 case TargetOpcode::G_INDEXED_SEXTLOAD:
3127 return selectIndexedExtLoad(
I, MRI);
3128 case TargetOpcode::G_INDEXED_LOAD:
3129 return selectIndexedLoad(
I, MRI);
3130 case TargetOpcode::G_INDEXED_STORE:
3133 case TargetOpcode::G_LSHR:
3134 case TargetOpcode::G_ASHR:
3136 return selectVectorAshrLshr(
I, MRI);
3138 case TargetOpcode::G_SHL: {
3139 if (Opcode == TargetOpcode::G_SHL &&
3141 return selectVectorSHL(
I, MRI);
3148 Register SrcReg =
I.getOperand(1).getReg();
3149 Register ShiftReg =
I.getOperand(2).getReg();
3150 const LLT ShiftTy = MRI.
getType(ShiftReg);
3151 const LLT SrcTy = MRI.
getType(SrcReg);
3156 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3157 .addReg(ShiftReg, {}, AArch64::sub_32);
3159 I.getOperand(2).setReg(Trunc.getReg(0));
3164 const Register DefReg =
I.getOperand(0).getReg();
3168 if (NewOpc ==
I.getOpcode())
3171 I.setDesc(
TII.get(NewOpc));
3179 case TargetOpcode::G_PTR_ADD: {
3180 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3181 I.eraseFromParent();
3185 case TargetOpcode::G_SADDE:
3186 case TargetOpcode::G_UADDE:
3187 case TargetOpcode::G_SSUBE:
3188 case TargetOpcode::G_USUBE:
3189 case TargetOpcode::G_SADDO:
3190 case TargetOpcode::G_UADDO:
3191 case TargetOpcode::G_SSUBO:
3192 case TargetOpcode::G_USUBO:
3193 return selectOverflowOp(
I, MRI);
3195 case TargetOpcode::G_PTRMASK: {
3196 Register MaskReg =
I.getOperand(2).getReg();
3203 I.setDesc(
TII.get(AArch64::ANDXri));
3204 I.getOperand(2).ChangeToImmediate(
3210 case TargetOpcode::G_PTRTOINT:
3211 case TargetOpcode::G_TRUNC: {
3212 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3213 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3215 const Register DstReg =
I.getOperand(0).getReg();
3216 const Register SrcReg =
I.getOperand(1).getReg();
3218 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3219 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3223 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3227 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3238 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3242 if (DstRC == SrcRC) {
3244 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3248 }
else if (DstRC == &AArch64::GPR32RegClass &&
3249 SrcRC == &AArch64::GPR64RegClass) {
3250 I.getOperand(1).setSubReg(AArch64::sub_32);
3253 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3257 I.setDesc(
TII.get(TargetOpcode::COPY));
3259 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3262 I.setDesc(
TII.get(AArch64::XTNv4i16));
3268 MachineInstr *Extract = emitExtractVectorElt(
3272 I.eraseFromParent();
3277 if (Opcode == TargetOpcode::G_PTRTOINT) {
3278 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3279 I.setDesc(
TII.get(TargetOpcode::COPY));
3287 case TargetOpcode::G_ANYEXT: {
3288 if (selectUSMovFromExtend(
I, MRI))
3291 const Register DstReg =
I.getOperand(0).getReg();
3292 const Register SrcReg =
I.getOperand(1).getReg();
3294 const RegisterBank &RBDst = *RBI.
getRegBank(DstReg, MRI,
TRI);
3295 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3297 <<
", expected: GPR\n");
3301 const RegisterBank &RBSrc = *RBI.
getRegBank(SrcReg, MRI,
TRI);
3302 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3304 <<
", expected: GPR\n");
3311 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3315 if (DstSize != 64 && DstSize > 32) {
3317 <<
", expected: 32 or 64\n");
3327 .
addImm(AArch64::sub_32);
3328 I.getOperand(1).setReg(ExtSrc);
3333 case TargetOpcode::G_ZEXT:
3334 case TargetOpcode::G_SEXT_INREG:
3335 case TargetOpcode::G_SEXT: {
3336 if (selectUSMovFromExtend(
I, MRI))
3339 unsigned Opcode =
I.getOpcode();
3340 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3341 const Register DefReg =
I.getOperand(0).getReg();
3342 Register SrcReg =
I.getOperand(1).getReg();
3343 const LLT DstTy = MRI.
getType(DefReg);
3344 const LLT SrcTy = MRI.
getType(SrcReg);
3350 if (Opcode == TargetOpcode::G_SEXT_INREG)
3351 SrcSize =
I.getOperand(2).getImm();
3357 AArch64::GPRRegBankID &&
3358 "Unexpected ext regbank");
3369 auto *LoadMI =
getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
3372 if (LoadMI && IsGPR) {
3373 const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3374 unsigned BytesLoaded = MemOp->getSize().getValue();
3381 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3384 const Register ZReg = AArch64::WZR;
3385 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3388 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3389 .addUse(SubregToRegSrc)
3390 .
addImm(AArch64::sub_32);
3394 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3404 I.eraseFromParent();
3409 if (DstSize == 64) {
3410 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3418 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3419 {&AArch64::GPR64RegClass}, {})
3425 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3429 }
else if (DstSize <= 32) {
3430 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3439 I.eraseFromParent();
3443 case TargetOpcode::G_FREEZE:
3446 case TargetOpcode::G_INTTOPTR:
3451 case TargetOpcode::G_BITCAST:
3459 case TargetOpcode::G_SELECT: {
3461 const Register CondReg = Sel.getCondReg();
3463 const Register FReg = Sel.getFalseReg();
3465 if (tryOptSelect(Sel))
3471 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3476 Sel.eraseFromParent();
3479 case TargetOpcode::G_ICMP: {
3489 auto &PredOp =
I.getOperand(1);
3490 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3), PredOp, MIB);
3494 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3495 AArch64::WZR, InvCC, MIB);
3496 I.eraseFromParent();
3500 case TargetOpcode::G_FCMP: {
3503 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3505 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3507 I.eraseFromParent();
3510 case TargetOpcode::G_VASTART:
3512 : selectVaStartAAPCS(
I, MF, MRI);
3513 case TargetOpcode::G_INTRINSIC:
3514 return selectIntrinsic(
I, MRI);
3515 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3516 return selectIntrinsicWithSideEffects(
I, MRI);
3517 case TargetOpcode::G_IMPLICIT_DEF: {
3518 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3519 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3520 const Register DstReg =
I.getOperand(0).getReg();
3521 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
3526 case TargetOpcode::G_BLOCK_ADDR: {
3527 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3528 if (std::optional<uint16_t> BADisc =
3530 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3531 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3540 AArch64::GPR64RegClass, MRI);
3541 I.eraseFromParent();
3545 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3546 I.eraseFromParent();
3549 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3550 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3551 I.getOperand(0).getReg())
3555 I.getOperand(1).getBlockAddress(), 0,
3557 I.eraseFromParent();
3562 case AArch64::G_DUP: {
3569 AArch64::GPRRegBankID)
3571 LLT VecTy = MRI.
getType(
I.getOperand(0).getReg());
3573 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3575 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3577 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3579 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3585 case TargetOpcode::G_BUILD_VECTOR:
3586 return selectBuildVector(
I, MRI);
3587 case TargetOpcode::G_MERGE_VALUES:
3589 case TargetOpcode::G_UNMERGE_VALUES:
3591 case TargetOpcode::G_SHUFFLE_VECTOR:
3592 return selectShuffleVector(
I, MRI);
3593 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3594 return selectExtractElt(
I, MRI);
3595 case TargetOpcode::G_CONCAT_VECTORS:
3596 return selectConcatVectors(
I, MRI);
3597 case TargetOpcode::G_JUMP_TABLE:
3598 return selectJumpTable(
I, MRI);
3599 case TargetOpcode::G_MEMCPY:
3600 case TargetOpcode::G_MEMCPY_INLINE:
3601 case TargetOpcode::G_MEMMOVE:
3602 case TargetOpcode::G_MEMSET:
3603 case TargetOpcode::G_MEMSET_INLINE:
3604 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3605 return selectMOPS(
I, MRI);
3611bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &
I) {
3612 MachineIRBuilderState OldMIBState = MIB.
getState();
3618bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
3619 MachineRegisterInfo &MRI) {
3622 case TargetOpcode::G_MEMCPY:
3623 case TargetOpcode::G_MEMCPY_INLINE:
3624 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3626 case TargetOpcode::G_MEMMOVE:
3627 Mopcode = AArch64::MOPSMemoryMovePseudo;
3629 case TargetOpcode::G_MEMSET:
3630 case TargetOpcode::G_MEMSET_INLINE:
3632 Mopcode = AArch64::MOPSMemorySetPseudo;
3645 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3646 const auto &SrcValRegClass =
3647 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3665 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3666 {DstPtrCopy, SizeCopy, SrcValCopy});
3669 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3670 {DstPtrCopy, SrcValCopy, SizeCopy});
3677bool AArch64InstructionSelector::selectBrJT(MachineInstr &
I,
3678 MachineRegisterInfo &MRI) {
3679 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3680 Register JTAddr =
I.getOperand(0).getReg();
3681 unsigned JTI =
I.getOperand(1).getIndex();
3684 MF->
getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4,
nullptr);
3696 "jump table hardening only supported on MachO/ELF");
3704 I.eraseFromParent();
3711 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3712 {TargetReg, ScratchReg}, {JTAddr,
Index})
3713 .addJumpTableIndex(JTI);
3715 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3716 {
static_cast<int64_t
>(JTI)});
3718 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3719 I.eraseFromParent();
3724bool AArch64InstructionSelector::selectJumpTable(MachineInstr &
I,
3725 MachineRegisterInfo &MRI) {
3726 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3727 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3729 Register DstReg =
I.getOperand(0).getReg();
3730 unsigned JTI =
I.getOperand(1).getIndex();
3733 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3736 I.eraseFromParent();
3741bool AArch64InstructionSelector::selectTLSGlobalValue(
3742 MachineInstr &
I, MachineRegisterInfo &MRI) {
3748 const auto &GlobalOp =
I.getOperand(1);
3749 assert(GlobalOp.getOffset() == 0 &&
3750 "Shouldn't have an offset on TLS globals!");
3751 const GlobalValue &GV = *GlobalOp.getGlobal();
3754 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3757 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3758 {LoadGOT.getReg(0)})
3769 assert(Opcode == AArch64::BLR);
3770 Opcode = AArch64::BLRAAZ;
3774 .addUse(AArch64::X0, RegState::Implicit)
3775 .
addDef(AArch64::X0, RegState::Implicit)
3781 I.eraseFromParent();
3785MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3787 MachineIRBuilder &MIRBuilder)
const {
3788 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3790 auto BuildFn = [&](
unsigned SubregIndex) {
3794 .addImm(SubregIndex);
3802 return BuildFn(AArch64::bsub);
3804 return BuildFn(AArch64::hsub);
3806 return BuildFn(AArch64::ssub);
3808 return BuildFn(AArch64::dsub);
3815AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3816 MachineIRBuilder &MIB,
3817 MachineRegisterInfo &MRI)
const {
3818 LLT DstTy = MRI.
getType(DstReg);
3820 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(SrcReg, MRI,
TRI));
3821 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3825 unsigned SubReg = 0;
3828 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
3834 .addReg(SrcReg, {}, SubReg);
3839bool AArch64InstructionSelector::selectMergeValues(
3840 MachineInstr &
I, MachineRegisterInfo &MRI) {
3841 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3842 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
3843 const LLT SrcTy = MRI.
getType(
I.getOperand(1).getReg());
3845 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
3847 if (
I.getNumOperands() != 3)
3854 Register DstReg =
I.getOperand(0).getReg();
3855 Register Src1Reg =
I.getOperand(1).getReg();
3856 Register Src2Reg =
I.getOperand(2).getReg();
3857 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3858 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3862 MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->
getOperand(0).
getReg(),
3863 Src2Reg, 1, RB, MIB);
3868 I.eraseFromParent();
3872 if (RB.
getID() != AArch64::GPRRegBankID)
3878 auto *DstRC = &AArch64::GPR64RegClass;
3880 MachineInstr &SubRegMI = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3881 TII.get(TargetOpcode::SUBREG_TO_REG))
3883 .
addUse(
I.getOperand(1).getReg())
3884 .
addImm(AArch64::sub_32);
3887 MachineInstr &SubRegMI2 = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3888 TII.get(TargetOpcode::SUBREG_TO_REG))
3890 .
addUse(
I.getOperand(2).getReg())
3891 .
addImm(AArch64::sub_32);
3893 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3894 .
addDef(
I.getOperand(0).getReg())
3902 I.eraseFromParent();
3907 const unsigned EltSize) {
3912 CopyOpc = AArch64::DUPi8;
3913 ExtractSubReg = AArch64::bsub;
3916 CopyOpc = AArch64::DUPi16;
3917 ExtractSubReg = AArch64::hsub;
3920 CopyOpc = AArch64::DUPi32;
3921 ExtractSubReg = AArch64::ssub;
3924 CopyOpc = AArch64::DUPi64;
3925 ExtractSubReg = AArch64::dsub;
3929 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
3935MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3936 std::optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
3937 Register VecReg,
unsigned LaneIdx, MachineIRBuilder &MIRBuilder)
const {
3938 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
3939 unsigned CopyOpc = 0;
3940 unsigned ExtractSubReg = 0;
3943 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
3948 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
3950 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
3954 const RegisterBank &VecRB = *RBI.
getRegBank(VecReg, MRI,
TRI);
3955 const LLT &VecTy = MRI.
getType(VecReg);
3957 getRegClassForTypeOnBank(VecTy, VecRB,
true);
3959 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
3969 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
3970 .addReg(VecReg, {}, ExtractSubReg);
3979 MachineInstr *ScalarToVector = emitScalarToVector(
3980 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
3981 if (!ScalarToVector)
3986 MachineInstr *LaneCopyMI =
3987 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
3995bool AArch64InstructionSelector::selectExtractElt(
3996 MachineInstr &
I, MachineRegisterInfo &MRI) {
3997 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
3998 "unexpected opcode!");
3999 Register DstReg =
I.getOperand(0).getReg();
4000 const LLT NarrowTy = MRI.
getType(DstReg);
4001 const Register SrcReg =
I.getOperand(1).getReg();
4002 const LLT WideTy = MRI.
getType(SrcReg);
4004 "source register size too small!");
4005 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4008 MachineOperand &LaneIdxOp =
I.getOperand(2);
4009 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4015 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4017 const RegisterBank &DstRB = *RBI.
getRegBank(DstReg, MRI,
TRI);
4018 if (DstRB.
getID() == AArch64::GPRRegBankID) {
4022 Opcode = AArch64::UMOVvi8;
4025 Opcode = AArch64::UMOVvi16;
4028 Opcode = AArch64::UMOVvi32;
4035 MachineInstr *ScalarToVector = emitScalarToVector(
4036 WideTy.
getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
4037 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
4041 I.setDesc(
TII.get(Opcode));
4042 I.getOperand(2).ChangeToImmediate(LaneIdx);
4047 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4052 I.eraseFromParent();
4056bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4057 MachineInstr &
I, MachineRegisterInfo &MRI) {
4058 unsigned NumElts =
I.getNumOperands() - 1;
4059 Register SrcReg =
I.getOperand(NumElts).getReg();
4060 const LLT NarrowTy = MRI.
getType(
I.getOperand(0).getReg());
4061 const LLT SrcTy = MRI.
getType(SrcReg);
4063 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4065 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4071 const RegisterBank &DstRB =
4073 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4074 Register Dst =
I.getOperand(OpIdx).getReg();
4075 MachineInstr *Extract =
4076 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4080 I.eraseFromParent();
4084bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &
I,
4085 MachineRegisterInfo &MRI) {
4086 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4087 "unexpected opcode");
4091 unsigned NumElts =
I.getNumOperands() - 1;
4092 Register SrcReg =
I.getOperand(NumElts).getReg();
4093 Register LoReg =
I.getOperand(0).getReg();
4094 Register HiReg =
I.getOperand(1).getReg();
4095 const LLT NarrowTy = MRI.
getType(LoReg);
4096 const LLT WideTy = MRI.
getType(SrcReg);
4097 const RegisterBank &LoRB = *RBI.
getRegBank(LoReg, MRI,
TRI);
4098 const RegisterBank &HiRB = *RBI.
getRegBank(HiReg, MRI,
TRI);
4099 const RegisterBank &SrcRB = *RBI.
getRegBank(SrcReg, MRI,
TRI);
4103 LoRB.
getID() == AArch64::GPRRegBankID &&
4104 HiRB.
getID() == AArch64::GPRRegBankID &&
4105 SrcRB.
getID() == AArch64::FPRRegBankID) {
4106 MachineInstr &
Lo = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4107 TII.get(AArch64::UMOVvi64), LoReg)
4110 MachineInstr &
Hi = *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
4111 TII.get(AArch64::UMOVvi64), HiReg)
4116 I.eraseFromParent();
4121 if (LoRB.
getID() != AArch64::FPRRegBankID ||
4122 HiRB.
getID() != AArch64::FPRRegBankID) {
4123 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4124 "currently unsupported.\n");
4129 "source register size too small!");
4132 return selectSplitVectorUnmerge(
I, MRI);
4136 unsigned CopyOpc = 0;
4137 unsigned ExtractSubReg = 0;
4148 unsigned NumInsertRegs = NumElts - 1;
4154 InsertRegs.
assign(NumInsertRegs, SrcReg);
4163 unsigned SubReg = 0;
4166 assert(Found &&
"expected to find last operand's subeg idx");
4167 for (
unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
4169 MachineInstr &ImpDefMI =
4170 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4175 MachineInstr &InsMI =
4177 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4194 Register CopyTo =
I.getOperand(0).getReg();
4195 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4196 .addReg(InsertRegs[0], {}, ExtractSubReg);
4200 unsigned LaneIdx = 1;
4201 for (
Register InsReg : InsertRegs) {
4202 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4203 MachineInstr &CopyInst =
4222 I.eraseFromParent();
4226bool AArch64InstructionSelector::selectConcatVectors(
4227 MachineInstr &
I, MachineRegisterInfo &MRI) {
4228 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4229 "Unexpected opcode");
4230 Register Dst =
I.getOperand(0).getReg();
4231 Register Op1 =
I.getOperand(1).getReg();
4232 Register Op2 =
I.getOperand(2).getReg();
4233 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4236 I.eraseFromParent();
4241AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4250MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4251 const Constant *CPVal, MachineIRBuilder &MIRBuilder)
const {
4258 RC = &AArch64::FPR128RegClass;
4259 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4262 RC = &AArch64::FPR64RegClass;
4263 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4266 RC = &AArch64::FPR32RegClass;
4267 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4270 RC = &AArch64::FPR16RegClass;
4271 Opc = AArch64::LDRHui;
4274 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4279 MachineInstr *LoadMI =
nullptr;
4280 auto &MF = MIRBuilder.
getMF();
4281 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4282 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4284 LoadMI = &*MIRBuilder.
buildInstr(
Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4287 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4291 .addConstantPoolIndex(
4307static std::pair<unsigned, unsigned>
4309 unsigned Opc, SubregIdx;
4310 if (RB.
getID() == AArch64::GPRRegBankID) {
4312 Opc = AArch64::INSvi8gpr;
4313 SubregIdx = AArch64::bsub;
4314 }
else if (EltSize == 16) {
4315 Opc = AArch64::INSvi16gpr;
4316 SubregIdx = AArch64::ssub;
4317 }
else if (EltSize == 32) {
4318 Opc = AArch64::INSvi32gpr;
4319 SubregIdx = AArch64::ssub;
4320 }
else if (EltSize == 64) {
4321 Opc = AArch64::INSvi64gpr;
4322 SubregIdx = AArch64::dsub;
4328 Opc = AArch64::INSvi8lane;
4329 SubregIdx = AArch64::bsub;
4330 }
else if (EltSize == 16) {
4331 Opc = AArch64::INSvi16lane;
4332 SubregIdx = AArch64::hsub;
4333 }
else if (EltSize == 32) {
4334 Opc = AArch64::INSvi32lane;
4335 SubregIdx = AArch64::ssub;
4336 }
else if (EltSize == 64) {
4337 Opc = AArch64::INSvi64lane;
4338 SubregIdx = AArch64::dsub;
4343 return std::make_pair(
Opc, SubregIdx);
4346MachineInstr *AArch64InstructionSelector::emitInstr(
4347 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4348 std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4349 const ComplexRendererFns &RenderFns)
const {
4350 assert(Opcode &&
"Expected an opcode?");
4352 "Function should only be used to produce selected instructions!");
4353 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4355 for (
auto &Fn : *RenderFns)
4361MachineInstr *AArch64InstructionSelector::emitAddSub(
4362 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4364 MachineIRBuilder &MIRBuilder)
const {
4366 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4370 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4371 bool Is32Bit =
Size == 32;
4374 if (
auto Fns = selectArithImmed(
RHS))
4375 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4379 if (
auto Fns = selectNegArithImmed(
RHS))
4380 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4384 if (
auto Fns = selectArithExtendedRegister(
RHS))
4385 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4389 if (
auto Fns = selectShiftedRegister(
RHS))
4390 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4392 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4397AArch64InstructionSelector::emitADD(
Register DefReg, MachineOperand &
LHS,
4398 MachineOperand &
RHS,
4399 MachineIRBuilder &MIRBuilder)
const {
4400 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4401 {{AArch64::ADDXri, AArch64::ADDWri},
4402 {AArch64::ADDXrs, AArch64::ADDWrs},
4403 {AArch64::ADDXrr, AArch64::ADDWrr},
4404 {AArch64::SUBXri, AArch64::SUBWri},
4405 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4406 return emitAddSub(OpcTable, DefReg,
LHS,
RHS, MIRBuilder);
4410AArch64InstructionSelector::emitADDS(
Register Dst, MachineOperand &
LHS,
4411 MachineOperand &
RHS,
4412 MachineIRBuilder &MIRBuilder)
const {
4413 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4414 {{AArch64::ADDSXri, AArch64::ADDSWri},
4415 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4416 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4417 {AArch64::SUBSXri, AArch64::SUBSWri},
4418 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4419 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4423AArch64InstructionSelector::emitSUBS(
Register Dst, MachineOperand &
LHS,
4424 MachineOperand &
RHS,
4425 MachineIRBuilder &MIRBuilder)
const {
4426 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4427 {{AArch64::SUBSXri, AArch64::SUBSWri},
4428 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4429 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4430 {AArch64::ADDSXri, AArch64::ADDSWri},
4431 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4432 return emitAddSub(OpcTable, Dst,
LHS,
RHS, MIRBuilder);
4436AArch64InstructionSelector::emitADCS(
Register Dst, MachineOperand &
LHS,
4437 MachineOperand &
RHS,
4438 MachineIRBuilder &MIRBuilder)
const {
4439 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4440 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4442 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4443 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4447AArch64InstructionSelector::emitSBCS(
Register Dst, MachineOperand &
LHS,
4448 MachineOperand &
RHS,
4449 MachineIRBuilder &MIRBuilder)
const {
4450 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4451 MachineRegisterInfo *MRI = MIRBuilder.
getMRI();
4453 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4454 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4458AArch64InstructionSelector::emitCMP(MachineOperand &
LHS, MachineOperand &
RHS,
4459 MachineIRBuilder &MIRBuilder)
const {
4462 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4467AArch64InstructionSelector::emitCMN(MachineOperand &
LHS, MachineOperand &
RHS,
4468 MachineIRBuilder &MIRBuilder)
const {
4471 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4476AArch64InstructionSelector::emitTST(MachineOperand &
LHS, MachineOperand &
RHS,
4477 MachineIRBuilder &MIRBuilder)
const {
4478 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4482 bool Is32Bit = (
RegSize == 32);
4483 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4484 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4485 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4489 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4492 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4499 if (
auto Fns = selectLogicalShiftedRegister(
RHS))
4500 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4501 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4504MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4505 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
4506 MachineIRBuilder &MIRBuilder)
const {
4507 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4514 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4516 if (
auto FoldCmp = tryFoldIntegerCompare(
LHS,
RHS, Predicate, MIRBuilder))
4518 return emitCMP(
LHS,
RHS, MIRBuilder);
4521MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4523 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4527 "Expected a 32-bit scalar register?");
4529 const Register ZReg = AArch64::WZR;
4534 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4540 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4541 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4542 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4547MachineInstr *AArch64InstructionSelector::emitFPCompare(
4549 std::optional<CmpInst::Predicate> Pred)
const {
4550 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
4555 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4565 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4568 ShouldUseImm =
true;
4572 unsigned CmpOpcTbl[2][3] = {
4573 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4574 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4576 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4588MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4590 MachineIRBuilder &MIRBuilder)
const {
4597 const LLT Op1Ty = MRI.
getType(Op1);
4598 const LLT Op2Ty = MRI.
getType(Op2);
4600 if (Op1Ty != Op2Ty) {
4601 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4604 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4607 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4618 const RegisterBank &FPRBank = *RBI.
getRegBank(Op1, MRI,
TRI);
4622 MachineInstr *WidenedOp1 =
4623 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4624 MachineInstr *WidenedOp2 =
4625 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4626 if (!WidenedOp1 || !WidenedOp2) {
4627 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4632 unsigned InsertOpc, InsSubRegIdx;
4633 std::tie(InsertOpc, InsSubRegIdx) =
4651 MachineIRBuilder &MIRBuilder)
const {
4652 auto &MRI = *MIRBuilder.
getMRI();
4658 Size =
TRI.getRegSizeInBits(*RC);
4662 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4663 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4664 unsigned Opc = OpcTable[
Size == 64];
4665 auto CSINC = MIRBuilder.
buildInstr(
Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4670MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &
I,
4672 MachineRegisterInfo *MRI = MIB.
getMRI();
4673 unsigned Opcode =
I.getOpcode();
4677 bool NeedsNegatedCarry =
4678 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4687 MachineInstr *SrcMI = MRI->
getVRegDef(CarryReg);
4688 if (SrcMI ==
I.getPrevNode()) {
4690 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4691 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4692 CarrySrcMI->isUnsigned() &&
4693 CarrySrcMI->getCarryOutReg() == CarryReg &&
4694 selectAndRestoreState(*SrcMI))
4701 if (NeedsNegatedCarry) {
4704 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4708 auto Fns = select12BitValueWithLeftShift(1);
4709 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4712bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &
I,
4713 MachineRegisterInfo &MRI) {
4718 emitCarryIn(
I, CarryInMI->getCarryInReg());
4722 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4723 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4725 Register CarryOutReg = CarryMI.getCarryOutReg();
4734 emitCSINC(CarryOutReg, ZReg, ZReg,
4735 getInvertedCondCode(OpAndCC.second), MIB);
4738 I.eraseFromParent();
4742std::pair<MachineInstr *, AArch64CC::CondCode>
4743AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4744 MachineOperand &
LHS,
4745 MachineOperand &
RHS,
4746 MachineIRBuilder &MIRBuilder)
const {
4750 case TargetOpcode::G_SADDO:
4752 case TargetOpcode::G_UADDO:
4754 case TargetOpcode::G_SSUBO:
4756 case TargetOpcode::G_USUBO:
4758 case TargetOpcode::G_SADDE:
4760 case TargetOpcode::G_UADDE:
4762 case TargetOpcode::G_SSUBE:
4764 case TargetOpcode::G_USUBE:
4785 unsigned Depth = 0) {
4792 MustBeFirst =
false;
4798 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4799 bool IsOR = Opcode == TargetOpcode::G_OR;
4811 if (MustBeFirstL && MustBeFirstR)
4817 if (!CanNegateL && !CanNegateR)
4821 CanNegate = WillNegate && CanNegateL && CanNegateR;
4824 MustBeFirst = !CanNegate;
4826 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4829 MustBeFirst = MustBeFirstL || MustBeFirstR;
4836MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4839 MachineIRBuilder &MIB)
const {
4840 auto &MRI = *MIB.
getMRI();
4843 std::optional<ValueAndVReg>
C;
4847 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4848 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4849 else if (
C->Value.ule(31))
4850 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4852 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4858 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4859 CCmpOpc = AArch64::FCCMPHrr;
4862 CCmpOpc = AArch64::FCCMPSrr;
4865 CCmpOpc = AArch64::FCCMPDrr;
4875 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4876 CCmp.
addImm(
C->Value.getZExtValue());
4877 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4878 CCmp.
addImm(
C->Value.abs().getZExtValue());
4886MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4890 auto &MRI = *MIB.
getMRI();
4908 MachineInstr *ExtraCmp;
4910 ExtraCmp = emitFPCompare(
LHS,
RHS, MIB, CC);
4922 return emitCMP(
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4923 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4924 Cmp->getOperand(3).getReg(), MIB);
4931 bool IsOR = Opcode == TargetOpcode::G_OR;
4937 assert(ValidL &&
"Valid conjunction/disjunction tree");
4944 assert(ValidR &&
"Valid conjunction/disjunction tree");
4949 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4958 bool NegateAfterAll;
4959 if (Opcode == TargetOpcode::G_OR) {
4962 assert(CanNegateR &&
"at least one side must be negatable");
4963 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4967 NegateAfterR =
true;
4970 NegateR = CanNegateR;
4971 NegateAfterR = !CanNegateR;
4974 NegateAfterAll = !Negate;
4976 assert(Opcode == TargetOpcode::G_AND &&
4977 "Valid conjunction/disjunction tree");
4978 assert(!Negate &&
"Valid conjunction/disjunction tree");
4982 NegateAfterR =
false;
4983 NegateAfterAll =
false;
4988 MachineInstr *CmpR =
4999MachineInstr *AArch64InstructionSelector::emitConjunction(
5001 bool DummyCanNegate;
5002 bool DummyMustBeFirst;
5009bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
5010 MachineInstr &CondMI) {
5021bool AArch64InstructionSelector::tryOptSelect(GSelect &
I) {
5022 MachineRegisterInfo &MRI = *MIB.
getMRI();
5041 MachineInstr *CondDef = MRI.
getVRegDef(
I.getOperand(1).getReg());
5050 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5056 unsigned CondOpc = CondDef->
getOpcode();
5057 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5058 if (tryOptSelectConjunction(
I, *CondDef))
5064 if (CondOpc == TargetOpcode::G_ICMP) {
5093 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5094 I.getOperand(3).getReg(), CondCode, MIB);
5095 I.eraseFromParent();
5099MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5100 MachineOperand &
LHS, MachineOperand &
RHS, MachineOperand &Predicate,
5101 MachineIRBuilder &MIRBuilder)
const {
5103 "Unexpected MachineOperand");
5104 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5127 if (
isCMN(RHSDef,
P, MRI))
5142 if (
isCMN(LHSDef,
P, MRI)) {
5159 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5162 if (!ValAndVReg || ValAndVReg->Value != 0)
5172bool AArch64InstructionSelector::selectShuffleVector(
5173 MachineInstr &
I, MachineRegisterInfo &MRI) {
5174 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5175 Register Src1Reg =
I.getOperand(1).getReg();
5176 Register Src2Reg =
I.getOperand(2).getReg();
5177 ArrayRef<int>
Mask =
I.getOperand(3).getShuffleMask();
5179 "Expected equal shuffle types during selection");
5188 SmallVector<int> NewMask;
5189 bool FirstUsed =
false;
5190 bool SecondUsed =
false;
5191 for (
int M : Mask) {
5193 if (M < 0 || VT->getKnownBits(M < NumElts ? Src1Reg : Src2Reg,
5196 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte)
5201 FirstUsed |=
M < NumElts;
5202 SecondUsed |=
M >= NumElts;
5203 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5212 for (
int &M : NewMask) {
5214 assert(M >= ByteLanes && M < 2 * ByteLanes);
5224 transform(NewMask, std::back_inserter(CstIdxs), [&Ctx](
int M) {
5225 return ConstantInt::get(Type::getInt8Ty(Ctx), M);
5238 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5245 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5249 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5254 MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(0).getReg()}, {})
5255 .addReg(TBL1.getReg(0), {}, AArch64::dsub);
5257 I.eraseFromParent();
5262 auto TBL1 = MIB.
buildInstr(AArch64::TBLv16i8One, {
I.getOperand(0)},
5265 I.eraseFromParent();
5273 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5276 I.eraseFromParent();
5280MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5282 unsigned LaneIdx,
const RegisterBank &RB,
5283 MachineIRBuilder &MIRBuilder)
const {
5284 MachineInstr *InsElt =
nullptr;
5286 MachineRegisterInfo &MRI = *MIRBuilder.
getMRI();
5295 if (RB.
getID() == AArch64::FPRRegBankID) {
5296 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5299 .
addUse(InsSub->getOperand(0).getReg())
5311bool AArch64InstructionSelector::selectUSMovFromExtend(
5312 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5313 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5314 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5315 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5317 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5318 const Register DefReg =
MI.getOperand(0).getReg();
5319 const LLT DstTy = MRI.
getType(DefReg);
5322 if (DstSize != 32 && DstSize != 64)
5325 MachineInstr *Extract =
getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5326 MI.getOperand(1).getReg(), MRI);
5332 const LLT VecTy = MRI.
getType(Src0);
5337 const MachineInstr *ScalarToVector = emitScalarToVector(
5338 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5339 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5345 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5347 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5349 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5351 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5353 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5361 MachineInstr *ExtI =
nullptr;
5362 if (DstSize == 64 && !IsSigned) {
5364 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5365 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5367 .
addImm(AArch64::sub_32);
5370 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5373 MI.eraseFromParent();
5377MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5378 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5380 if (DstSize == 128) {
5381 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5383 Op = AArch64::MOVIv16b_ns;
5385 Op = AArch64::MOVIv8b_ns;
5392 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5399MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5400 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5404 if (DstSize == 128) {
5405 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5407 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5409 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5429MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5430 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5434 if (DstSize == 128) {
5435 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5437 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5439 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5465MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5466 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5469 if (DstSize == 128) {
5470 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5472 Op = AArch64::MOVIv2d_ns;
5474 Op = AArch64::MOVID;
5480 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5487MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5488 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
5492 if (DstSize == 128) {
5493 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5495 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5497 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5517MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5518 Register Dst,
unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
5521 bool IsWide =
false;
5522 if (DstSize == 128) {
5523 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5525 Op = AArch64::FMOVv4f32_ns;
5528 Op = AArch64::FMOVv2f32_ns;
5537 Op = AArch64::FMOVv2f64_ns;
5541 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5546bool AArch64InstructionSelector::selectIndexedExtLoad(
5547 MachineInstr &
MI, MachineRegisterInfo &MRI) {
5550 Register WriteBack = ExtLd.getWritebackReg();
5555 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5556 bool IsPre = ExtLd.isPre();
5558 unsigned InsertIntoSubReg = 0;
5564 if ((IsSExt && IsFPR) || Ty.
isVector())
5572 if (MemSizeBits == 8) {
5575 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5577 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5578 NewLdDstTy = IsDst64 ? s64 : s32;
5580 Opc = IsPre ? AArch64::LDRBpre : AArch64::LDRBpost;
5581 InsertIntoSubReg = AArch64::bsub;
5584 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5585 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5588 }
else if (MemSizeBits == 16) {
5591 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5593 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5594 NewLdDstTy = IsDst64 ? s64 : s32;
5596 Opc = IsPre ? AArch64::LDRHpre : AArch64::LDRHpost;
5597 InsertIntoSubReg = AArch64::hsub;
5600 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5601 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5604 }
else if (MemSizeBits == 32) {
5606 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5609 Opc = IsPre ? AArch64::LDRSpre : AArch64::LDRSpost;
5610 InsertIntoSubReg = AArch64::ssub;
5613 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5614 InsertIntoSubReg = IsDst64 ? AArch64::sub_32 : 0;
5626 .addImm(Cst->getSExtValue());
5631 if (InsertIntoSubReg) {
5633 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5634 .addUse(LdMI.getReg(1))
5635 .
addImm(InsertIntoSubReg);
5638 *getRegClassForTypeOnBank(MRI.
getType(Dst),
5645 MI.eraseFromParent();
5650bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &
MI,
5651 MachineRegisterInfo &MRI) {
5654 Register WriteBack = Ld.getWritebackReg();
5658 "Unexpected type for indexed load");
5659 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5662 return selectIndexedExtLoad(
MI, MRI);
5666 static constexpr unsigned GPROpcodes[] = {
5667 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5669 static constexpr unsigned FPROpcodes[] = {
5670 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5673 ? FPROpcodes[
Log2_32(MemSize)]
5674 : GPROpcodes[
Log2_32(MemSize)];
5677 static constexpr unsigned GPROpcodes[] = {
5678 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5680 static constexpr unsigned FPROpcodes[] = {
5681 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5682 AArch64::LDRDpost, AArch64::LDRQpost};
5684 ? FPROpcodes[
Log2_32(MemSize)]
5685 : GPROpcodes[
Log2_32(MemSize)];
5695 MI.eraseFromParent();
5699bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &
I,
5700 MachineRegisterInfo &MRI) {
5706 "Unexpected type for indexed store");
5708 LocationSize MemSize =
I.getMMO().getSize();
5709 unsigned MemSizeInBytes = MemSize.
getValue();
5711 assert(MemSizeInBytes && MemSizeInBytes <= 16 &&
5712 "Unexpected indexed store size");
5713 unsigned MemSizeLog2 =
Log2_32(MemSizeInBytes);
5717 static constexpr unsigned GPROpcodes[] = {
5718 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5720 static constexpr unsigned FPROpcodes[] = {
5721 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5725 Opc = FPROpcodes[MemSizeLog2];
5727 Opc = GPROpcodes[MemSizeLog2];
5729 static constexpr unsigned GPROpcodes[] = {
5730 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5732 static constexpr unsigned FPROpcodes[] = {
5733 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5734 AArch64::STRDpost, AArch64::STRQpost};
5737 Opc = FPROpcodes[MemSizeLog2];
5739 Opc = GPROpcodes[MemSizeLog2];
5747 Str.cloneMemRefs(
I);
5749 I.eraseFromParent();
5754AArch64InstructionSelector::emitConstantVector(
Register Dst, Constant *CV,
5755 MachineIRBuilder &MIRBuilder,
5756 MachineRegisterInfo &MRI) {
5759 assert((DstSize == 64 || DstSize == 128) &&
5760 "Unexpected vector constant size");
5763 if (DstSize == 128) {
5765 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5770 if (DstSize == 64) {
5773 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5776 .addReg(Mov.getReg(0), {}, AArch64::dsub);
5783 APInt SplatValueAsInt =
5786 : SplatValue->getUniqueInteger();
5789 auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
5790 MachineInstr *NewOp;
5814 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5818 auto TryWithFNeg = [&](APInt DefBits,
int NumBits,
5819 unsigned NegOpc) -> MachineInstr * {
5822 APInt NegBits(DstSize, 0);
5823 unsigned NumElts = DstSize / NumBits;
5824 for (
unsigned i = 0; i < NumElts; i++)
5825 NegBits |= Neg << (NumBits * i);
5826 NegBits = DefBits ^ NegBits;
5830 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5832 DstSize == 64 ? &AArch64::FPR64RegClass : &AArch64::FPR128RegClass);
5834 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5839 if ((R = TryWithFNeg(DefBits, 32,
5840 DstSize == 64 ? AArch64::FNEGv2f32
5841 : AArch64::FNEGv4f32)) ||
5842 (R = TryWithFNeg(DefBits, 64,
5843 DstSize == 64 ? AArch64::FNEGDr
5844 : AArch64::FNEGv2f64)) ||
5845 (STI.hasFullFP16() &&
5846 (R = TryWithFNeg(DefBits, 16,
5847 DstSize == 64 ? AArch64::FNEGv4f16
5848 : AArch64::FNEGv8f16))))
5854 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5858 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5860 Dst, *MRI.
getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5864bool AArch64InstructionSelector::tryOptConstantBuildVec(
5865 MachineInstr &
I, LLT DstTy, MachineRegisterInfo &MRI) {
5866 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5868 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5874 for (
unsigned Idx = 1; Idx <
I.getNumOperands(); ++Idx) {
5875 Register OpReg =
I.getOperand(Idx).getReg();
5884 std::move(AnyConst->Value)));
5897 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB, MRI))
5899 I.eraseFromParent();
5903bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5904 MachineInstr &
I, MachineRegisterInfo &MRI) {
5909 Register Dst =
I.getOperand(0).getReg();
5910 Register EltReg =
I.getOperand(1).getReg();
5911 LLT EltTy = MRI.
getType(EltReg);
5914 const RegisterBank &EltRB = *RBI.
getRegBank(EltReg, MRI,
TRI);
5919 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5927 getRegClassForTypeOnBank(MRI.
getType(Dst), DstRB);
5932 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5935 I.eraseFromParent();
5940bool AArch64InstructionSelector::selectBuildVector(MachineInstr &
I,
5941 MachineRegisterInfo &MRI) {
5942 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5945 const LLT DstTy = MRI.
getType(
I.getOperand(0).getReg());
5946 const LLT EltTy = MRI.
getType(
I.getOperand(1).getReg());
5949 if (tryOptConstantBuildVec(
I, DstTy, MRI))
5951 if (tryOptBuildVecToSubregToReg(
I, MRI))
5954 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5956 const RegisterBank &RB = *RBI.
getRegBank(
I.getOperand(1).getReg(), MRI,
TRI);
5959 MachineInstr *ScalarToVec =
5961 I.getOperand(1).getReg(), MIB);
5970 MachineInstr *PrevMI = ScalarToVec;
5971 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5974 Register OpReg =
I.getOperand(i).getReg();
5977 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5984 if (DstSize < 128) {
5987 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
5990 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5995 unsigned SubReg = 0;
5998 if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
5999 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
6005 Register DstReg =
I.getOperand(0).getReg();
6007 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, {}, SubReg);
6008 MachineOperand &RegOp =
I.getOperand(1);
6028 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
6030 getRegClassForTypeOnBank(DstTy, *RBI.
getRegBank(DstVec, MRI,
TRI));
6039bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
6042 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6044 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6045 auto &MRI = *MIB.
getMRI();
6046 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6049 "Destination must be 64 bits or 128 bits?");
6050 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
6051 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
6056 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6057 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6058 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(Idx)}, {})
6059 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6068bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6069 unsigned Opc,
unsigned NumVecs, MachineInstr &
I) {
6070 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6072 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6073 auto &MRI = *MIB.
getMRI();
6074 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6077 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6079 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6080 [](
auto MO) { return MO.getReg(); });
6084 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6099 .
addImm(LaneNo->getZExtValue())
6103 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6104 unsigned SubReg = AArch64::qsub0;
6105 for (
unsigned Idx = 0; Idx < NumVecs; ++Idx) {
6106 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6107 {Narrow ? DstOp(&AArch64::FPR128RegClass)
6108 : DstOp(
I.getOperand(Idx).
getReg())},
6110 .addReg(SelectedLoadDst, {}, SubReg + Idx);
6115 !emitNarrowVector(
I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
6121void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &
I,
6124 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6125 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6126 Register Ptr =
I.getOperand(1 + NumVecs).getReg();
6129 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6130 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6139bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6140 MachineInstr &
I,
unsigned NumVecs,
unsigned Opc) {
6141 MachineRegisterInfo &MRI =
I.getParent()->getParent()->getRegInfo();
6142 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6146 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6147 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6151 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6161 Register Ptr =
I.getOperand(1 + NumVecs + 1).getReg();
6164 .
addImm(LaneNo->getZExtValue())
6171bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6172 MachineInstr &
I, MachineRegisterInfo &MRI) {
6185 case Intrinsic::aarch64_ldxp:
6186 case Intrinsic::aarch64_ldaxp: {
6188 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6189 {
I.getOperand(0).getReg(),
I.getOperand(1).getReg()},
6195 case Intrinsic::aarch64_neon_ld1x2: {
6196 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6199 Opc = AArch64::LD1Twov8b;
6201 Opc = AArch64::LD1Twov16b;
6203 Opc = AArch64::LD1Twov4h;
6205 Opc = AArch64::LD1Twov8h;
6207 Opc = AArch64::LD1Twov2s;
6209 Opc = AArch64::LD1Twov4s;
6211 Opc = AArch64::LD1Twov2d;
6212 else if (Ty ==
S64 || Ty == P0)
6213 Opc = AArch64::LD1Twov1d;
6216 selectVectorLoadIntrinsic(
Opc, 2,
I);
6219 case Intrinsic::aarch64_neon_ld1x3: {
6220 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6223 Opc = AArch64::LD1Threev8b;
6225 Opc = AArch64::LD1Threev16b;
6227 Opc = AArch64::LD1Threev4h;
6229 Opc = AArch64::LD1Threev8h;
6231 Opc = AArch64::LD1Threev2s;
6233 Opc = AArch64::LD1Threev4s;
6235 Opc = AArch64::LD1Threev2d;
6236 else if (Ty ==
S64 || Ty == P0)
6237 Opc = AArch64::LD1Threev1d;
6240 selectVectorLoadIntrinsic(
Opc, 3,
I);
6243 case Intrinsic::aarch64_neon_ld1x4: {
6244 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6247 Opc = AArch64::LD1Fourv8b;
6249 Opc = AArch64::LD1Fourv16b;
6251 Opc = AArch64::LD1Fourv4h;
6253 Opc = AArch64::LD1Fourv8h;
6255 Opc = AArch64::LD1Fourv2s;
6257 Opc = AArch64::LD1Fourv4s;
6259 Opc = AArch64::LD1Fourv2d;
6260 else if (Ty ==
S64 || Ty == P0)
6261 Opc = AArch64::LD1Fourv1d;
6264 selectVectorLoadIntrinsic(
Opc, 4,
I);
6267 case Intrinsic::aarch64_neon_ld2: {
6268 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6271 Opc = AArch64::LD2Twov8b;
6273 Opc = AArch64::LD2Twov16b;
6275 Opc = AArch64::LD2Twov4h;
6277 Opc = AArch64::LD2Twov8h;
6279 Opc = AArch64::LD2Twov2s;
6281 Opc = AArch64::LD2Twov4s;
6283 Opc = AArch64::LD2Twov2d;
6284 else if (Ty ==
S64 || Ty == P0)
6285 Opc = AArch64::LD1Twov1d;
6288 selectVectorLoadIntrinsic(
Opc, 2,
I);
6291 case Intrinsic::aarch64_neon_ld2lane: {
6292 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6295 Opc = AArch64::LD2i8;
6297 Opc = AArch64::LD2i16;
6299 Opc = AArch64::LD2i32;
6302 Opc = AArch64::LD2i64;
6305 if (!selectVectorLoadLaneIntrinsic(
Opc, 2,
I))
6309 case Intrinsic::aarch64_neon_ld2r: {
6310 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6313 Opc = AArch64::LD2Rv8b;
6315 Opc = AArch64::LD2Rv16b;
6317 Opc = AArch64::LD2Rv4h;
6319 Opc = AArch64::LD2Rv8h;
6321 Opc = AArch64::LD2Rv2s;
6323 Opc = AArch64::LD2Rv4s;
6325 Opc = AArch64::LD2Rv2d;
6326 else if (Ty ==
S64 || Ty == P0)
6327 Opc = AArch64::LD2Rv1d;
6330 selectVectorLoadIntrinsic(
Opc, 2,
I);
6333 case Intrinsic::aarch64_neon_ld3: {
6334 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6337 Opc = AArch64::LD3Threev8b;
6339 Opc = AArch64::LD3Threev16b;
6341 Opc = AArch64::LD3Threev4h;
6343 Opc = AArch64::LD3Threev8h;
6345 Opc = AArch64::LD3Threev2s;
6347 Opc = AArch64::LD3Threev4s;
6349 Opc = AArch64::LD3Threev2d;
6350 else if (Ty ==
S64 || Ty == P0)
6351 Opc = AArch64::LD1Threev1d;
6354 selectVectorLoadIntrinsic(
Opc, 3,
I);
6357 case Intrinsic::aarch64_neon_ld3lane: {
6358 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6361 Opc = AArch64::LD3i8;
6363 Opc = AArch64::LD3i16;
6365 Opc = AArch64::LD3i32;
6368 Opc = AArch64::LD3i64;
6371 if (!selectVectorLoadLaneIntrinsic(
Opc, 3,
I))
6375 case Intrinsic::aarch64_neon_ld3r: {
6376 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6379 Opc = AArch64::LD3Rv8b;
6381 Opc = AArch64::LD3Rv16b;
6383 Opc = AArch64::LD3Rv4h;
6385 Opc = AArch64::LD3Rv8h;
6387 Opc = AArch64::LD3Rv2s;
6389 Opc = AArch64::LD3Rv4s;
6391 Opc = AArch64::LD3Rv2d;
6392 else if (Ty ==
S64 || Ty == P0)
6393 Opc = AArch64::LD3Rv1d;
6396 selectVectorLoadIntrinsic(
Opc, 3,
I);
6399 case Intrinsic::aarch64_neon_ld4: {
6400 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6403 Opc = AArch64::LD4Fourv8b;
6405 Opc = AArch64::LD4Fourv16b;
6407 Opc = AArch64::LD4Fourv4h;
6409 Opc = AArch64::LD4Fourv8h;
6411 Opc = AArch64::LD4Fourv2s;
6413 Opc = AArch64::LD4Fourv4s;
6415 Opc = AArch64::LD4Fourv2d;
6416 else if (Ty ==
S64 || Ty == P0)
6417 Opc = AArch64::LD1Fourv1d;
6420 selectVectorLoadIntrinsic(
Opc, 4,
I);
6423 case Intrinsic::aarch64_neon_ld4lane: {
6424 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6427 Opc = AArch64::LD4i8;
6429 Opc = AArch64::LD4i16;
6431 Opc = AArch64::LD4i32;
6434 Opc = AArch64::LD4i64;
6437 if (!selectVectorLoadLaneIntrinsic(
Opc, 4,
I))
6441 case Intrinsic::aarch64_neon_ld4r: {
6442 LLT Ty = MRI.
getType(
I.getOperand(0).getReg());
6445 Opc = AArch64::LD4Rv8b;
6447 Opc = AArch64::LD4Rv16b;
6449 Opc = AArch64::LD4Rv4h;
6451 Opc = AArch64::LD4Rv8h;
6453 Opc = AArch64::LD4Rv2s;
6455 Opc = AArch64::LD4Rv4s;
6457 Opc = AArch64::LD4Rv2d;
6458 else if (Ty ==
S64 || Ty == P0)
6459 Opc = AArch64::LD4Rv1d;
6462 selectVectorLoadIntrinsic(
Opc, 4,
I);
6465 case Intrinsic::aarch64_neon_st1x2: {
6466 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6469 Opc = AArch64::ST1Twov8b;
6471 Opc = AArch64::ST1Twov16b;
6473 Opc = AArch64::ST1Twov4h;
6475 Opc = AArch64::ST1Twov8h;
6477 Opc = AArch64::ST1Twov2s;
6479 Opc = AArch64::ST1Twov4s;
6481 Opc = AArch64::ST1Twov2d;
6482 else if (Ty ==
S64 || Ty == P0)
6483 Opc = AArch64::ST1Twov1d;
6486 selectVectorStoreIntrinsic(
I, 2,
Opc);
6489 case Intrinsic::aarch64_neon_st1x3: {
6490 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6493 Opc = AArch64::ST1Threev8b;
6495 Opc = AArch64::ST1Threev16b;
6497 Opc = AArch64::ST1Threev4h;
6499 Opc = AArch64::ST1Threev8h;
6501 Opc = AArch64::ST1Threev2s;
6503 Opc = AArch64::ST1Threev4s;
6505 Opc = AArch64::ST1Threev2d;
6506 else if (Ty ==
S64 || Ty == P0)
6507 Opc = AArch64::ST1Threev1d;
6510 selectVectorStoreIntrinsic(
I, 3,
Opc);
6513 case Intrinsic::aarch64_neon_st1x4: {
6514 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6517 Opc = AArch64::ST1Fourv8b;
6519 Opc = AArch64::ST1Fourv16b;
6521 Opc = AArch64::ST1Fourv4h;
6523 Opc = AArch64::ST1Fourv8h;
6525 Opc = AArch64::ST1Fourv2s;
6527 Opc = AArch64::ST1Fourv4s;
6529 Opc = AArch64::ST1Fourv2d;
6530 else if (Ty ==
S64 || Ty == P0)
6531 Opc = AArch64::ST1Fourv1d;
6534 selectVectorStoreIntrinsic(
I, 4,
Opc);
6537 case Intrinsic::aarch64_neon_st2: {
6538 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6541 Opc = AArch64::ST2Twov8b;
6543 Opc = AArch64::ST2Twov16b;
6545 Opc = AArch64::ST2Twov4h;
6547 Opc = AArch64::ST2Twov8h;
6549 Opc = AArch64::ST2Twov2s;
6551 Opc = AArch64::ST2Twov4s;
6553 Opc = AArch64::ST2Twov2d;
6554 else if (Ty ==
S64 || Ty == P0)
6555 Opc = AArch64::ST1Twov1d;
6558 selectVectorStoreIntrinsic(
I, 2,
Opc);
6561 case Intrinsic::aarch64_neon_st3: {
6562 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6565 Opc = AArch64::ST3Threev8b;
6567 Opc = AArch64::ST3Threev16b;
6569 Opc = AArch64::ST3Threev4h;
6571 Opc = AArch64::ST3Threev8h;
6573 Opc = AArch64::ST3Threev2s;
6575 Opc = AArch64::ST3Threev4s;
6577 Opc = AArch64::ST3Threev2d;
6578 else if (Ty ==
S64 || Ty == P0)
6579 Opc = AArch64::ST1Threev1d;
6582 selectVectorStoreIntrinsic(
I, 3,
Opc);
6585 case Intrinsic::aarch64_neon_st4: {
6586 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6589 Opc = AArch64::ST4Fourv8b;
6591 Opc = AArch64::ST4Fourv16b;
6593 Opc = AArch64::ST4Fourv4h;
6595 Opc = AArch64::ST4Fourv8h;
6597 Opc = AArch64::ST4Fourv2s;
6599 Opc = AArch64::ST4Fourv4s;
6601 Opc = AArch64::ST4Fourv2d;
6602 else if (Ty ==
S64 || Ty == P0)
6603 Opc = AArch64::ST1Fourv1d;
6606 selectVectorStoreIntrinsic(
I, 4,
Opc);
6609 case Intrinsic::aarch64_neon_st2lane: {
6610 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6613 Opc = AArch64::ST2i8;
6615 Opc = AArch64::ST2i16;
6617 Opc = AArch64::ST2i32;
6620 Opc = AArch64::ST2i64;
6623 if (!selectVectorStoreLaneIntrinsic(
I, 2,
Opc))
6627 case Intrinsic::aarch64_neon_st3lane: {
6628 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6631 Opc = AArch64::ST3i8;
6633 Opc = AArch64::ST3i16;
6635 Opc = AArch64::ST3i32;
6638 Opc = AArch64::ST3i64;
6641 if (!selectVectorStoreLaneIntrinsic(
I, 3,
Opc))
6645 case Intrinsic::aarch64_neon_st4lane: {
6646 LLT Ty = MRI.
getType(
I.getOperand(1).getReg());
6649 Opc = AArch64::ST4i8;
6651 Opc = AArch64::ST4i16;
6653 Opc = AArch64::ST4i32;
6656 Opc = AArch64::ST4i64;
6659 if (!selectVectorStoreLaneIntrinsic(
I, 4,
Opc))
6663 case Intrinsic::aarch64_mops_memset_tag: {
6676 Register DstDef =
I.getOperand(0).getReg();
6678 Register DstUse =
I.getOperand(2).getReg();
6679 Register ValUse =
I.getOperand(3).getReg();
6680 Register SizeUse =
I.getOperand(4).getReg();
6687 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6688 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6693 case Intrinsic::ptrauth_resign_load_relative: {
6694 Register DstReg =
I.getOperand(0).getReg();
6695 Register ValReg =
I.getOperand(2).getReg();
6696 uint64_t AUTKey =
I.getOperand(3).getImm();
6697 Register AUTDisc =
I.getOperand(4).getReg();
6698 uint64_t PACKey =
I.getOperand(5).getImm();
6699 Register PACDisc =
I.getOperand(6).getReg();
6700 int64_t Addend =
I.getOperand(7).getImm();
6703 uint16_t AUTConstDiscC = 0;
6704 std::tie(AUTConstDiscC, AUTAddrDisc) =
6708 uint16_t PACConstDiscC = 0;
6709 std::tie(PACConstDiscC, PACAddrDisc) =
6712 MIB.
buildCopy({AArch64::X16}, {ValReg});
6726 I.eraseFromParent();
6731 I.eraseFromParent();
6735bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &
I,
6736 MachineRegisterInfo &MRI) {
6742 case Intrinsic::ptrauth_resign: {
6743 Register DstReg =
I.getOperand(0).getReg();
6744 Register ValReg =
I.getOperand(2).getReg();
6745 uint64_t AUTKey =
I.getOperand(3).getImm();
6746 Register AUTDisc =
I.getOperand(4).getReg();
6747 uint64_t PACKey =
I.getOperand(5).getImm();
6748 Register PACDisc =
I.getOperand(6).getReg();
6751 uint16_t AUTConstDiscC = 0;
6752 std::tie(AUTConstDiscC, AUTAddrDisc) =
6756 uint16_t PACConstDiscC = 0;
6757 std::tie(PACConstDiscC, PACAddrDisc) =
6760 MIB.
buildCopy({AArch64::X16}, {ValReg});
6761 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6773 I.eraseFromParent();
6776 case Intrinsic::ptrauth_auth_with_pc_and_resign: {
6777 Register DstReg =
I.getOperand(0).getReg();
6778 Register ValReg =
I.getOperand(2).getReg();
6779 uint64_t AUTKey =
I.getOperand(3).getImm();
6780 Register AUTDisc =
I.getOperand(4).getReg();
6781 Register AUTPC =
I.getOperand(5).getReg();
6782 uint64_t PACKey =
I.getOperand(6).getImm();
6783 Register PACDisc =
I.getOperand(7).getReg();
6786 "auth_with_pc_and_resign only supports IA and IB keys");
6788 uint16_t PACConstDiscC = 0;
6790 std::tie(PACConstDiscC, PACAddrDisc) =
6793 if (PACAddrDisc == AArch64::NoRegister)
6794 PACAddrDisc = AArch64::XZR;
6796 MIB.
buildCopy({AArch64::X17}, {ValReg});
6797 MIB.
buildCopy({AArch64::X16}, {AUTDisc});
6809 I.eraseFromParent();
6812 case Intrinsic::ptrauth_auth: {
6813 Register DstReg =
I.getOperand(0).getReg();
6814 Register ValReg =
I.getOperand(2).getReg();
6815 uint64_t AUTKey =
I.getOperand(3).getImm();
6816 Register AUTDisc =
I.getOperand(4).getReg();
6819 uint16_t AUTConstDiscC = 0;
6820 std::tie(AUTConstDiscC, AUTAddrDisc) =
6824 MIB.
buildCopy({AArch64::X16}, {ValReg});
6825 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6846 I.eraseFromParent();
6849 case Intrinsic::frameaddress:
6850 case Intrinsic::returnaddress: {
6854 unsigned Depth =
I.getOperand(2).getImm();
6855 Register DstReg =
I.getOperand(0).getReg();
6858 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6859 if (!MFReturnAddr) {
6864 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6867 if (STI.hasPAuth()) {
6868 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6875 I.eraseFromParent();
6884 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6886 FrameAddr = NextFrame;
6889 if (IntrinID == Intrinsic::frameaddress)
6894 if (STI.hasPAuth()) {
6896 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6897 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6906 I.eraseFromParent();
6909 case Intrinsic::aarch64_neon_tbl2:
6910 SelectTable(
I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6912 case Intrinsic::aarch64_neon_tbl3:
6913 SelectTable(
I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6916 case Intrinsic::aarch64_neon_tbl4:
6917 SelectTable(
I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6919 case Intrinsic::aarch64_neon_tbx2:
6920 SelectTable(
I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6922 case Intrinsic::aarch64_neon_tbx3:
6923 SelectTable(
I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6925 case Intrinsic::aarch64_neon_tbx4:
6926 SelectTable(
I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6928 case Intrinsic::swift_async_context_addr:
6929 auto Sub = MIB.
buildInstr(AArch64::SUBXri, {
I.getOperand(0).getReg()},
6936 MF->
getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(
true);
6937 I.eraseFromParent();
6972bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6973 MachineInstr &
I, MachineRegisterInfo &MRI)
const {
6974 Register DefReg =
I.getOperand(0).getReg();
6975 Register Addr =
I.getOperand(1).getReg();
6977 Register AddrDisc =
I.getOperand(3).getReg();
6978 uint64_t Disc =
I.getOperand(4).getImm();
6988 "constant discriminator in ptrauth global out of range [0, 0xffff]");
7004 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
7016 const GlobalValue *GV;
7027 MachineIRBuilder MIB(
I);
7033 "unsupported non-GOT op flags on ptrauth global reference");
7035 "unsupported non-GOT reference to weak ptrauth global");
7038 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
7045 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
7046 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
7047 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
7050 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
7055 I.eraseFromParent();
7067 "unsupported non-zero offset in weak ptrauth global reference");
7072 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
7073 .addGlobalAddress(GV,
Offset)
7078 I.eraseFromParent();
7082void AArch64InstructionSelector::SelectTable(MachineInstr &
I,
7083 MachineRegisterInfo &MRI,
7084 unsigned NumVec,
unsigned Opc1,
7085 unsigned Opc2,
bool isExt) {
7086 Register DstReg =
I.getOperand(0).getReg();
7091 for (
unsigned i = 0; i < NumVec; i++)
7092 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
7095 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7096 MachineInstrBuilder
Instr;
7103 I.eraseFromParent();
7106InstructionSelector::ComplexRendererFns
7107AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7109 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7110 return std::nullopt;
7111 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7112 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7115InstructionSelector::ComplexRendererFns
7116AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7118 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7119 return std::nullopt;
7121 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7124InstructionSelector::ComplexRendererFns
7125AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7127 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7128 return std::nullopt;
7129 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7130 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7133InstructionSelector::ComplexRendererFns
7134AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7136 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7137 return std::nullopt;
7139 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
7147InstructionSelector::ComplexRendererFns
7148AArch64InstructionSelector::select12BitValueWithLeftShift(
7151 if (Immed >> 12 == 0) {
7153 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7155 Immed = Immed >> 12;
7157 return std::nullopt;
7161 [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
7162 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
7169InstructionSelector::ComplexRendererFns
7170AArch64InstructionSelector::selectArithImmed(MachineOperand &Root)
const {
7177 if (MaybeImmed == std::nullopt)
7178 return std::nullopt;
7179 return select12BitValueWithLeftShift(*MaybeImmed);
7184InstructionSelector::ComplexRendererFns
7185AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root)
const {
7189 return std::nullopt;
7191 if (MaybeImmed == std::nullopt)
7192 return std::nullopt;
7199 return std::nullopt;
7205 Immed = ~((uint32_t)Immed) + 1;
7207 Immed = ~Immed + 1ULL;
7209 if (Immed & 0xFFFFFFFFFF000000ULL)
7210 return std::nullopt;
7212 Immed &= 0xFFFFFFULL;
7213 return select12BitValueWithLeftShift(Immed);
7230std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7231 const MachineInstr &
MI,
const MachineRegisterInfo &MRI)
const {
7232 if (
MI.getOpcode() == AArch64::G_SHL) {
7236 MI.getOperand(2).getReg(), MRI)) {
7237 const APInt ShiftVal = ValAndVeg->Value;
7240 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7243 return std::nullopt;
7251bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7252 const MachineInstr &
MI,
const MachineRegisterInfo &MRI,
7253 bool IsAddrOperand)
const {
7258 MI.getParent()->getParent()->getFunction().hasOptSize())
7261 if (IsAddrOperand) {
7263 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI, MRI))
7267 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7268 MachineInstr *OffsetInst =
7274 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7285 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
7288InstructionSelector::ComplexRendererFns
7289AArch64InstructionSelector::selectExtendedSHL(
7290 MachineOperand &Root, MachineOperand &
Base, MachineOperand &
Offset,
7291 unsigned SizeInBytes,
bool WantsExt)
const {
7292 assert(
Base.isReg() &&
"Expected base to be a register operand");
7293 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7298 unsigned OffsetOpc = OffsetInst->
getOpcode();
7299 bool LookedThroughZExt =
false;
7300 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7302 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7303 return std::nullopt;
7307 LookedThroughZExt =
true;
7309 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7310 return std::nullopt;
7313 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7314 if (LegalShiftVal == 0)
7315 return std::nullopt;
7316 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7317 return std::nullopt;
7328 if (OffsetOpc == TargetOpcode::G_SHL)
7329 return std::nullopt;
7335 return std::nullopt;
7340 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7344 if (OffsetOpc == TargetOpcode::G_MUL) {
7346 return std::nullopt;
7352 if ((ImmVal & 0x7) != ImmVal)
7353 return std::nullopt;
7357 if (ImmVal != LegalShiftVal)
7358 return std::nullopt;
7360 unsigned SignExtend = 0;
7364 if (!LookedThroughZExt) {
7366 auto Ext = getExtendTypeForInst(*ExtInst, MRI,
true);
7368 return std::nullopt;
7373 return std::nullopt;
7379 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7384 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base.getReg()); },
7385 [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
7386 [=](MachineInstrBuilder &MIB) {
7389 MIB.addImm(SignExtend);
7402InstructionSelector::ComplexRendererFns
7403AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7404 MachineOperand &Root,
unsigned SizeInBytes)
const {
7406 return std::nullopt;
7421 MachineInstr *PtrAdd =
7423 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7424 return std::nullopt;
7428 MachineInstr *OffsetInst =
7430 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7443InstructionSelector::ComplexRendererFns
7444AArch64InstructionSelector::selectAddrModeRegisterOffset(
7445 MachineOperand &Root)
const {
7451 return std::nullopt;
7457 return std::nullopt;
7460 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
Base); },
7461 [=](MachineInstrBuilder &MIB) { MIB.addUse(
Offset); },
7462 [=](MachineInstrBuilder &MIB) {
7472InstructionSelector::ComplexRendererFns
7473AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
7474 unsigned SizeInBytes)
const {
7477 return std::nullopt;
7478 MachineInstr *PtrAdd =
7481 return std::nullopt;
7499 unsigned Scale =
Log2_32(SizeInBytes);
7500 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7504 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7505 ImmOff < (0x1000 << Scale))
7506 return std::nullopt;
7511 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7515 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7521 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7522 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7527 return std::nullopt;
7531 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7537 return selectAddrModeRegisterOffset(Root);
7546InstructionSelector::ComplexRendererFns
7547AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
7548 unsigned SizeInBytes)
const {
7551 MachineInstr *PtrAdd =
7553 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI,
true))
7554 return std::nullopt;
7575 auto ExtendedShl = selectExtendedSHL(Root,
LHS, OffsetInst->
getOperand(0),
7584 if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI,
true))
7585 return std::nullopt;
7589 getExtendTypeForInst(*OffsetInst, MRI,
true);
7591 return std::nullopt;
7594 MachineIRBuilder MIB(*PtrAdd);
7596 AArch64::GPR32RegClass, MIB);
7600 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(
LHS.getReg()); },
7601 [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7602 [=](MachineInstrBuilder &MIB) {
7603 MIB.addImm(SignExtend);
7613InstructionSelector::ComplexRendererFns
7614AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
7615 unsigned Size)
const {
7616 MachineRegisterInfo &MRI =
7620 return std::nullopt;
7622 if (!isBaseWithConstantOffset(Root, MRI))
7623 return std::nullopt;
7627 MachineOperand &OffImm = RootDef->
getOperand(2);
7628 if (!OffImm.
isReg())
7629 return std::nullopt;
7631 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7632 return std::nullopt;
7634 MachineOperand &RHSOp1 =
RHS->getOperand(1);
7636 return std::nullopt;
7639 if (RHSC >= -256 && RHSC < 256) {
7642 [=](MachineInstrBuilder &MIB) { MIB.add(
Base); },
7643 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
7646 return std::nullopt;
7649InstructionSelector::ComplexRendererFns
7650AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
7652 MachineRegisterInfo &MRI)
const {
7653 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7654 return std::nullopt;
7657 return std::nullopt;
7662 return std::nullopt;
7666 return std::nullopt;
7670 return std::nullopt;
7673 MachineIRBuilder MIRBuilder(RootDef);
7675 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
7676 [=](MachineInstrBuilder &MIB) {
7677 MIB.addGlobalAddress(GV,
Offset,
7686InstructionSelector::ComplexRendererFns
7687AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
7688 unsigned Size)
const {
7693 return std::nullopt;
7696 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7698 [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->
getOperand(1)); },
7699 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7707 MachineInstr *RootParent = Root.
getParent();
7709 !(RootParent->
getOpcode() == AArch64::G_AARCH64_PREFETCH &&
7711 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size, MRI);
7716 if (isBaseWithConstantOffset(Root, MRI)) {
7724 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7725 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7727 [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->
getOperand(1)); },
7728 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7732 [=](MachineInstrBuilder &MIB) { MIB.add(
LHS); },
7733 [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
7740 if (selectAddrModeUnscaled(Root,
Size))
7741 return std::nullopt;
7744 [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
7745 [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
7752 switch (
MI.getOpcode()) {
7755 case TargetOpcode::G_SHL:
7757 case TargetOpcode::G_LSHR:
7759 case TargetOpcode::G_ASHR:
7761 case TargetOpcode::G_ROTR:
7768InstructionSelector::ComplexRendererFns
7769AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7770 bool AllowROR)
const {
7772 return std::nullopt;
7773 MachineRegisterInfo &MRI =
7781 return std::nullopt;
7783 return std::nullopt;
7784 if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI,
false))
7785 return std::nullopt;
7788 MachineOperand &ShiftRHS = ShiftInst->
getOperand(2);
7791 return std::nullopt;
7795 MachineOperand &ShiftLHS = ShiftInst->
getOperand(1);
7799 unsigned Val = *Immed & (NumBits - 1);
7802 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
7803 [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
7807 MachineInstr &
MI, MachineRegisterInfo &MRI,
bool IsLoadStore)
const {
7808 unsigned Opc =
MI.getOpcode();
7811 if (
Opc == TargetOpcode::G_SEXT ||
Opc == TargetOpcode::G_SEXT_INREG) {
7813 if (
Opc == TargetOpcode::G_SEXT)
7816 Size =
MI.getOperand(2).getImm();
7817 assert(
Size != 64 &&
"Extend from 64 bits?");
7830 if (
Opc == TargetOpcode::G_ZEXT ||
Opc == TargetOpcode::G_ANYEXT) {
7832 assert(
Size != 64 &&
"Extend from 64 bits?");
7847 if (
Opc != TargetOpcode::G_AND)
7866Register AArch64InstructionSelector::moveScalarRegClass(
7868 MachineRegisterInfo &MRI = *MIB.
getMRI();
7878 return Copy.getReg(0);
7883InstructionSelector::ComplexRendererFns
7884AArch64InstructionSelector::selectArithExtendedRegister(
7885 MachineOperand &Root)
const {
7887 return std::nullopt;
7888 MachineRegisterInfo &MRI =
7896 return std::nullopt;
7898 if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI,
false))
7899 return std::nullopt;
7902 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7907 return std::nullopt;
7908 ShiftVal = *MaybeShiftVal;
7910 return std::nullopt;
7915 return std::nullopt;
7916 Ext = getExtendTypeForInst(*ExtDef, MRI);
7918 return std::nullopt;
7922 Ext = getExtendTypeForInst(*RootDef, MRI);
7924 return std::nullopt;
7932 MachineInstr *ExtInst = MRI.
getVRegDef(ExtReg);
7933 if (isDef32(*ExtInst))
7934 return std::nullopt;
7940 MachineIRBuilder MIB(*RootDef);
7941 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7943 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
7944 [=](MachineInstrBuilder &MIB) {
7945 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7949InstructionSelector::ComplexRendererFns
7950AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root)
const {
7952 return std::nullopt;
7953 MachineRegisterInfo &MRI =
7957 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7962 return std::nullopt;
7965 if (Unmerge->getNumDefs() == 2 &&
7967 Register ExtReg = Unmerge->getSourceReg();
7968 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7972 LLT SrcTy = MRI.
getType(ExtElt->getVectorReg());
7976 LaneIdx->Value.getSExtValue() == 1) {
7977 Register ExtReg = ExtElt->getVectorReg();
7978 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7982 LLT SrcTy = MRI.
getType(Subvec->getSrcVec());
7983 auto LaneIdx = Subvec->getIndexImm();
7985 Register ExtReg = Subvec->getSrcVec();
7986 return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
7990 return std::nullopt;
7993InstructionSelector::ComplexRendererFns
7994AArch64InstructionSelector::selectCVTFixedPointBase(
const MachineOperand &Root,
7995 unsigned DstElemWidth,
7996 bool isReciprocal)
const {
7998 return std::nullopt;
7999 const MachineRegisterInfo &MRI =
8005 if (Dup && Dup->
getOpcode() == AArch64::G_DUP)
8008 std::optional<ValueAndVReg> CstVal =
8012 return std::nullopt;
8016 switch (CstElemWidth) {
8018 FVal =
APFloat(APFloat::IEEEhalf(), CstVal->Value);
8021 FVal =
APFloat(APFloat::IEEEsingle(), CstVal->Value);
8024 FVal =
APFloat(APFloat::IEEEdouble(), CstVal->Value);
8027 return std::nullopt;
8029 if (
unsigned FBits =
8031 return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(FBits); }}};
8033 return std::nullopt;
8036unsigned AArch64InstructionSelector::getFixedPointWidthFromOperand(
8037 const MachineOperand &Root)
const {
8045template <
unsigned W
idth>
8046InstructionSelector::ComplexRendererFns
8047AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root)
const {
8048 return selectCVTFixedPointBase(Root, Width,
false);
8051InstructionSelector::ComplexRendererFns
8052AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root)
const {
8053 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8057InstructionSelector::ComplexRendererFns
8058AArch64InstructionSelector::selectCVTFixedPosRecipOperandVec(
8059 MachineOperand &Root)
const {
8060 return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
8064void AArch64InstructionSelector::renderFixedPointScalarXForm(
8065 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8066 assert(OpIdx == 3 &&
MI.getOperand(OpIdx).isImm() &&
8067 "Expected vecshift immediate operand");
8068 MIB.
addImm(
MI.getOperand(OpIdx).getImm());
8071void AArch64InstructionSelector::renderFixedPointImm(MachineInstrBuilder &MIB,
8072 const MachineOperand &Root,
8074 bool isReciprocal)
const {
8078 InstructionSelector::ComplexRendererFns Renderer =
8079 selectCVTFixedPointBase(Root, Width, isReciprocal);
8080 assert((Renderer && Renderer->size() == 1) &&
8081 "Expected selectCVTFixedPointBase to provide a function\n");
8082 (Renderer->front())(MIB);
8085void AArch64InstructionSelector::renderFixedPointXForm(MachineInstrBuilder &MIB,
8086 const MachineInstr &
MI,
8088 const MachineOperand &Root =
MI.getOperand(OpIdx);
8089 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8093void AArch64InstructionSelector::renderFixedPointRecipXForm(
8094 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8095 const MachineOperand &Root =
MI.getOperand(OpIdx);
8096 renderFixedPointImm(MIB, Root, getFixedPointWidthFromOperand(Root),
8100void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
8101 const MachineInstr &
MI,
8103 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8104 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8105 "Expected G_CONSTANT");
8106 std::optional<int64_t> CstVal =
8108 assert(CstVal &&
"Expected constant value");
8112void AArch64InstructionSelector::renderLogicalImm32(
8113 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8114 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8115 "Expected G_CONSTANT");
8116 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8121void AArch64InstructionSelector::renderLogicalImm64(
8122 MachineInstrBuilder &MIB,
const MachineInstr &
I,
int OpIdx)
const {
8123 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
8124 "Expected G_CONSTANT");
8125 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
8130void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
8131 const MachineInstr &
MI,
8133 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
8134 "Expected G_UBSANTRAP");
8135 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
8138void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
8139 const MachineInstr &
MI,
8141 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8142 "Expected G_FCONSTANT");
8147void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
8148 const MachineInstr &
MI,
8150 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8151 "Expected G_FCONSTANT");
8156void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
8157 const MachineInstr &
MI,
8159 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8160 "Expected G_FCONSTANT");
8165void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
8166 MachineInstrBuilder &MIB,
const MachineInstr &
MI,
int OpIdx)
const {
8167 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
8168 "Expected G_FCONSTANT");
8176bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
8177 const MachineInstr &
MI,
unsigned NumBytes)
const {
8178 if (!
MI.mayLoadOrStore())
8181 "Expected load/store to have only one mem op!");
8182 return (*
MI.memoperands_begin())->getSize() == NumBytes;
8185bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
8186 const MachineRegisterInfo &MRI =
MI.getParent()->getParent()->getRegInfo();
8194 switch (
MI.getOpcode()) {
8197 case TargetOpcode::COPY:
8198 case TargetOpcode::G_BITCAST:
8199 case TargetOpcode::G_TRUNC:
8200 case TargetOpcode::G_PHI:
8210 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8213 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8231 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8236 MO.setReg(Copy.getReg(0));
8245 for (
auto &BB : MF) {
8246 for (
auto &
MI : BB) {
8247 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8252 for (
auto *
MI : Phis) {
8274 bool HasGPROp =
false, HasFPROp =
false;
8278 const LLT &Ty = MRI.
getType(MO.getReg());
8288 if (RB->
getID() == AArch64::GPRRegBankID)
8294 if (HasGPROp && HasFPROp)
8300InstructionSelector *
8304 return new AArch64InstructionSelector(TM, Subtarget, RBI);
MachineInstrBuilder MachineInstrBuilder & DefMI
static std::tuple< SDValue, SDValue > extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG)
static bool isPreferredADD(int64_t ImmOff)
static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue CCOp, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, const SDLoc &DL, SelectionDAG &DAG)
can be transformed to: not (and (not (and (setCC (cmp C)) (setCD (cmp D)))) (and (not (setCA (cmp A))...
static SDValue tryAdvSIMDModImm16(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue tryAdvSIMDModImmFP(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue tryAdvSIMDModImm64(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG)
static SDValue tryAdvSIMDModImm8(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp, AArch64CC::CondCode Predicate)
Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain of CCMP/CFCMP ops.
static SDValue tryAdvSIMDModImm321s(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits)
static void changeFPCCToANDAArch64CC(ISD::CondCode CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert a DAG fp condition code to an AArch64 CC.
static bool canEmitConjunction(SelectionDAG &DAG, const SDValue Val, bool &CanNegate, bool &MustBeFirst, bool &PreferFirst, bool WillNegate, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/SETCC operations that can be expressed as a conjunction.
static SDValue tryAdvSIMDModImm32(unsigned NewOp, SDValue Op, SelectionDAG &DAG, const APInt &Bits, const SDValue *LHS=nullptr)
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val, AArch64CC::CondCode &OutCC)
Emit expression as a conjunction (a series of CCMP/CFCMP ops).
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert, MachineRegisterInfo &MRI)
Return a register which can be used as a bit to test in a TB(N)Z.
static unsigned getMinSizeForRegBank(const RegisterBank &RB)
Returns the minimum size the given register bank can hold.
static std::optional< int64_t > getVectorShiftImm(Register Reg, MachineRegisterInfo &MRI)
Returns the element immediate value of a vector shift operand if found.
static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the G_LOAD or G_STORE operation GenericOpc, appropriate for the (value)...
static const TargetRegisterClass * getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits, bool GetAllRegSet=false)
Given a register bank, and size in bits, return the smallest register class that can represent that c...
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc, appropriate for the register ban...
static bool getSubRegForClass(const TargetRegisterClass *RC, const TargetRegisterInfo &TRI, unsigned &SubReg)
Returns the correct subregister to use for a given register class.
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI, Register SrcReg, const TargetRegisterClass *To, unsigned SubReg)
Helper function for selectCopy.
static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P, Register RHS={}, MachineRegisterInfo *MRI=nullptr)
static Register createDTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of D-registers using the registers in Regs.
static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, const AArch64RegisterBankInfo &RBI)
static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI, const RegisterBankInfo &RBI)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg, const unsigned EltSize)
static Register createQTuple(ArrayRef< Register > Regs, MachineIRBuilder &MIB)
Create a tuple of Q-registers using the registers in Regs.
static std::optional< uint64_t > getImmedFromMO(const MachineOperand &Root)
static std::pair< unsigned, unsigned > getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize)
Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given size and RB.
static Register createTuple(ArrayRef< Register > Regs, const unsigned RegClassIDs[], const unsigned SubRegs[], MachineIRBuilder &MIB)
Create a REG_SEQUENCE instruction using the registers in Regs.
static std::optional< int64_t > getVectorSHLImm(LLT SrcTy, Register Reg, MachineRegisterInfo &MRI)
Matches and returns the shift immediate value for a SHL instruction given a shift operand.
static void changeFPCCToORAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares the targeting of the RegisterBankInfo class for AArch64.
static bool isStore(int Opcode)
static bool selectMergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file contains constants used for implementing Dwarf debug support.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static MachineBasicBlock * emitSelect(MachineInstr &MI, MachineBasicBlock *BB, const TargetInstrInfo *TII, const PPCSubtarget &Subtarget)
Emit SELECT instruction, using ISEL if available, otherwise use branch-based control flow.
static StringRef getName(Value *V)
static constexpr int Concat[]
unsigned getVarArgsFPRSize() const
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isTargetDarwin() const
bool isTargetILP32() const
std::optional< uint16_t > getPtrAuthBlockAddressDiscriminatorIfEnabled(const Function &ParentFn) const
Compute the integer discriminator for a given BlockAddress constant, if blockaddress signing is enabl...
const AArch64TargetLowering * getTargetLowering() const override
bool isTargetMachO() const
unsigned ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const
ClassifyGlobalReference - Find the target operand flags that describe how a global value should be re...
bool isLittleEndian() const
bool isX16X17Safer() const
Returns whether the operating system makes it safer to store sensitive values in x16 and x17 as oppos...
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
const APFloat & getValueAPF() const
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
virtual void setupMF(MachineFunction &mf, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
Represents indexed stores.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getCondReg() const
Register getFalseReg() const
Register getTrueReg() const
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
bool hasExternalWeakLinkage() const
bool isEquality() const
Return true if this predicate is either EQ or NE.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
constexpr bool isPointerVector() const
constexpr bool isInteger() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
TypeSize getValue() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
void setAdjustsStack(bool V)
void setFrameAddressIsTaken(bool T)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
void setState(const MachineIRBuilderState &NewState)
Setter for the State.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
Register getReg(unsigned Idx) const
Get the register for the operand index.
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addRegMask(const uint32_t *Mask) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
AtomicOrdering getSuccessOrdering() const
Return the atomic ordering requirements for this memory operation.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToImmediate(int64_t ImmVal, unsigned TargetFlags=0)
ChangeToImmediate - Replace this operand with a new immediate operand of the specified value.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
static MachineOperand CreatePredicate(unsigned Pred)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
static MachineOperand CreateBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
const ConstantFP * getFPImm() const
unsigned getPredicate() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
def_instr_iterator def_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
const RegisterBank * getRegBankOrNull(Register Reg) const
Return the register bank of Reg, or null if Reg has not been assigned a register bank or has been ass...
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
Analysis providing profile information.
Holds all the information related to register banks.
static const TargetRegisterClass * constrainGenericRegister(Register Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI)
Constrain the (possibly generic) virtual register Reg to RC.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
TypeSize getSizeInBits(Register Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const
Get the size in bits of Reg.
This class implements the register bank concept.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
bool isPositionIndependent() const
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static CondCode getInvertedCondCode(CondCode Code)
static unsigned getNZCVToSatisfyCondCode(CondCode Code)
Given a condition code, return NZCV flags that would satisfy that condition.
void changeFCMPPredToAArch64CC(const CmpInst::Predicate P, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Find the AArch64 condition codes necessary to represent P for a scalar floating point comparison.
std::optional< int64_t > getAArch64VectorSplatScalar(const MachineInstr &MI, const MachineRegisterInfo &MRI)
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_G1
MO_G1 - A symbol operand with this flag (granule 1) represents the bits 16-31 of a 64-bit address,...
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_GOT
MO_GOT - This flag indicates that a symbol operand represents the address of the GOT entry for the sy...
@ MO_G0
MO_G0 - A symbol operand with this flag (granule 0) represents the bits 0-15 of a 64-bit address,...
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_TLS
MO_TLS - Indicates that the operand being accessed is some kind of thread-local symbol.
@ MO_G2
MO_G2 - A symbol operand with this flag (granule 2) represents the bits 32-47 of a 64-bit address,...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint8_t encodeAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType9(uint64_t Imm)
static bool isAdvSIMDModImmType4(uint64_t Imm)
static bool isAdvSIMDModImmType5(uint64_t Imm)
static int getFP32Imm(const APInt &Imm)
getFP32Imm - Return an 8-bit floating-point version of the 32-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType10(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType9(uint64_t Imm)
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
static bool isAdvSIMDModImmType7(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType5(uint64_t Imm)
static int getFP64Imm(const APInt &Imm)
getFP64Imm - Return an 8-bit floating-point version of the 64-bit floating-point value.
static bool isAdvSIMDModImmType10(uint64_t Imm)
static int getFP16Imm(const APInt &Imm)
getFP16Imm - Return an 8-bit floating-point version of the 16-bit floating-point value.
static uint8_t encodeAdvSIMDModImmType8(uint64_t Imm)
static bool isAdvSIMDModImmType12(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType11(uint64_t Imm)
static bool isAdvSIMDModImmType11(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType6(uint64_t Imm)
static bool isAdvSIMDModImmType8(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType4(uint64_t Imm)
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
static bool isAdvSIMDModImmType6(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType1(uint64_t Imm)
static uint8_t encodeAdvSIMDModImmType3(uint64_t Imm)
static bool isAdvSIMDModImmType2(uint64_t Imm)
static bool isAdvSIMDModImmType3(uint64_t Imm)
static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
isSignExtendShiftType - Returns true if Type is sign extending.
static bool isAdvSIMDModImmType1(uint64_t Imm)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
auto m_PosZeroFP()
Matches a floating-point positive zero.
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI Register constrainOperandRegClass(const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, const RegisterBankInfo &RBI, MachineInstr &InsertPt, const TargetRegisterClass &RegClass, MachineOperand &RegMO)
Constrain the Register operand OpIdx, so that it is now constrained to the TargetRegisterClass passed...
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
unsigned CheckFixedPointOperandConstant(APFloat &FVal, unsigned RegWidth, bool isReciprocal)
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isStrongerThanMonotonic(AtomicOrdering AO)
LLVM_ABI void constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
unsigned getBLRCallOpcode(const MachineFunction &MF)
Return opcode to be used for indirect calls.
@ O1
Optimize quickly without destroying debuggability.
@ O0
Disable as many optimizations as possible.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &, const AArch64Subtarget &, const AArch64RegisterBankInfo &)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.