44#include "llvm/IR/IntrinsicsAArch64.h"
51#define DEBUG_TYPE "aarch64-isel"
54using namespace MIPatternMatch;
55using namespace AArch64GISelUtils;
64#define GET_GLOBALISEL_PREDICATE_BITSET
65#include "AArch64GenGlobalISel.inc"
66#undef GET_GLOBALISEL_PREDICATE_BITSET
81 InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
86 ProduceNonFlagSettingCondBr =
134 bool tryOptAndIntoCompareBranch(
MachineInstr &AndInst,
bool Invert,
212 bool selectVectorLoadIntrinsic(
unsigned Opc,
unsigned NumVecs,
214 bool selectVectorLoadLaneIntrinsic(
unsigned Opc,
unsigned NumVecs,
216 void selectVectorStoreIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
218 bool selectVectorStoreLaneIntrinsic(
MachineInstr &
I,
unsigned NumVecs,
232 unsigned Opc1,
unsigned Opc2,
bool isExt);
238 unsigned emitConstantPoolEntry(
const Constant *CPVal,
257 std::optional<CmpInst::Predicate> = std::nullopt)
const;
260 emitInstr(
unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
261 std::initializer_list<llvm::SrcOp> SrcOps,
263 const ComplexRendererFns &RenderFns = std::nullopt)
const;
298 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
319 MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
341 std::pair<MachineInstr *, AArch64CC::CondCode>
376 ComplexRendererFns selectShiftA_32(
const MachineOperand &Root)
const;
377 ComplexRendererFns selectShiftB_32(
const MachineOperand &Root)
const;
378 ComplexRendererFns selectShiftA_64(
const MachineOperand &Root)
const;
379 ComplexRendererFns selectShiftB_64(
const MachineOperand &Root)
const;
381 ComplexRendererFns select12BitValueWithLeftShift(
uint64_t Immed)
const;
383 ComplexRendererFns selectNegArithImmed(
MachineOperand &Root)
const;
386 unsigned Size)
const;
388 ComplexRendererFns selectAddrModeUnscaled8(
MachineOperand &Root)
const {
389 return selectAddrModeUnscaled(Root, 1);
391 ComplexRendererFns selectAddrModeUnscaled16(
MachineOperand &Root)
const {
392 return selectAddrModeUnscaled(Root, 2);
394 ComplexRendererFns selectAddrModeUnscaled32(
MachineOperand &Root)
const {
395 return selectAddrModeUnscaled(Root, 4);
397 ComplexRendererFns selectAddrModeUnscaled64(
MachineOperand &Root)
const {
398 return selectAddrModeUnscaled(Root, 8);
400 ComplexRendererFns selectAddrModeUnscaled128(
MachineOperand &Root)
const {
401 return selectAddrModeUnscaled(Root, 16);
406 ComplexRendererFns tryFoldAddLowIntoImm(
MachineInstr &RootDef,
unsigned Size,
410 unsigned Size)
const;
412 ComplexRendererFns selectAddrModeIndexed(
MachineOperand &Root)
const {
413 return selectAddrModeIndexed(Root, Width / 8);
422 bool IsAddrOperand)
const;
425 unsigned SizeInBytes)
const;
433 bool WantsExt)
const;
434 ComplexRendererFns selectAddrModeRegisterOffset(
MachineOperand &Root)
const;
436 unsigned SizeInBytes)
const;
438 ComplexRendererFns selectAddrModeXRO(
MachineOperand &Root)
const {
439 return selectAddrModeXRO(Root, Width / 8);
443 unsigned SizeInBytes)
const;
445 ComplexRendererFns selectAddrModeWRO(
MachineOperand &Root)
const {
446 return selectAddrModeWRO(Root, Width / 8);
450 bool AllowROR =
false)
const;
452 ComplexRendererFns selectArithShiftedRegister(
MachineOperand &Root)
const {
453 return selectShiftedRegister(Root);
456 ComplexRendererFns selectLogicalShiftedRegister(
MachineOperand &Root)
const {
457 return selectShiftedRegister(Root,
true);
467 bool IsLoadStore =
false)
const;
478 ComplexRendererFns selectArithExtendedRegister(
MachineOperand &Root)
const;
483 int OpIdx = -1)
const;
485 int OpIdx = -1)
const;
487 int OpIdx = -1)
const;
491 int OpIdx = -1)
const;
493 int OpIdx = -1)
const;
495 int OpIdx = -1)
const;
498 int OpIdx = -1)
const;
504 bool tryOptSelect(
GSelect &Sel);
511 bool isLoadStoreOfNumBytes(
const MachineInstr &
MI,
unsigned NumBytes)
const;
524 bool ProduceNonFlagSettingCondBr =
false;
533#define GET_GLOBALISEL_PREDICATES_DECL
534#include "AArch64GenGlobalISel.inc"
535#undef GET_GLOBALISEL_PREDICATES_DECL
539#define GET_GLOBALISEL_TEMPORARIES_DECL
540#include "AArch64GenGlobalISel.inc"
541#undef GET_GLOBALISEL_TEMPORARIES_DECL
546#define GET_GLOBALISEL_IMPL
547#include "AArch64GenGlobalISel.inc"
548#undef GET_GLOBALISEL_IMPL
550AArch64InstructionSelector::AArch64InstructionSelector(
553 : TM(TM), STI(STI),
TII(*STI.getInstrInfo()),
TRI(*STI.getRegisterInfo()),
556#include
"AArch64GenGlobalISel.inc"
559#include
"AArch64GenGlobalISel.inc"
571 bool GetAllRegSet =
false) {
572 if (RB.
getID() == AArch64::GPRRegBankID) {
574 return GetAllRegSet ? &AArch64::GPR32allRegClass
575 : &AArch64::GPR32RegClass;
577 return GetAllRegSet ? &AArch64::GPR64allRegClass
578 : &AArch64::GPR64RegClass;
580 return &AArch64::XSeqPairsClassRegClass;
584 if (RB.
getID() == AArch64::FPRRegBankID) {
587 return &AArch64::FPR8RegClass;
589 return &AArch64::FPR16RegClass;
591 return &AArch64::FPR32RegClass;
593 return &AArch64::FPR64RegClass;
595 return &AArch64::FPR128RegClass;
607 bool GetAllRegSet =
false) {
610 "Expected FPR regbank for scalable type size");
611 return &AArch64::ZPRRegClass;
614 unsigned RegBankID = RB.
getID();
616 if (RegBankID == AArch64::GPRRegBankID) {
618 if (SizeInBits <= 32)
619 return GetAllRegSet ? &AArch64::GPR32allRegClass
620 : &AArch64::GPR32RegClass;
621 if (SizeInBits == 64)
622 return GetAllRegSet ? &AArch64::GPR64allRegClass
623 : &AArch64::GPR64RegClass;
624 if (SizeInBits == 128)
625 return &AArch64::XSeqPairsClassRegClass;
628 if (RegBankID == AArch64::FPRRegBankID) {
631 "Unexpected scalable register size");
632 return &AArch64::ZPRRegClass;
635 switch (SizeInBits) {
639 return &AArch64::FPR8RegClass;
641 return &AArch64::FPR16RegClass;
643 return &AArch64::FPR32RegClass;
645 return &AArch64::FPR64RegClass;
647 return &AArch64::FPR128RegClass;
657 switch (
TRI.getRegSizeInBits(*RC)) {
665 if (RC != &AArch64::FPR32RegClass)
675 dbgs() <<
"Couldn't find appropriate subregister for register class.");
684 switch (RB.
getID()) {
685 case AArch64::GPRRegBankID:
687 case AArch64::FPRRegBankID:
710 const unsigned RegClassIDs[],
712 unsigned NumRegs = Regs.
size();
715 assert(NumRegs >= 2 && NumRegs <= 4 &&
716 "Only support between two and 4 registers in a tuple!");
718 auto *DesiredClass =
TRI->getRegClass(RegClassIDs[NumRegs - 2]);
720 MIB.
buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
721 for (
unsigned I = 0, E = Regs.
size();
I < E; ++
I) {
722 RegSequence.addUse(Regs[
I]);
723 RegSequence.addImm(SubRegs[
I]);
725 return RegSequence.getReg(0);
730 static const unsigned RegClassIDs[] = {
731 AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
732 static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
733 AArch64::dsub2, AArch64::dsub3};
734 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
739 static const unsigned RegClassIDs[] = {
740 AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
741 static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
742 AArch64::qsub2, AArch64::qsub3};
743 return createTuple(Regs, RegClassIDs, SubRegs, MIB);
748 auto &
MBB = *
MI.getParent();
750 auto &
MRI = MF.getRegInfo();
756 else if (Root.
isReg()) {
761 Immed = ValAndVReg->Value.getSExtValue();
777 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
784 for (
auto &MO :
I.operands()) {
787 LLVM_DEBUG(
dbgs() <<
"Generic inst non-reg operands are unsupported\n");
795 if (!MO.getReg().isVirtual()) {
796 LLVM_DEBUG(
dbgs() <<
"Generic inst has physical register operand\n");
806 if (PrevOpBank && OpBank != PrevOpBank) {
807 LLVM_DEBUG(
dbgs() <<
"Generic inst operands have different banks\n");
822 case AArch64::GPRRegBankID:
824 switch (GenericOpc) {
825 case TargetOpcode::G_SHL:
826 return AArch64::LSLVWr;
827 case TargetOpcode::G_LSHR:
828 return AArch64::LSRVWr;
829 case TargetOpcode::G_ASHR:
830 return AArch64::ASRVWr;
834 }
else if (OpSize == 64) {
835 switch (GenericOpc) {
836 case TargetOpcode::G_PTR_ADD:
837 return AArch64::ADDXrr;
838 case TargetOpcode::G_SHL:
839 return AArch64::LSLVXr;
840 case TargetOpcode::G_LSHR:
841 return AArch64::LSRVXr;
842 case TargetOpcode::G_ASHR:
843 return AArch64::ASRVXr;
849 case AArch64::FPRRegBankID:
852 switch (GenericOpc) {
853 case TargetOpcode::G_FADD:
854 return AArch64::FADDSrr;
855 case TargetOpcode::G_FSUB:
856 return AArch64::FSUBSrr;
857 case TargetOpcode::G_FMUL:
858 return AArch64::FMULSrr;
859 case TargetOpcode::G_FDIV:
860 return AArch64::FDIVSrr;
865 switch (GenericOpc) {
866 case TargetOpcode::G_FADD:
867 return AArch64::FADDDrr;
868 case TargetOpcode::G_FSUB:
869 return AArch64::FSUBDrr;
870 case TargetOpcode::G_FMUL:
871 return AArch64::FMULDrr;
872 case TargetOpcode::G_FDIV:
873 return AArch64::FDIVDrr;
874 case TargetOpcode::G_OR:
875 return AArch64::ORRv8i8;
892 const bool isStore = GenericOpc == TargetOpcode::G_STORE;
894 case AArch64::GPRRegBankID:
897 return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
899 return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
901 return isStore ? AArch64::STRWui : AArch64::LDRWui;
903 return isStore ? AArch64::STRXui : AArch64::LDRXui;
906 case AArch64::FPRRegBankID:
909 return isStore ? AArch64::STRBui : AArch64::LDRBui;
911 return isStore ? AArch64::STRHui : AArch64::LDRHui;
913 return isStore ? AArch64::STRSui : AArch64::LDRSui;
915 return isStore ? AArch64::STRDui : AArch64::LDRDui;
917 return isStore ? AArch64::STRQui : AArch64::LDRQui;
931 assert(SrcReg.
isValid() &&
"Expected a valid source register?");
932 assert(To &&
"Destination register class cannot be null");
939 RegOp.
setReg(SubRegCopy.getReg(0));
943 if (!
I.getOperand(0).getReg().isPhysical())
953static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
957 Register DstReg =
I.getOperand(0).getReg();
958 Register SrcReg =
I.getOperand(1).getReg();
973 if (SrcRegBank != DstRegBank &&
992 if (Reg.isPhysical())
994 LLT Ty =
MRI.getType(Reg);
997 dyn_cast<const TargetRegisterClass *>(RegClassOrBank);
999 const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
1000 RC = getRegClassForTypeOnBank(Ty, RB);
1003 dbgs() <<
"Warning: DBG_VALUE operand has unexpected size/bank\n");
1016 Register DstReg =
I.getOperand(0).getReg();
1017 Register SrcReg =
I.getOperand(1).getReg();
1036 LLVM_DEBUG(
dbgs() <<
"Couldn't determine source register class\n");
1040 const TypeSize SrcSize =
TRI.getRegSizeInBits(*SrcRC);
1041 const TypeSize DstSize =
TRI.getRegSizeInBits(*DstRC);
1052 auto Copy = MIB.
buildCopy({DstTempRC}, {SrcReg});
1054 }
else if (SrcSize > DstSize) {
1061 }
else if (DstSize > SrcSize) {
1068 Register PromoteReg =
MRI.createVirtualRegister(PromotionRC);
1070 TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
1075 RegOp.
setReg(PromoteReg);
1094 if (
I.getOpcode() == TargetOpcode::G_ZEXT) {
1095 I.setDesc(
TII.get(AArch64::COPY));
1096 assert(SrcRegBank.
getID() == AArch64::GPRRegBankID);
1100 I.setDesc(
TII.get(AArch64::COPY));
1115 switch (GenericOpc) {
1116 case TargetOpcode::G_SITOFP:
1117 return AArch64::SCVTFUWSri;
1118 case TargetOpcode::G_UITOFP:
1119 return AArch64::UCVTFUWSri;
1120 case TargetOpcode::G_FPTOSI:
1121 return AArch64::FCVTZSUWSr;
1122 case TargetOpcode::G_FPTOUI:
1123 return AArch64::FCVTZUUWSr;
1128 switch (GenericOpc) {
1129 case TargetOpcode::G_SITOFP:
1130 return AArch64::SCVTFUXSri;
1131 case TargetOpcode::G_UITOFP:
1132 return AArch64::UCVTFUXSri;
1133 case TargetOpcode::G_FPTOSI:
1134 return AArch64::FCVTZSUWDr;
1135 case TargetOpcode::G_FPTOUI:
1136 return AArch64::FCVTZUUWDr;
1146 switch (GenericOpc) {
1147 case TargetOpcode::G_SITOFP:
1148 return AArch64::SCVTFUWDri;
1149 case TargetOpcode::G_UITOFP:
1150 return AArch64::UCVTFUWDri;
1151 case TargetOpcode::G_FPTOSI:
1152 return AArch64::FCVTZSUXSr;
1153 case TargetOpcode::G_FPTOUI:
1154 return AArch64::FCVTZUUXSr;
1159 switch (GenericOpc) {
1160 case TargetOpcode::G_SITOFP:
1161 return AArch64::SCVTFUXDri;
1162 case TargetOpcode::G_UITOFP:
1163 return AArch64::UCVTFUXDri;
1164 case TargetOpcode::G_FPTOSI:
1165 return AArch64::FCVTZSUXDr;
1166 case TargetOpcode::G_FPTOUI:
1167 return AArch64::FCVTZUUXDr;
1186 RBI.getRegBank(True,
MRI,
TRI)->getID() &&
1187 "Expected both select operands to have the same regbank?");
1188 LLT Ty =
MRI.getType(True);
1193 "Expected 32 bit or 64 bit select only?");
1194 const bool Is32Bit =
Size == 32;
1195 if (RBI.getRegBank(True,
MRI,
TRI)->getID() != AArch64::GPRRegBankID) {
1196 unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1197 auto FCSel = MIB.
buildInstr(Opc, {Dst}, {True, False}).addImm(
CC);
1203 unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1205 auto TryFoldBinOpIntoSelect = [&Opc, Is32Bit, &
CC, &
MRI,
1220 Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1237 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1256 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1272 auto TryOptSelectCst = [&Opc, &True, &False, &
CC, Is32Bit, &
MRI,
1278 if (!TrueCst && !FalseCst)
1281 Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1282 if (TrueCst && FalseCst) {
1283 int64_t
T = TrueCst->Value.getSExtValue();
1284 int64_t
F = FalseCst->Value.getSExtValue();
1286 if (
T == 0 &&
F == 1) {
1288 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1294 if (
T == 0 &&
F == -1) {
1296 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1304 int64_t
T = TrueCst->Value.getSExtValue();
1307 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1316 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1325 int64_t
F = FalseCst->Value.getSExtValue();
1328 Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1335 Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1343 Optimized |= TryFoldBinOpIntoSelect(False, True,
false);
1344 Optimized |= TryFoldBinOpIntoSelect(True, False,
true);
1465 assert(Reg.isValid() &&
"Expected valid register!");
1466 bool HasZext =
false;
1468 unsigned Opc =
MI->getOpcode();
1470 if (!
MI->getOperand(0).isReg() ||
1471 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1478 if (Opc == TargetOpcode::G_ANYEXT || Opc == TargetOpcode::G_ZEXT ||
1479 Opc == TargetOpcode::G_TRUNC) {
1480 if (Opc == TargetOpcode::G_ZEXT)
1483 Register NextReg =
MI->getOperand(1).getReg();
1485 if (!NextReg.
isValid() || !
MRI.hasOneNonDBGUse(NextReg))
1494 std::optional<uint64_t>
C;
1499 case TargetOpcode::G_AND:
1500 case TargetOpcode::G_XOR: {
1501 TestReg =
MI->getOperand(1).getReg();
1502 Register ConstantReg =
MI->getOperand(2).getReg();
1513 C = VRegAndVal->Value.getZExtValue();
1515 C = VRegAndVal->Value.getSExtValue();
1519 case TargetOpcode::G_ASHR:
1520 case TargetOpcode::G_LSHR:
1521 case TargetOpcode::G_SHL: {
1522 TestReg =
MI->getOperand(1).getReg();
1526 C = VRegAndVal->Value.getSExtValue();
1538 unsigned TestRegSize =
MRI.getType(TestReg).getSizeInBits();
1542 case TargetOpcode::G_AND:
1544 if ((*
C >> Bit) & 1)
1547 case TargetOpcode::G_SHL:
1550 if (*
C <= Bit && (Bit - *
C) < TestRegSize) {
1555 case TargetOpcode::G_ASHR:
1560 if (Bit >= TestRegSize)
1561 Bit = TestRegSize - 1;
1563 case TargetOpcode::G_LSHR:
1565 if ((Bit + *
C) < TestRegSize) {
1570 case TargetOpcode::G_XOR:
1579 if ((*
C >> Bit) & 1)
1598 assert(ProduceNonFlagSettingCondBr &&
1599 "Cannot emit TB(N)Z with speculation tracking!");
1604 LLT Ty =
MRI.getType(TestReg);
1607 assert(Bit < 64 &&
"Bit is too large!");
1611 bool UseWReg =
Bit < 32;
1612 unsigned NecessarySize = UseWReg ? 32 : 64;
1613 if (
Size != NecessarySize)
1614 TestReg = moveScalarRegClass(
1615 TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1618 static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
1619 {AArch64::TBZW, AArch64::TBNZW}};
1620 unsigned Opc = OpcTable[UseWReg][IsNegative];
1627bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1630 assert(AndInst.
getOpcode() == TargetOpcode::G_AND &&
"Expected G_AND only?");
1657 int32_t
Bit = MaybeBit->Value.exactLogBase2();
1664 emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
1672 assert(ProduceNonFlagSettingCondBr &&
"CBZ does not set flags!");
1674 assert(RBI.getRegBank(CompareReg,
MRI,
TRI)->getID() ==
1675 AArch64::GPRRegBankID &&
1676 "Expected GPRs only?");
1677 auto Ty =
MRI.getType(CompareReg);
1680 assert(Width <= 64 &&
"Expected width to be at most 64?");
1681 static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1682 {AArch64::CBNZW, AArch64::CBNZX}};
1683 unsigned Opc = OpcTable[IsNegative][Width == 64];
1684 auto BranchMI = MIB.
buildInstr(Opc, {}, {CompareReg}).addMBB(DestMBB);
1689bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1692 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1704 I.eraseFromParent();
1708bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1711 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1717 if (!ProduceNonFlagSettingCondBr)
1736 if (VRegAndVal && !AndInst) {
1737 int64_t
C = VRegAndVal->Value.getSExtValue();
1743 emitTestBit(LHS, Bit,
false, DestMBB, MIB);
1744 I.eraseFromParent();
1752 emitTestBit(LHS, Bit,
true, DestMBB, MIB);
1753 I.eraseFromParent();
1761 emitTestBit(LHS, Bit,
false, DestMBB, MIB);
1762 I.eraseFromParent();
1776 if (VRegAndVal && VRegAndVal->Value == 0) {
1784 tryOptAndIntoCompareBranch(
1786 I.eraseFromParent();
1791 auto LHSTy =
MRI.getType(LHS);
1792 if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1794 I.eraseFromParent();
1803bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1806 assert(
I.getOpcode() == TargetOpcode::G_BRCOND);
1807 if (tryOptCompareBranchFedByICmp(
I, ICmp, MIB))
1817 I.eraseFromParent();
1821bool AArch64InstructionSelector::selectCompareBranch(
1823 Register CondReg =
I.getOperand(0).getReg();
1828 if (CCMIOpc == TargetOpcode::G_FCMP)
1829 return selectCompareBranchFedByFCmp(
I, *CCMI, MIB);
1830 if (CCMIOpc == TargetOpcode::G_ICMP)
1831 return selectCompareBranchFedByICmp(
I, *CCMI, MIB);
1836 if (ProduceNonFlagSettingCondBr) {
1837 emitTestBit(CondReg, 0,
true,
1838 I.getOperand(1).getMBB(), MIB);
1839 I.eraseFromParent();
1849 .
addMBB(
I.getOperand(1).getMBB());
1850 I.eraseFromParent();
1858 assert(
MRI.getType(Reg).isVector() &&
"Expected a *vector* shift operand");
1869 return std::nullopt;
1871 int64_t Imm = *ShiftImm;
1873 return std::nullopt;
1877 return std::nullopt;
1880 return std::nullopt;
1884 return std::nullopt;
1888 return std::nullopt;
1892 return std::nullopt;
1898bool AArch64InstructionSelector::selectVectorSHL(
MachineInstr &
I,
1900 assert(
I.getOpcode() == TargetOpcode::G_SHL);
1901 Register DstReg =
I.getOperand(0).getReg();
1902 const LLT Ty =
MRI.getType(DstReg);
1903 Register Src1Reg =
I.getOperand(1).getReg();
1904 Register Src2Reg =
I.getOperand(2).getReg();
1915 Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1917 Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1919 Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1921 Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1923 Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1925 Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1927 Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
1933 auto Shl = MIB.
buildInstr(Opc, {DstReg}, {Src1Reg});
1939 I.eraseFromParent();
1943bool AArch64InstructionSelector::selectVectorAshrLshr(
1945 assert(
I.getOpcode() == TargetOpcode::G_ASHR ||
1946 I.getOpcode() == TargetOpcode::G_LSHR);
1947 Register DstReg =
I.getOperand(0).getReg();
1948 const LLT Ty =
MRI.getType(DstReg);
1949 Register Src1Reg =
I.getOperand(1).getReg();
1950 Register Src2Reg =
I.getOperand(2).getReg();
1955 bool IsASHR =
I.getOpcode() == TargetOpcode::G_ASHR;
1965 unsigned NegOpc = 0;
1967 getRegClassForTypeOnBank(Ty, RBI.getRegBank(AArch64::FPRRegBankID));
1969 Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
1970 NegOpc = AArch64::NEGv2i64;
1972 Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
1973 NegOpc = AArch64::NEGv4i32;
1975 Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
1976 NegOpc = AArch64::NEGv2i32;
1978 Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1979 NegOpc = AArch64::NEGv4i16;
1981 Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1982 NegOpc = AArch64::NEGv8i16;
1984 Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
1985 NegOpc = AArch64::NEGv16i8;
1987 Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1988 NegOpc = AArch64::NEGv8i8;
1994 auto Neg = MIB.
buildInstr(NegOpc, {RC}, {Src2Reg});
1996 auto SShl = MIB.
buildInstr(Opc, {DstReg}, {Src1Reg, Neg});
1998 I.eraseFromParent();
2002bool AArch64InstructionSelector::selectVaStartAAPCS(
2013 const unsigned PtrSize = STI.isTargetILP32() ? 4 : 8;
2014 const auto *PtrRegClass =
2015 STI.isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
2018 TII.get(STI.isTargetILP32() ? AArch64::ADDWri : AArch64::ADDXri);
2020 TII.get(STI.isTargetILP32() ? AArch64::STRWui : AArch64::STRXui);
2031 const auto VAList =
I.getOperand(0).getReg();
2034 unsigned OffsetBytes = 0;
2038 const auto PushAddress = [&](
const int FrameIndex,
const int64_t
Imm) {
2039 const Register Top =
MRI.createVirtualRegister(PtrRegClass);
2040 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDAddAddr)
2047 const auto *MMO = *
I.memoperands_begin();
2048 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(), MCIDStoreAddr)
2051 .
addImm(OffsetBytes / PtrSize)
2053 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2057 OffsetBytes += PtrSize;
2073 const auto PushIntConstant = [&](
const int32_t
Value) {
2074 constexpr int IntSize = 4;
2075 const Register Temp =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2077 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::MOVi32imm))
2082 const auto *MMO = *
I.memoperands_begin();
2083 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRWui))
2086 .
addImm(OffsetBytes / IntSize)
2088 MMO->getPointerInfo().getWithOffset(OffsetBytes),
2091 OffsetBytes += IntSize;
2095 PushIntConstant(-
static_cast<int32_t
>(GPRSize));
2098 PushIntConstant(-
static_cast<int32_t
>(FPRSize));
2100 assert(OffsetBytes == (STI.isTargetILP32() ? 20 : 32) &&
"Unexpected offset");
2102 I.eraseFromParent();
2106bool AArch64InstructionSelector::selectVaStartDarwin(
2109 Register ListReg =
I.getOperand(0).getReg();
2111 Register ArgsAddrReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2122 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::ADDXri))
2130 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::STRXui))
2137 I.eraseFromParent();
2141void AArch64InstructionSelector::materializeLargeCMVal(
2147 auto MovZ = MIB.
buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
2158 :
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
2160 if (
auto *GV = dyn_cast<GlobalValue>(V)) {
2162 GV, MovZ->getOperand(1).getOffset(), Flags));
2166 MovZ->getOperand(1).getOffset(), Flags));
2172 Register DstReg = BuildMovK(MovZ.getReg(0),
2178bool AArch64InstructionSelector::preISelLower(
MachineInstr &
I) {
2183 switch (
I.getOpcode()) {
2184 case TargetOpcode::G_STORE: {
2185 bool Changed = contractCrossBankCopyIntoStore(
I,
MRI);
2193 SrcOp.setReg(NewSrc);
2194 RBI.constrainGenericRegister(NewSrc, AArch64::GPR64RegClass,
MRI);
2199 case TargetOpcode::G_PTR_ADD:
2200 return convertPtrAddToAdd(
I,
MRI);
2201 case TargetOpcode::G_LOAD: {
2206 Register DstReg =
I.getOperand(0).getReg();
2207 const LLT DstTy =
MRI.getType(DstReg);
2213 case AArch64::G_DUP: {
2215 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2219 MRI.setType(
I.getOperand(0).getReg(),
2221 MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2222 I.getOperand(1).setReg(NewSrc.getReg(0));
2225 case AArch64::G_INSERT_VECTOR_ELT: {
2227 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2228 LLT SrcVecTy =
MRI.getType(
I.getOperand(1).getReg());
2232 MRI.setType(
I.getOperand(1).getReg(),
2234 MRI.setType(
I.getOperand(0).getReg(),
2236 MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2237 I.getOperand(2).setReg(NewSrc.getReg(0));
2240 case TargetOpcode::G_UITOFP:
2241 case TargetOpcode::G_SITOFP: {
2246 Register SrcReg =
I.getOperand(1).getReg();
2247 LLT SrcTy =
MRI.getType(SrcReg);
2248 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2252 if (RBI.getRegBank(SrcReg,
MRI,
TRI)->getID() == AArch64::FPRRegBankID) {
2253 if (
I.getOpcode() == TargetOpcode::G_SITOFP)
2254 I.setDesc(
TII.get(AArch64::G_SITOF));
2256 I.setDesc(
TII.get(AArch64::G_UITOF));
2274bool AArch64InstructionSelector::convertPtrAddToAdd(
2276 assert(
I.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
2277 Register DstReg =
I.getOperand(0).getReg();
2278 Register AddOp1Reg =
I.getOperand(1).getReg();
2279 const LLT PtrTy =
MRI.getType(DstReg);
2283 const LLT CastPtrTy =
2288 MRI.setRegBank(PtrToInt.getReg(0), RBI.getRegBank(AArch64::FPRRegBankID));
2290 MRI.setRegBank(PtrToInt.getReg(0), RBI.getRegBank(AArch64::GPRRegBankID));
2294 I.setDesc(
TII.get(TargetOpcode::G_ADD));
2295 MRI.setType(DstReg, CastPtrTy);
2296 I.getOperand(1).setReg(PtrToInt.getReg(0));
2297 if (!select(*PtrToInt)) {
2298 LLVM_DEBUG(
dbgs() <<
"Failed to select G_PTRTOINT in convertPtrAddToAdd");
2307 I.getOperand(2).setReg(NegatedReg);
2308 I.setDesc(
TII.get(TargetOpcode::G_SUB));
2312bool AArch64InstructionSelector::earlySelectSHL(
MachineInstr &
I,
2317 assert(
I.getOpcode() == TargetOpcode::G_SHL &&
"unexpected op");
2318 const auto &MO =
I.getOperand(2);
2323 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2327 auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
2328 auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
2330 if (!Imm1Fn || !Imm2Fn)
2334 MIB.
buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
2337 for (
auto &RenderFn : *Imm1Fn)
2339 for (
auto &RenderFn : *Imm2Fn)
2342 I.eraseFromParent();
2346bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
2348 assert(
I.getOpcode() == TargetOpcode::G_STORE &&
"Expected G_STORE");
2366 LLT DefDstTy =
MRI.getType(DefDstReg);
2367 Register StoreSrcReg =
I.getOperand(0).getReg();
2368 LLT StoreSrcTy =
MRI.getType(StoreSrcReg);
2379 if (RBI.getRegBank(StoreSrcReg,
MRI,
TRI) ==
2380 RBI.getRegBank(DefDstReg,
MRI,
TRI))
2384 I.getOperand(0).setReg(DefDstReg);
2388bool AArch64InstructionSelector::earlySelect(
MachineInstr &
I) {
2389 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2390 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2396 switch (
I.getOpcode()) {
2397 case AArch64::G_DUP: {
2400 Register Src =
I.getOperand(1).getReg();
2405 Register Dst =
I.getOperand(0).getReg();
2407 MRI.getType(Dst).getNumElements(),
2410 ValAndVReg->Value.trunc(
MRI.getType(Dst).getScalarSizeInBits())));
2411 if (!emitConstantVector(Dst, CV, MIB,
MRI))
2413 I.eraseFromParent();
2416 case TargetOpcode::G_SEXT:
2419 if (selectUSMovFromExtend(
I,
MRI))
2422 case TargetOpcode::G_BR:
2424 case TargetOpcode::G_SHL:
2425 return earlySelectSHL(
I,
MRI);
2426 case TargetOpcode::G_CONSTANT: {
2427 bool IsZero =
false;
2428 if (
I.getOperand(1).isCImm())
2429 IsZero =
I.getOperand(1).getCImm()->isZero();
2430 else if (
I.getOperand(1).isImm())
2431 IsZero =
I.getOperand(1).getImm() == 0;
2436 Register DefReg =
I.getOperand(0).getReg();
2437 LLT Ty =
MRI.getType(DefReg);
2439 I.getOperand(1).ChangeToRegister(AArch64::XZR,
false);
2440 RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass,
MRI);
2442 I.getOperand(1).ChangeToRegister(AArch64::WZR,
false);
2443 RBI.constrainGenericRegister(DefReg, AArch64::GPR32RegClass,
MRI);
2447 I.setDesc(
TII.get(TargetOpcode::COPY));
2451 case TargetOpcode::G_ADD: {
2460 Register AddDst =
I.getOperand(0).getReg();
2461 Register AddLHS =
I.getOperand(1).getReg();
2462 Register AddRHS =
I.getOperand(2).getReg();
2464 LLT Ty =
MRI.getType(AddLHS);
2473 if (!
MRI.hasOneNonDBGUse(Reg))
2487 MRI.getType(
Cmp->getOperand(2).getReg()).getSizeInBits() != 64)
2497 Cmp = MatchCmp(AddRHS);
2501 auto &PredOp =
Cmp->getOperand(1);
2506 emitIntegerCompare(
Cmp->getOperand(2),
2507 Cmp->getOperand(3), PredOp, MIB);
2508 emitCSINC(AddDst, AddLHS, AddLHS, InvCC, MIB);
2509 I.eraseFromParent();
2512 case TargetOpcode::G_OR: {
2516 Register Dst =
I.getOperand(0).getReg();
2517 LLT Ty =
MRI.getType(Dst);
2536 if (ShiftImm >
Size || ((1ULL << ShiftImm) - 1ULL) !=
uint64_t(MaskImm))
2539 int64_t Immr =
Size - ShiftImm;
2540 int64_t Imms =
Size - ShiftImm - 1;
2541 unsigned Opc =
Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2542 emitInstr(Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2543 I.eraseFromParent();
2546 case TargetOpcode::G_FENCE: {
2547 if (
I.getOperand(1).getImm() == 0)
2551 .
addImm(
I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
2552 I.eraseFromParent();
2561 assert(
I.getParent() &&
"Instruction should be in a basic block!");
2562 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
2569 if (Subtarget->requiresStrictAlign()) {
2571 LLVM_DEBUG(
dbgs() <<
"AArch64 GISel does not support strict-align yet\n");
2577 unsigned Opcode =
I.getOpcode();
2579 if (!
I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
2582 if (Opcode == TargetOpcode::LOAD_STACK_GUARD)
2585 if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
2586 const Register DefReg =
I.getOperand(0).getReg();
2587 const LLT DefTy =
MRI.getType(DefReg);
2590 MRI.getRegClassOrRegBank(DefReg);
2593 dyn_cast<const TargetRegisterClass *>(RegClassOrBank);
2599 const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank);
2600 DefRC = getRegClassForTypeOnBank(DefTy, RB);
2607 I.setDesc(
TII.get(TargetOpcode::PHI));
2609 return RBI.constrainGenericRegister(DefReg, *DefRC,
MRI);
2615 if (
I.isDebugInstr())
2622 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
2624 dbgs() <<
"Generic instruction has unexpected implicit operands\n");
2631 if (preISelLower(
I)) {
2632 Opcode =
I.getOpcode();
2643 if (selectImpl(
I, *CoverageInfo))
2647 I.getOperand(0).isReg() ?
MRI.getType(
I.getOperand(0).getReg()) :
LLT{};
2650 case TargetOpcode::G_SBFX:
2651 case TargetOpcode::G_UBFX: {
2652 static const unsigned OpcTable[2][2] = {
2653 {AArch64::UBFMWri, AArch64::UBFMXri},
2654 {AArch64::SBFMWri, AArch64::SBFMXri}};
2655 bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2657 unsigned Opc = OpcTable[IsSigned][
Size == 64];
2660 assert(Cst1 &&
"Should have gotten a constant for src 1?");
2663 assert(Cst2 &&
"Should have gotten a constant for src 2?");
2664 auto LSB = Cst1->Value.getZExtValue();
2665 auto Width = Cst2->Value.getZExtValue();
2667 MIB.
buildInstr(Opc, {
I.getOperand(0)}, {
I.getOperand(1)})
2669 .
addImm(LSB + Width - 1);
2670 I.eraseFromParent();
2673 case TargetOpcode::G_BRCOND:
2674 return selectCompareBranch(
I, MF,
MRI);
2676 case TargetOpcode::G_BRINDIRECT: {
2678 if (std::optional<uint16_t> BADisc =
2679 STI.getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn)) {
2683 MI.addReg(AArch64::XZR);
2684 I.eraseFromParent();
2687 I.setDesc(
TII.get(AArch64::BR));
2691 case TargetOpcode::G_BRJT:
2692 return selectBrJT(
I,
MRI);
2694 case AArch64::G_ADD_LOW: {
2700 if (BaseMI->
getOpcode() != AArch64::ADRP) {
2701 I.setDesc(
TII.get(AArch64::ADDXri));
2706 "Expected small code model");
2708 auto Op2 =
I.getOperand(2);
2709 auto MovAddr = MIB.
buildInstr(AArch64::MOVaddr, {
I.getOperand(0)}, {})
2710 .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
2711 Op1.getTargetFlags())
2713 Op2.getTargetFlags());
2714 I.eraseFromParent();
2718 case TargetOpcode::G_FCONSTANT:
2719 case TargetOpcode::G_CONSTANT: {
2720 const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
2729 const Register DefReg =
I.getOperand(0).getReg();
2730 const LLT DefTy =
MRI.getType(DefReg);
2736 if (Ty != s16 && Ty != s32 && Ty != s64 && Ty != s128) {
2738 <<
" constant, expected: " << s16 <<
" or " << s32
2739 <<
" or " << s64 <<
" or " << s128 <<
'\n');
2743 if (RB.
getID() != AArch64::FPRRegBankID) {
2745 <<
" constant on bank: " << RB
2746 <<
", expected: FPR\n");
2754 if (DefSize != 128 &&
I.getOperand(1).getFPImm()->isExactlyValue(0.0))
2758 if (Ty != p0 && Ty != s8 && Ty != s16) {
2760 <<
" constant, expected: " << s32 <<
", " << s64
2761 <<
", or " << p0 <<
'\n');
2765 if (RB.
getID() != AArch64::GPRRegBankID) {
2767 <<
" constant on bank: " << RB
2768 <<
", expected: GPR\n");
2781 bool OptForSize = shouldOptForSize(&MF);
2785 if (TLI->isFPImmLegal(
I.getOperand(1).getFPImm()->getValueAPF(),
2792 auto *FPImm =
I.getOperand(1).getFPImm();
2795 LLVM_DEBUG(
dbgs() <<
"Failed to load double constant pool entry\n");
2799 I.eraseFromParent();
2800 return RBI.constrainGenericRegister(DefReg, FPRRC,
MRI);
2804 assert((DefSize == 32 || DefSize == 64) &&
"Unexpected const def size");
2806 const Register DefGPRReg =
MRI.createVirtualRegister(
2807 DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
2813 if (!RBI.constrainGenericRegister(DefReg, FPRRC,
MRI)) {
2814 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_FCONSTANT def operand\n");
2822 }
else if (
I.getOperand(1).isCImm()) {
2823 uint64_t Val =
I.getOperand(1).getCImm()->getZExtValue();
2824 I.getOperand(1).ChangeToImmediate(Val);
2825 }
else if (
I.getOperand(1).isImm()) {
2826 uint64_t Val =
I.getOperand(1).getImm();
2827 I.getOperand(1).ChangeToImmediate(Val);
2830 const unsigned MovOpc =
2831 DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
2832 I.setDesc(
TII.get(MovOpc));
2836 case TargetOpcode::G_EXTRACT: {
2837 Register DstReg =
I.getOperand(0).getReg();
2838 Register SrcReg =
I.getOperand(1).getReg();
2839 LLT SrcTy =
MRI.getType(SrcReg);
2840 LLT DstTy =
MRI.getType(DstReg);
2852 unsigned Offset =
I.getOperand(2).getImm();
2861 if (SrcRB.
getID() == AArch64::GPRRegBankID) {
2863 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {})
2865 Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2867 AArch64::GPR64RegClass, NewI->getOperand(0));
2868 I.eraseFromParent();
2874 unsigned LaneIdx =
Offset / 64;
2876 DstReg, DstRB,
LLT::scalar(64), SrcReg, LaneIdx, MIB);
2879 I.eraseFromParent();
2883 I.setDesc(
TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
2889 "unexpected G_EXTRACT types");
2896 .addReg(DstReg, 0, AArch64::sub_32);
2897 RBI.constrainGenericRegister(
I.getOperand(0).getReg(),
2898 AArch64::GPR32RegClass,
MRI);
2899 I.getOperand(0).setReg(DstReg);
2904 case TargetOpcode::G_INSERT: {
2905 LLT SrcTy =
MRI.getType(
I.getOperand(2).getReg());
2906 LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
2913 I.setDesc(
TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
2914 unsigned LSB =
I.getOperand(3).getImm();
2915 unsigned Width =
MRI.getType(
I.getOperand(2).getReg()).getSizeInBits();
2916 I.getOperand(3).setImm((DstSize - LSB) % DstSize);
2921 "unexpected G_INSERT types");
2927 TII.get(AArch64::SUBREG_TO_REG))
2930 .
addUse(
I.getOperand(2).getReg())
2931 .
addImm(AArch64::sub_32);
2932 RBI.constrainGenericRegister(
I.getOperand(2).getReg(),
2933 AArch64::GPR32RegClass,
MRI);
2934 I.getOperand(2).setReg(SrcReg);
2938 case TargetOpcode::G_FRAME_INDEX: {
2945 I.setDesc(
TII.get(AArch64::ADDXri));
2954 case TargetOpcode::G_GLOBAL_VALUE: {
2957 if (
I.getOperand(1).isSymbol()) {
2958 OpFlags =
I.getOperand(1).getTargetFlags();
2962 GV =
I.getOperand(1).getGlobal();
2964 return selectTLSGlobalValue(
I,
MRI);
2965 OpFlags = STI.ClassifyGlobalReference(GV, TM);
2970 ? AArch64::LOADgotAUTH
2971 : AArch64::LOADgot));
2972 I.getOperand(1).setTargetFlags(OpFlags);
2974 !
TM.isPositionIndependent()) {
2976 materializeLargeCMVal(
I, GV, OpFlags);
2977 I.eraseFromParent();
2980 I.setDesc(
TII.get(AArch64::ADR));
2981 I.getOperand(1).setTargetFlags(OpFlags);
2983 I.setDesc(
TII.get(AArch64::MOVaddr));
2986 MIB.addGlobalAddress(GV,
I.getOperand(1).getOffset(),
2992 case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2993 return selectPtrAuthGlobalValue(
I,
MRI);
2995 case TargetOpcode::G_ZEXTLOAD:
2996 case TargetOpcode::G_LOAD:
2997 case TargetOpcode::G_STORE: {
2999 bool IsZExtLoad =
I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
3013 if (Order != AtomicOrdering::NotAtomic &&
3014 Order != AtomicOrdering::Unordered &&
3015 Order != AtomicOrdering::Monotonic) {
3016 assert(!isa<GZExtLoad>(LdSt));
3017 assert(MemSizeInBytes <= 8 &&
3018 "128-bit atomics should already be custom-legalized");
3020 if (isa<GLoad>(LdSt)) {
3021 static constexpr unsigned LDAPROpcodes[] = {
3022 AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
3023 static constexpr unsigned LDAROpcodes[] = {
3024 AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
3026 STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
3029 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
3031 static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
3032 AArch64::STLRW, AArch64::STLRX};
3034 if (
MRI.getType(ValReg).getSizeInBits() == 64 && MemSizeInBits != 64) {
3036 Register NewVal =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3037 MIB.
buildInstr(TargetOpcode::COPY, {NewVal}, {})
3038 .addReg(
I.getOperand(0).getReg(), 0, AArch64::sub_32);
3039 I.getOperand(0).setReg(NewVal);
3041 I.setDesc(
TII.get(Opcodes[
Log2_32(MemSizeInBytes)]));
3052 "Load/Store pointer operand isn't a GPR");
3053 assert(
MRI.getType(PtrReg).isPointer() &&
3054 "Load/Store pointer operand isn't a pointer");
3059 LLT ValTy =
MRI.getType(ValReg);
3063 if (isa<GStore>(LdSt) && ValTy.
getSizeInBits() > MemSizeInBits) {
3066 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3072 .addReg(ValReg, 0,
SubReg)
3074 RBI.constrainGenericRegister(Copy, *RC,
MRI);
3076 }
else if (isa<GLoad>(LdSt) && ValTy.
getSizeInBits() > MemSizeInBits) {
3079 if (RB.
getID() == AArch64::FPRRegBankID) {
3082 auto *RC = getRegClassForTypeOnBank(MemTy, RB);
3089 MRI.setRegBank(NewDst, RB);
3092 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
3096 auto SubRegRC = getRegClassForTypeOnBank(
MRI.getType(OldDst), RB);
3097 RBI.constrainGenericRegister(OldDst, *SubRegRC,
MRI);
3105 auto SelectLoadStoreAddressingMode = [&]() ->
MachineInstr * {
3106 bool IsStore = isa<GStore>(
I);
3107 const unsigned NewOpc =
3109 if (NewOpc ==
I.getOpcode())
3113 selectAddrModeIndexed(
I.getOperand(1), MemSizeInBytes);
3116 I.setDesc(
TII.get(NewOpc));
3122 auto NewInst = MIB.
buildInstr(NewOpc, {}, {},
I.getFlags());
3123 Register CurValReg =
I.getOperand(0).getReg();
3124 IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3125 NewInst.cloneMemRefs(
I);
3126 for (
auto &Fn : *AddrModeFns)
3128 I.eraseFromParent();
3137 if (Opcode == TargetOpcode::G_STORE) {
3140 if (CVal && CVal->Value == 0) {
3142 case AArch64::STRWui:
3143 case AArch64::STRHHui:
3144 case AArch64::STRBBui:
3145 LoadStore->getOperand(0).setReg(AArch64::WZR);
3147 case AArch64::STRXui:
3148 LoadStore->getOperand(0).setReg(AArch64::XZR);
3154 if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3155 ValTy ==
LLT::scalar(64) && MemSizeInBits == 32)) {
3158 if (
MRI.getType(
LoadStore->getOperand(0).getReg()).getSizeInBits() != 64)
3162 Register LdReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3167 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
3170 .
addImm(AArch64::sub_32);
3172 return RBI.constrainGenericRegister(DstReg, AArch64::GPR64allRegClass,
3178 case TargetOpcode::G_INDEXED_ZEXTLOAD:
3179 case TargetOpcode::G_INDEXED_SEXTLOAD:
3180 return selectIndexedExtLoad(
I,
MRI);
3181 case TargetOpcode::G_INDEXED_LOAD:
3182 return selectIndexedLoad(
I,
MRI);
3183 case TargetOpcode::G_INDEXED_STORE:
3184 return selectIndexedStore(cast<GIndexedStore>(
I),
MRI);
3186 case TargetOpcode::G_LSHR:
3187 case TargetOpcode::G_ASHR:
3188 if (
MRI.getType(
I.getOperand(0).getReg()).isVector())
3189 return selectVectorAshrLshr(
I,
MRI);
3191 case TargetOpcode::G_SHL:
3192 if (Opcode == TargetOpcode::G_SHL &&
3193 MRI.getType(
I.getOperand(0).getReg()).isVector())
3194 return selectVectorSHL(
I,
MRI);
3201 Register SrcReg =
I.getOperand(1).getReg();
3202 Register ShiftReg =
I.getOperand(2).getReg();
3203 const LLT ShiftTy =
MRI.getType(ShiftReg);
3204 const LLT SrcTy =
MRI.getType(SrcReg);
3209 auto Trunc = MIB.
buildInstr(TargetOpcode::COPY, {SrcTy}, {})
3210 .addReg(ShiftReg, 0, AArch64::sub_32);
3211 MRI.setRegBank(Trunc.getReg(0), RBI.getRegBank(AArch64::GPRRegBankID));
3212 I.getOperand(2).setReg(Trunc.getReg(0));
3216 case TargetOpcode::G_OR: {
3223 const Register DefReg =
I.getOperand(0).getReg();
3227 if (NewOpc ==
I.getOpcode())
3230 I.setDesc(
TII.get(NewOpc));
3238 case TargetOpcode::G_PTR_ADD: {
3239 emitADD(
I.getOperand(0).getReg(),
I.getOperand(1),
I.getOperand(2), MIB);
3240 I.eraseFromParent();
3244 case TargetOpcode::G_SADDE:
3245 case TargetOpcode::G_UADDE:
3246 case TargetOpcode::G_SSUBE:
3247 case TargetOpcode::G_USUBE:
3248 case TargetOpcode::G_SADDO:
3249 case TargetOpcode::G_UADDO:
3250 case TargetOpcode::G_SSUBO:
3251 case TargetOpcode::G_USUBO:
3252 return selectOverflowOp(
I,
MRI);
3254 case TargetOpcode::G_PTRMASK: {
3255 Register MaskReg =
I.getOperand(2).getReg();
3262 I.setDesc(
TII.get(AArch64::ANDXri));
3263 I.getOperand(2).ChangeToImmediate(
3268 case TargetOpcode::G_PTRTOINT:
3269 case TargetOpcode::G_TRUNC: {
3270 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3271 const LLT SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3273 const Register DstReg =
I.getOperand(0).getReg();
3274 const Register SrcReg =
I.getOperand(1).getReg();
3281 dbgs() <<
"G_TRUNC/G_PTRTOINT input/output on different banks\n");
3285 if (DstRB.
getID() == AArch64::GPRRegBankID) {
3294 if (!RBI.constrainGenericRegister(SrcReg, *SrcRC,
MRI) ||
3295 !RBI.constrainGenericRegister(DstReg, *DstRC,
MRI)) {
3296 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_TRUNC/G_PTRTOINT\n");
3300 if (DstRC == SrcRC) {
3302 }
else if (Opcode == TargetOpcode::G_TRUNC && DstTy ==
LLT::scalar(32) &&
3306 }
else if (DstRC == &AArch64::GPR32RegClass &&
3307 SrcRC == &AArch64::GPR64RegClass) {
3308 I.getOperand(1).setSubReg(AArch64::sub_32);
3311 dbgs() <<
"Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
3315 I.setDesc(
TII.get(TargetOpcode::COPY));
3317 }
else if (DstRB.
getID() == AArch64::FPRRegBankID) {
3320 I.setDesc(
TII.get(AArch64::XTNv4i16));
3330 I.eraseFromParent();
3335 if (Opcode == TargetOpcode::G_PTRTOINT) {
3336 assert(DstTy.
isVector() &&
"Expected an FPR ptrtoint to be a vector");
3337 I.setDesc(
TII.get(TargetOpcode::COPY));
3345 case TargetOpcode::G_ANYEXT: {
3346 if (selectUSMovFromExtend(
I,
MRI))
3349 const Register DstReg =
I.getOperand(0).getReg();
3350 const Register SrcReg =
I.getOperand(1).getReg();
3353 if (RBDst.
getID() != AArch64::GPRRegBankID) {
3355 <<
", expected: GPR\n");
3360 if (RBSrc.
getID() != AArch64::GPRRegBankID) {
3362 <<
", expected: GPR\n");
3366 const unsigned DstSize =
MRI.getType(DstReg).getSizeInBits();
3369 LLVM_DEBUG(
dbgs() <<
"G_ANYEXT operand has no size, not a gvreg?\n");
3373 if (DstSize != 64 && DstSize > 32) {
3375 <<
", expected: 32 or 64\n");
3381 Register ExtSrc =
MRI.createVirtualRegister(&AArch64::GPR64allRegClass);
3386 .
addImm(AArch64::sub_32);
3387 I.getOperand(1).setReg(ExtSrc);
3392 case TargetOpcode::G_ZEXT:
3393 case TargetOpcode::G_SEXT_INREG:
3394 case TargetOpcode::G_SEXT: {
3395 if (selectUSMovFromExtend(
I,
MRI))
3398 unsigned Opcode =
I.getOpcode();
3399 const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
3400 const Register DefReg =
I.getOperand(0).getReg();
3401 Register SrcReg =
I.getOperand(1).getReg();
3402 const LLT DstTy =
MRI.getType(DefReg);
3403 const LLT SrcTy =
MRI.getType(SrcReg);
3409 if (Opcode == TargetOpcode::G_SEXT_INREG)
3410 SrcSize =
I.getOperand(2).getImm();
3416 AArch64::GPRRegBankID &&
3417 "Unexpected ext regbank");
3430 RBI.getRegBank(SrcReg,
MRI,
TRI)->getID() == AArch64::GPRRegBankID;
3431 if (LoadMI && IsGPR) {
3433 unsigned BytesLoaded =
MemOp->getSize().getValue();
3440 if (IsGPR && SrcSize == 32 && DstSize == 64) {
3442 MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3443 const Register ZReg = AArch64::WZR;
3444 MIB.
buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3447 MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
3450 .
addImm(AArch64::sub_32);
3452 if (!RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass,
3454 LLVM_DEBUG(
dbgs() <<
"Failed to constrain G_ZEXT destination\n");
3458 if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass,
3464 I.eraseFromParent();
3469 if (DstSize == 64) {
3470 if (Opcode != TargetOpcode::G_SEXT_INREG) {
3472 if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass,
3478 SrcReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG,
3479 {&AArch64::GPR64RegClass}, {})
3486 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
3490 }
else if (DstSize <= 32) {
3491 ExtI = MIB.
buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
3500 I.eraseFromParent();
3504 case TargetOpcode::G_SITOFP:
3505 case TargetOpcode::G_UITOFP:
3506 case TargetOpcode::G_FPTOSI:
3507 case TargetOpcode::G_FPTOUI: {
3508 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg()),
3509 SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3511 if (NewOpc == Opcode)
3514 I.setDesc(
TII.get(NewOpc));
3521 case TargetOpcode::G_FREEZE:
3524 case TargetOpcode::G_INTTOPTR:
3529 case TargetOpcode::G_BITCAST:
3537 case TargetOpcode::G_SELECT: {
3538 auto &Sel = cast<GSelect>(
I);
3539 const Register CondReg = Sel.getCondReg();
3540 const Register TReg = Sel.getTrueReg();
3541 const Register FReg = Sel.getFalseReg();
3543 if (tryOptSelect(Sel))
3548 Register DeadVReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3549 auto TstMI = MIB.
buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
3552 if (!emitSelect(Sel.getReg(0), TReg, FReg,
AArch64CC::NE, MIB))
3554 Sel.eraseFromParent();
3557 case TargetOpcode::G_ICMP: {
3570 emitIntegerCompare(
I.getOperand(2),
I.getOperand(3),
I.getOperand(1), MIB);
3571 emitCSINC(
I.getOperand(0).getReg(), AArch64::WZR,
3572 AArch64::WZR, InvCC, MIB);
3573 I.eraseFromParent();
3577 case TargetOpcode::G_FCMP: {
3580 if (!emitFPCompare(
I.getOperand(2).getReg(),
I.getOperand(3).getReg(), MIB,
3582 !emitCSetForFCmp(
I.getOperand(0).getReg(), Pred, MIB))
3584 I.eraseFromParent();
3587 case TargetOpcode::G_VASTART:
3588 return STI.isTargetDarwin() ? selectVaStartDarwin(
I, MF,
MRI)
3589 : selectVaStartAAPCS(
I, MF,
MRI);
3590 case TargetOpcode::G_INTRINSIC:
3591 return selectIntrinsic(
I,
MRI);
3592 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
3593 return selectIntrinsicWithSideEffects(
I,
MRI);
3594 case TargetOpcode::G_IMPLICIT_DEF: {
3595 I.setDesc(
TII.get(TargetOpcode::IMPLICIT_DEF));
3596 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3597 const Register DstReg =
I.getOperand(0).getReg();
3600 RBI.constrainGenericRegister(DstReg, *DstRC,
MRI);
3603 case TargetOpcode::G_BLOCK_ADDR: {
3604 Function *BAFn =
I.getOperand(1).getBlockAddress()->getFunction();
3605 if (std::optional<uint16_t> BADisc =
3606 STI.getPtrAuthBlockAddressDiscriminatorIfEnabled(*BAFn)) {
3607 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3608 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3616 RBI.constrainGenericRegister(
I.getOperand(0).getReg(),
3617 AArch64::GPR64RegClass,
MRI);
3618 I.eraseFromParent();
3622 materializeLargeCMVal(
I,
I.getOperand(1).getBlockAddress(), 0);
3623 I.eraseFromParent();
3626 I.setDesc(
TII.get(AArch64::MOVaddrBA));
3627 auto MovMI =
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(AArch64::MOVaddrBA),
3628 I.getOperand(0).getReg())
3632 I.getOperand(1).getBlockAddress(), 0,
3634 I.eraseFromParent();
3638 case AArch64::G_DUP: {
3644 if (RBI.getRegBank(
I.getOperand(1).getReg(),
MRI,
TRI)->getID() !=
3645 AArch64::GPRRegBankID)
3647 LLT VecTy =
MRI.getType(
I.getOperand(0).getReg());
3649 I.setDesc(
TII.get(AArch64::DUPv8i8gpr));
3651 I.setDesc(
TII.get(AArch64::DUPv16i8gpr));
3653 I.setDesc(
TII.get(AArch64::DUPv4i16gpr));
3655 I.setDesc(
TII.get(AArch64::DUPv8i16gpr));
3660 case TargetOpcode::G_BUILD_VECTOR:
3661 return selectBuildVector(
I,
MRI);
3662 case TargetOpcode::G_MERGE_VALUES:
3664 case TargetOpcode::G_UNMERGE_VALUES:
3666 case TargetOpcode::G_SHUFFLE_VECTOR:
3667 return selectShuffleVector(
I,
MRI);
3668 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3669 return selectExtractElt(
I,
MRI);
3670 case TargetOpcode::G_CONCAT_VECTORS:
3671 return selectConcatVectors(
I,
MRI);
3672 case TargetOpcode::G_JUMP_TABLE:
3673 return selectJumpTable(
I,
MRI);
3674 case TargetOpcode::G_MEMCPY:
3675 case TargetOpcode::G_MEMCPY_INLINE:
3676 case TargetOpcode::G_MEMMOVE:
3677 case TargetOpcode::G_MEMSET:
3678 assert(STI.hasMOPS() &&
"Shouldn't get here without +mops feature");
3679 return selectMOPS(
I,
MRI);
3685bool AArch64InstructionSelector::selectAndRestoreState(
MachineInstr &
I) {
3692bool AArch64InstructionSelector::selectMOPS(
MachineInstr &GI,
3696 case TargetOpcode::G_MEMCPY:
3697 case TargetOpcode::G_MEMCPY_INLINE:
3698 Mopcode = AArch64::MOPSMemoryCopyPseudo;
3700 case TargetOpcode::G_MEMMOVE:
3701 Mopcode = AArch64::MOPSMemoryMovePseudo;
3703 case TargetOpcode::G_MEMSET:
3705 Mopcode = AArch64::MOPSMemorySetPseudo;
3714 const Register DstPtrCopy =
MRI.cloneVirtualRegister(DstPtr.getReg());
3715 const Register SrcValCopy =
MRI.cloneVirtualRegister(SrcOrVal.getReg());
3718 const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
3719 const auto &SrcValRegClass =
3720 IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
3723 RBI.constrainGenericRegister(DstPtrCopy, AArch64::GPR64commonRegClass,
MRI);
3724 RBI.constrainGenericRegister(SrcValCopy, SrcValRegClass,
MRI);
3725 RBI.constrainGenericRegister(SizeCopy, AArch64::GPR64RegClass,
MRI);
3735 Register DefDstPtr =
MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
3736 Register DefSize =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3738 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSize},
3739 {DstPtrCopy, SizeCopy, SrcValCopy});
3741 Register DefSrcPtr =
MRI.createVirtualRegister(&SrcValRegClass);
3742 MIB.
buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
3743 {DstPtrCopy, SrcValCopy, SizeCopy});
3752 assert(
I.getOpcode() == TargetOpcode::G_BRJT &&
"Expected G_BRJT");
3753 Register JTAddr =
I.getOperand(0).getReg();
3754 unsigned JTI =
I.getOperand(1).getIndex();
3763 if (STI.isTargetMachO()) {
3768 assert(STI.isTargetELF() &&
3769 "jump table hardening only supported on MachO/ELF");
3777 I.eraseFromParent();
3781 Register TargetReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
3782 Register ScratchReg =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
3784 auto JumpTableInst = MIB.
buildInstr(AArch64::JumpTableDest32,
3785 {TargetReg, ScratchReg}, {JTAddr,
Index})
3786 .addJumpTableIndex(JTI);
3788 MIB.
buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
3789 {
static_cast<int64_t
>(JTI)});
3791 MIB.
buildInstr(AArch64::BR, {}, {TargetReg});
3792 I.eraseFromParent();
3796bool AArch64InstructionSelector::selectJumpTable(
MachineInstr &
I,
3798 assert(
I.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
"Expected jump table");
3799 assert(
I.getOperand(1).isJTI() &&
"Jump table op should have a JTI!");
3801 Register DstReg =
I.getOperand(0).getReg();
3802 unsigned JTI =
I.getOperand(1).getIndex();
3805 MIB.
buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
3808 I.eraseFromParent();
3812bool AArch64InstructionSelector::selectTLSGlobalValue(
3814 if (!STI.isTargetMachO())
3819 const auto &GlobalOp =
I.getOperand(1);
3820 assert(GlobalOp.getOffset() == 0 &&
3821 "Shouldn't have an offset on TLS globals!");
3825 MIB.
buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
3828 auto Load = MIB.
buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3829 {LoadGOT.getReg(0)})
3840 assert(Opcode == AArch64::BLR);
3841 Opcode = AArch64::BLRAAZ;
3850 RBI.constrainGenericRegister(
I.getOperand(0).getReg(), AArch64::GPR64RegClass,
3852 I.eraseFromParent();
3856MachineInstr *AArch64InstructionSelector::emitScalarToVector(
3859 auto Undef = MIRBuilder.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
3861 auto BuildFn = [&](
unsigned SubregIndex) {
3865 .addImm(SubregIndex);
3873 return BuildFn(AArch64::bsub);
3875 return BuildFn(AArch64::hsub);
3877 return BuildFn(AArch64::ssub);
3879 return BuildFn(AArch64::dsub);
3886AArch64InstructionSelector::emitNarrowVector(
Register DstReg,
Register SrcReg,
3889 LLT DstTy =
MRI.getType(DstReg);
3891 getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(SrcReg,
MRI,
TRI));
3892 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
3899 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
3905 .addReg(SrcReg, 0,
SubReg);
3906 RBI.constrainGenericRegister(DstReg, *RC,
MRI);
3910bool AArch64InstructionSelector::selectMergeValues(
3912 assert(
I.getOpcode() == TargetOpcode::G_MERGE_VALUES &&
"unexpected opcode");
3913 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
3914 const LLT SrcTy =
MRI.getType(
I.getOperand(1).getReg());
3918 if (
I.getNumOperands() != 3)
3925 Register DstReg =
I.getOperand(0).getReg();
3926 Register Src1Reg =
I.getOperand(1).getReg();
3927 Register Src2Reg =
I.getOperand(2).getReg();
3928 auto Tmp = MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3929 MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3934 Src2Reg, 1, RB, MIB);
3939 I.eraseFromParent();
3943 if (RB.
getID() != AArch64::GPRRegBankID)
3949 auto *DstRC = &AArch64::GPR64RegClass;
3950 Register SubToRegDef =
MRI.createVirtualRegister(DstRC);
3952 TII.get(TargetOpcode::SUBREG_TO_REG))
3955 .
addUse(
I.getOperand(1).getReg())
3956 .
addImm(AArch64::sub_32);
3957 Register SubToRegDef2 =
MRI.createVirtualRegister(DstRC);
3960 TII.get(TargetOpcode::SUBREG_TO_REG))
3963 .
addUse(
I.getOperand(2).getReg())
3964 .
addImm(AArch64::sub_32);
3966 *
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(AArch64::BFMXri))
3967 .
addDef(
I.getOperand(0).getReg())
3975 I.eraseFromParent();
3980 const unsigned EltSize) {
3985 CopyOpc = AArch64::DUPi8;
3986 ExtractSubReg = AArch64::bsub;
3989 CopyOpc = AArch64::DUPi16;
3990 ExtractSubReg = AArch64::hsub;
3993 CopyOpc = AArch64::DUPi32;
3994 ExtractSubReg = AArch64::ssub;
3997 CopyOpc = AArch64::DUPi64;
3998 ExtractSubReg = AArch64::dsub;
4002 LLVM_DEBUG(
dbgs() <<
"Elt size '" << EltSize <<
"' unsupported.\n");
4008MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
4009 std::optional<Register> DstReg,
const RegisterBank &DstRB,
LLT ScalarTy,
4012 unsigned CopyOpc = 0;
4013 unsigned ExtractSubReg = 0;
4016 dbgs() <<
"Couldn't determine lane copy opcode for instruction.\n");
4021 getRegClassForTypeOnBank(ScalarTy, DstRB,
true);
4023 LLVM_DEBUG(
dbgs() <<
"Could not determine destination register class.\n");
4028 const LLT &VecTy =
MRI.getType(VecReg);
4030 getRegClassForTypeOnBank(VecTy, VecRB,
true);
4032 LLVM_DEBUG(
dbgs() <<
"Could not determine source register class.\n");
4039 DstReg =
MRI.createVirtualRegister(DstRC);
4042 auto Copy = MIRBuilder.
buildInstr(TargetOpcode::COPY, {*DstReg}, {})
4043 .addReg(VecReg, 0, ExtractSubReg);
4044 RBI.constrainGenericRegister(*DstReg, *DstRC,
MRI);
4053 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
4054 if (!ScalarToVector)
4060 MIRBuilder.
buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
4064 RBI.constrainGenericRegister(*DstReg, *DstRC,
MRI);
4068bool AArch64InstructionSelector::selectExtractElt(
4070 assert(
I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
4071 "unexpected opcode!");
4072 Register DstReg =
I.getOperand(0).getReg();
4073 const LLT NarrowTy =
MRI.getType(DstReg);
4074 const Register SrcReg =
I.getOperand(1).getReg();
4075 const LLT WideTy =
MRI.getType(SrcReg);
4078 "source register size too small!");
4079 assert(!NarrowTy.
isVector() &&
"cannot extract vector into vector!");
4083 assert(LaneIdxOp.
isReg() &&
"Lane index operand was not a register?");
4085 if (RBI.getRegBank(DstReg,
MRI,
TRI)->getID() != AArch64::FPRRegBankID) {
4094 unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
4098 MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
4103 I.eraseFromParent();
4107bool AArch64InstructionSelector::selectSplitVectorUnmerge(
4109 unsigned NumElts =
I.getNumOperands() - 1;
4110 Register SrcReg =
I.getOperand(NumElts).getReg();
4111 const LLT NarrowTy =
MRI.getType(
I.getOperand(0).getReg());
4112 const LLT SrcTy =
MRI.getType(SrcReg);
4114 assert(NarrowTy.
isVector() &&
"Expected an unmerge into vectors");
4116 LLVM_DEBUG(
dbgs() <<
"Unexpected vector type for vec split unmerge");
4123 *RBI.getRegBank(
I.getOperand(0).getReg(),
MRI,
TRI);
4124 for (
unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
4125 Register Dst =
I.getOperand(OpIdx).getReg();
4127 emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
4131 I.eraseFromParent();
4135bool AArch64InstructionSelector::selectUnmergeValues(
MachineInstr &
I,
4137 assert(
I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
4138 "unexpected opcode");
4141 if (RBI.getRegBank(
I.getOperand(0).getReg(),
MRI,
TRI)->getID() !=
4142 AArch64::FPRRegBankID ||
4143 RBI.getRegBank(
I.getOperand(1).getReg(),
MRI,
TRI)->getID() !=
4144 AArch64::FPRRegBankID) {
4145 LLVM_DEBUG(
dbgs() <<
"Unmerging vector-to-gpr and scalar-to-scalar "
4146 "currently unsupported.\n");
4152 unsigned NumElts =
I.getNumOperands() - 1;
4153 Register SrcReg =
I.getOperand(NumElts).getReg();
4154 const LLT NarrowTy =
MRI.getType(
I.getOperand(0).getReg());
4155 const LLT WideTy =
MRI.getType(SrcReg);
4158 "can only unmerge from vector or s128 types!");
4160 "source register size too small!");
4163 return selectSplitVectorUnmerge(
I,
MRI);
4167 unsigned CopyOpc = 0;
4168 unsigned ExtractSubReg = 0;
4179 unsigned NumInsertRegs = NumElts - 1;
4191 *RBI.getRegBank(SrcReg,
MRI,
TRI));
4195 assert(Found &&
"expected to find last operand's subeg idx");
4196 for (
unsigned Idx = 0;
Idx < NumInsertRegs; ++
Idx) {
4197 Register ImpDefReg =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
4199 *
BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(TargetOpcode::IMPLICIT_DEF),
4203 Register InsertReg =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
4206 TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
4223 Register CopyTo =
I.getOperand(0).getReg();
4224 auto FirstCopy = MIB.
buildInstr(TargetOpcode::COPY, {CopyTo}, {})
4225 .addReg(InsertRegs[0], 0, ExtractSubReg);
4229 unsigned LaneIdx = 1;
4230 for (
Register InsReg : InsertRegs) {
4231 Register CopyTo =
I.getOperand(LaneIdx).getReg();
4244 MRI.getRegClassOrNull(
I.getOperand(1).getReg());
4250 RBI.constrainGenericRegister(CopyTo, *RC,
MRI);
4251 I.eraseFromParent();
4255bool AArch64InstructionSelector::selectConcatVectors(
4257 assert(
I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
4258 "Unexpected opcode");
4259 Register Dst =
I.getOperand(0).getReg();
4260 Register Op1 =
I.getOperand(1).getReg();
4261 Register Op2 =
I.getOperand(2).getReg();
4262 MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
4265 I.eraseFromParent();
4270AArch64InstructionSelector::emitConstantPoolEntry(
const Constant *CPVal,
4279MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
4287 RC = &AArch64::FPR128RegClass;
4288 Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
4291 RC = &AArch64::FPR64RegClass;
4292 Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4295 RC = &AArch64::FPR32RegClass;
4296 Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
4299 RC = &AArch64::FPR16RegClass;
4300 Opc = AArch64::LDRHui;
4303 LLVM_DEBUG(
dbgs() <<
"Could not load from constant pool of type "
4309 auto &MF = MIRBuilder.
getMF();
4310 unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
4311 if (IsTiny && (
Size == 16 ||
Size == 8 ||
Size == 4)) {
4313 LoadMI = &*MIRBuilder.
buildInstr(Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
4316 MIRBuilder.
buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
4319 LoadMI = &*MIRBuilder.
buildInstr(Opc, {RC}, {Adrp})
4320 .addConstantPoolIndex(
4336static std::pair<unsigned, unsigned>
4338 unsigned Opc, SubregIdx;
4339 if (RB.
getID() == AArch64::GPRRegBankID) {
4341 Opc = AArch64::INSvi8gpr;
4342 SubregIdx = AArch64::bsub;
4343 }
else if (EltSize == 16) {
4344 Opc = AArch64::INSvi16gpr;
4345 SubregIdx = AArch64::ssub;
4346 }
else if (EltSize == 32) {
4347 Opc = AArch64::INSvi32gpr;
4348 SubregIdx = AArch64::ssub;
4349 }
else if (EltSize == 64) {
4350 Opc = AArch64::INSvi64gpr;
4351 SubregIdx = AArch64::dsub;
4357 Opc = AArch64::INSvi8lane;
4358 SubregIdx = AArch64::bsub;
4359 }
else if (EltSize == 16) {
4360 Opc = AArch64::INSvi16lane;
4361 SubregIdx = AArch64::hsub;
4362 }
else if (EltSize == 32) {
4363 Opc = AArch64::INSvi32lane;
4364 SubregIdx = AArch64::ssub;
4365 }
else if (EltSize == 64) {
4366 Opc = AArch64::INSvi64lane;
4367 SubregIdx = AArch64::dsub;
4372 return std::make_pair(Opc, SubregIdx);
4376 unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4378 const ComplexRendererFns &RenderFns)
const {
4379 assert(Opcode &&
"Expected an opcode?");
4381 "Function should only be used to produce selected instructions!");
4382 auto MI = MIRBuilder.
buildInstr(Opcode, DstOps, SrcOps);
4384 for (
auto &Fn : *RenderFns)
4391 const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4395 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4396 auto Ty =
MRI.getType(
LHS.getReg());
4399 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit type only");
4400 bool Is32Bit =
Size == 32;
4403 if (
auto Fns = selectArithImmed(RHS))
4404 return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {
LHS},
4408 if (
auto Fns = selectNegArithImmed(RHS))
4409 return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {
LHS},
4413 if (
auto Fns = selectArithExtendedRegister(RHS))
4414 return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {
LHS},
4418 if (
auto Fns = selectShiftedRegister(RHS))
4419 return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {
LHS},
4421 return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {
LHS,
RHS},
4429 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4430 {{AArch64::ADDXri, AArch64::ADDWri},
4431 {AArch64::ADDXrs, AArch64::ADDWrs},
4432 {AArch64::ADDXrr, AArch64::ADDWrr},
4433 {AArch64::SUBXri, AArch64::SUBWri},
4434 {AArch64::ADDXrx, AArch64::ADDWrx}}};
4435 return emitAddSub(OpcTable, DefReg, LHS, RHS, MIRBuilder);
4442 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4443 {{AArch64::ADDSXri, AArch64::ADDSWri},
4444 {AArch64::ADDSXrs, AArch64::ADDSWrs},
4445 {AArch64::ADDSXrr, AArch64::ADDSWrr},
4446 {AArch64::SUBSXri, AArch64::SUBSWri},
4447 {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4448 return emitAddSub(OpcTable, Dst, LHS, RHS, MIRBuilder);
4455 const std::array<std::array<unsigned, 2>, 5> OpcTable{
4456 {{AArch64::SUBSXri, AArch64::SUBSWri},
4457 {AArch64::SUBSXrs, AArch64::SUBSWrs},
4458 {AArch64::SUBSXrr, AArch64::SUBSWrr},
4459 {AArch64::ADDSXri, AArch64::ADDSWri},
4460 {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4461 return emitAddSub(OpcTable, Dst, LHS, RHS, MIRBuilder);
4468 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4470 bool Is32Bit = (
MRI->getType(
LHS.getReg()).getSizeInBits() == 32);
4471 static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
4472 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4479 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4481 bool Is32Bit = (
MRI->getType(
LHS.getReg()).getSizeInBits() == 32);
4482 static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
4483 return emitInstr(OpcTable[Is32Bit], {Dst}, {
LHS,
RHS}, MIRBuilder);
4490 bool Is32Bit = (
MRI.getType(
LHS.getReg()).getSizeInBits() == 32);
4491 auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4492 return emitADDS(
MRI.createVirtualRegister(RC), LHS, RHS, MIRBuilder);
4498 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected register operands?");
4502 bool Is32Bit = (
RegSize == 32);
4503 const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4504 {AArch64::ANDSXrs, AArch64::ANDSWrs},
4505 {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4509 int64_t
Imm = ValAndVReg->Value.getSExtValue();
4512 auto TstMI = MIRBuilder.
buildInstr(OpcTable[0][Is32Bit], {Ty}, {
LHS});
4519 if (
auto Fns = selectLogicalShiftedRegister(RHS))
4520 return emitInstr(OpcTable[1][Is32Bit], {Ty}, {
LHS}, MIRBuilder, Fns);
4521 return emitInstr(OpcTable[2][Is32Bit], {Ty}, {
LHS,
RHS}, MIRBuilder);
4524MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
4527 assert(
LHS.isReg() &&
RHS.isReg() &&
"Expected LHS and RHS to be registers!");
4534 assert((
Size == 32 ||
Size == 64) &&
"Expected a 32-bit or 64-bit LHS/RHS?");
4536 if (
auto FoldCmp = tryFoldIntegerCompare(LHS, RHS, Predicate, MIRBuilder))
4538 auto Dst =
MRI.cloneVirtualRegister(
LHS.getReg());
4539 return emitSUBS(Dst, LHS, RHS, MIRBuilder);
4542MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4546 LLT Ty =
MRI.getType(Dst);
4548 "Expected a 32-bit scalar register?");
4550 const Register ZReg = AArch64::WZR;
4555 return emitCSINC(Dst, ZReg, ZReg, InvCC1,
4561 emitCSINC(Def1Reg, ZReg, ZReg, InvCC1, MIRBuilder);
4562 emitCSINC(Def2Reg, ZReg, ZReg, InvCC2, MIRBuilder);
4563 auto OrMI = MIRBuilder.
buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4568MachineInstr *AArch64InstructionSelector::emitFPCompare(
4570 std::optional<CmpInst::Predicate> Pred)
const {
4572 LLT Ty =
MRI.getType(LHS);
4576 assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4587 if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4591 ShouldUseImm =
true;
4595 unsigned CmpOpcTbl[2][3] = {
4596 {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4597 {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4599 CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4611MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4620 const LLT Op1Ty =
MRI.getType(Op1);
4621 const LLT Op2Ty =
MRI.getType(Op2);
4623 if (Op1Ty != Op2Ty) {
4624 LLVM_DEBUG(
dbgs() <<
"Could not do vector concat of differing vector tys");
4627 assert(Op1Ty.
isVector() &&
"Expected a vector for vector concat");
4630 LLVM_DEBUG(
dbgs() <<
"Vector concat not supported for full size vectors");
4646 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op1, MIRBuilder);
4648 emitScalarToVector(ScalarTy.
getSizeInBits(), DstRC, Op2, MIRBuilder);
4649 if (!WidenedOp1 || !WidenedOp2) {
4650 LLVM_DEBUG(
dbgs() <<
"Could not emit a vector from scalar value");
4655 unsigned InsertOpc, InsSubRegIdx;
4656 std::tie(InsertOpc, InsSubRegIdx) =
4660 Dst =
MRI.createVirtualRegister(DstRC);
4680 if (
const auto *RC = dyn_cast<const TargetRegisterClass *>(RegClassOrBank))
4681 Size =
TRI.getRegSizeInBits(*RC);
4683 Size =
MRI.getType(Dst).getSizeInBits();
4685 assert(
Size <= 64 &&
"Expected 64 bits or less only!");
4686 static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4687 unsigned Opc = OpcTable[
Size == 64];
4688 auto CSINC = MIRBuilder.
buildInstr(Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4696 unsigned Opcode =
I.getOpcode();
4700 bool NeedsNegatedCarry =
4701 (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
4711 if (SrcMI ==
I.getPrevNode()) {
4712 if (
auto *CarrySrcMI = dyn_cast<GAddSubCarryOut>(SrcMI)) {
4713 bool ProducesNegatedCarry = CarrySrcMI->isSub();
4714 if (NeedsNegatedCarry == ProducesNegatedCarry &&
4715 CarrySrcMI->isUnsigned() &&
4716 CarrySrcMI->getCarryOutReg() == CarryReg &&
4717 selectAndRestoreState(*SrcMI))
4722 Register DeadReg =
MRI->createVirtualRegister(&AArch64::GPR32RegClass);
4724 if (NeedsNegatedCarry) {
4727 return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
4731 auto Fns = select12BitValueWithLeftShift(1);
4732 return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
4735bool AArch64InstructionSelector::selectOverflowOp(
MachineInstr &
I,
4737 auto &CarryMI = cast<GAddSubCarryOut>(
I);
4739 if (
auto *CarryInMI = dyn_cast<GAddSubCarryInOut>(&
I)) {
4741 emitCarryIn(
I, CarryInMI->getCarryInReg());
4745 auto OpAndCC = emitOverflowOp(
I.getOpcode(), CarryMI.getDstReg(),
4746 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
4748 Register CarryOutReg = CarryMI.getCarryOutReg();
4751 if (!
MRI.use_nodbg_empty(CarryOutReg)) {
4757 emitCSINC(CarryOutReg, ZReg, ZReg,
4758 getInvertedCondCode(OpAndCC.second), MIB);
4761 I.eraseFromParent();
4765std::pair<MachineInstr *, AArch64CC::CondCode>
4766AArch64InstructionSelector::emitOverflowOp(
unsigned Opcode,
Register Dst,
4773 case TargetOpcode::G_SADDO:
4774 return std::make_pair(emitADDS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::VS);
4775 case TargetOpcode::G_UADDO:
4776 return std::make_pair(emitADDS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::HS);
4777 case TargetOpcode::G_SSUBO:
4778 return std::make_pair(emitSUBS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::VS);
4779 case TargetOpcode::G_USUBO:
4780 return std::make_pair(emitSUBS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::LO);
4781 case TargetOpcode::G_SADDE:
4782 return std::make_pair(emitADCS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::VS);
4783 case TargetOpcode::G_UADDE:
4784 return std::make_pair(emitADCS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::HS);
4785 case TargetOpcode::G_SSUBE:
4786 return std::make_pair(emitSBCS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::VS);
4787 case TargetOpcode::G_USUBE:
4788 return std::make_pair(emitSBCS(Dst, LHS, RHS, MIRBuilder),
AArch64CC::LO);
4808 unsigned Depth = 0) {
4809 if (!
MRI.hasOneNonDBGUse(Val))
4813 if (isa<GAnyCmp>(ValDef)) {
4815 MustBeFirst =
false;
4821 if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
4822 bool IsOR = Opcode == TargetOpcode::G_OR;
4834 if (MustBeFirstL && MustBeFirstR)
4840 if (!CanNegateL && !CanNegateR)
4844 CanNegate = WillNegate && CanNegateL && CanNegateR;
4847 MustBeFirst = !CanNegate;
4849 assert(Opcode == TargetOpcode::G_AND &&
"Must be G_AND");
4852 MustBeFirst = MustBeFirstL || MustBeFirstR;
4859MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
4864 LLT OpTy =
MRI.getType(LHS);
4866 std::optional<ValueAndVReg>
C;
4870 if (!
C ||
C->Value.sgt(31) ||
C->Value.slt(-31))
4871 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4872 else if (
C->Value.ule(31))
4873 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4875 CCmpOpc = OpTy.
getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
4881 assert(STI.hasFullFP16() &&
"Expected Full FP16 for fp16 comparisons");
4882 CCmpOpc = AArch64::FCCMPHrr;
4885 CCmpOpc = AArch64::FCCMPSrr;
4888 CCmpOpc = AArch64::FCCMPDrr;
4898 if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4899 CCmp.
addImm(
C->Value.getZExtValue());
4900 else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4901 CCmp.
addImm(
C->Value.abs().getZExtValue());
4909MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
4916 if (
auto *Cmp = dyn_cast<GAnyCmp>(ValDef)) {
4922 if (isa<GICmp>(Cmp)) {
4933 ExtraCmp = emitFPCompare(LHS, RHS, MIB,
CC);
4944 auto Dst =
MRI.cloneVirtualRegister(LHS);
4945 if (isa<GICmp>(Cmp))
4946 return emitSUBS(Dst,
Cmp->getOperand(2),
Cmp->getOperand(3), MIB);
4947 return emitFPCompare(
Cmp->getOperand(2).getReg(),
4948 Cmp->getOperand(3).getReg(), MIB);
4953 assert(
MRI.hasOneNonDBGUse(Val) &&
"Valid conjunction/disjunction tree");
4955 bool IsOR = Opcode == TargetOpcode::G_OR;
4961 assert(ValidL &&
"Valid conjunction/disjunction tree");
4968 assert(ValidR &&
"Valid conjunction/disjunction tree");
4973 assert(!MustBeFirstR &&
"Valid conjunction/disjunction tree");
4982 bool NegateAfterAll;
4983 if (Opcode == TargetOpcode::G_OR) {
4986 assert(CanNegateR &&
"at least one side must be negatable");
4987 assert(!MustBeFirstR &&
"invalid conjunction/disjunction tree");
4991 NegateAfterR =
true;
4994 NegateR = CanNegateR;
4995 NegateAfterR = !CanNegateR;
4998 NegateAfterAll = !Negate;
5000 assert(Opcode == TargetOpcode::G_AND &&
5001 "Valid conjunction/disjunction tree");
5002 assert(!Negate &&
"Valid conjunction/disjunction tree");
5006 NegateAfterR =
false;
5007 NegateAfterAll =
false;
5023MachineInstr *AArch64InstructionSelector::emitConjunction(
5025 bool DummyCanNegate;
5026 bool DummyMustBeFirst;
5033bool AArch64InstructionSelector::tryOptSelectConjunction(
GSelect &SelI,
5045bool AArch64InstructionSelector::tryOptSelect(
GSelect &
I) {
5069 if (!
MRI.hasOneNonDBGUse(CondDefReg)) {
5071 for (
const MachineInstr &UI :
MRI.use_nodbg_instructions(CondDefReg)) {
5074 if (UI.getOpcode() != TargetOpcode::G_SELECT)
5080 unsigned CondOpc = CondDef->
getOpcode();
5081 if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
5082 if (tryOptSelectConjunction(
I, *CondDef))
5088 if (CondOpc == TargetOpcode::G_ICMP) {
5116 emitSelect(
I.getOperand(0).getReg(),
I.getOperand(2).getReg(),
5117 I.getOperand(3).getReg(), CondCode, MIB);
5118 I.eraseFromParent();
5122MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
5126 "Unexpected MachineOperand");
5163 return emitCMN(LHS, RHSDef->
getOperand(2), MIRBuilder);
5174 LHSDef->
getOpcode() == TargetOpcode::G_AND) {
5177 if (!ValAndVReg || ValAndVReg->Value != 0)
5187bool AArch64InstructionSelector::selectShuffleVector(
5189 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5190 Register Src1Reg =
I.getOperand(1).getReg();
5191 const LLT Src1Ty =
MRI.getType(Src1Reg);
5192 Register Src2Reg =
I.getOperand(2).getReg();
5193 const LLT Src2Ty =
MRI.getType(Src2Reg);
5204 LLVM_DEBUG(
dbgs() <<
"Could not select a \"scalar\" G_SHUFFLE_VECTOR\n");
5211 for (
int Val : Mask) {
5214 Val = Val < 0 ? 0 : Val;
5215 for (
unsigned Byte = 0;
Byte < BytesPerElt; ++
Byte) {
5233 emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
5240 IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5244 AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
5250 .addReg(TBL1.getReg(0), 0, AArch64::dsub);
5251 RBI.constrainGenericRegister(
Copy.getReg(0), AArch64::FPR64RegClass,
MRI);
5252 I.eraseFromParent();
5260 auto TBL2 = MIB.
buildInstr(AArch64::TBLv16i8Two, {
I.getOperand(0)},
5263 I.eraseFromParent();
5267MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5277 DstReg =
MRI.createVirtualRegister(DstRC);
5279 unsigned EltSize =
MRI.getType(EltReg).getSizeInBits();
5282 if (RB.
getID() == AArch64::FPRRegBankID) {
5283 auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
5284 InsElt = MIRBuilder.
buildInstr(Opc, {*DstReg}, {SrcReg})
5286 .
addUse(InsSub->getOperand(0).getReg())
5289 InsElt = MIRBuilder.
buildInstr(Opc, {*DstReg}, {SrcReg})
5298bool AArch64InstructionSelector::selectUSMovFromExtend(
5300 if (
MI.getOpcode() != TargetOpcode::G_SEXT &&
5301 MI.getOpcode() != TargetOpcode::G_ZEXT &&
5302 MI.getOpcode() != TargetOpcode::G_ANYEXT)
5304 bool IsSigned =
MI.getOpcode() == TargetOpcode::G_SEXT;
5305 const Register DefReg =
MI.getOperand(0).getReg();
5306 const LLT DstTy =
MRI.getType(DefReg);
5309 if (DstSize != 32 && DstSize != 64)
5313 MI.getOperand(1).getReg(),
MRI);
5319 const LLT VecTy =
MRI.getType(Src0);
5324 const MachineInstr *ScalarToVector = emitScalarToVector(
5325 VecTy.
getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5326 assert(ScalarToVector &&
"Didn't expect emitScalarToVector to fail!");
5332 Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5334 Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5336 Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5338 Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5340 Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5349 if (DstSize == 64 && !IsSigned) {
5350 Register NewReg =
MRI.createVirtualRegister(&AArch64::GPR32RegClass);
5351 MIB.
buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5352 ExtI = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5355 .
addImm(AArch64::sub_32);
5356 RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass,
MRI);
5358 ExtI = MIB.
buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5361 MI.eraseFromParent();
5365MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
5368 if (DstSize == 128) {
5369 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5371 Op = AArch64::MOVIv16b_ns;
5373 Op = AArch64::MOVIv8b_ns;
5380 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5387MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
5392 if (DstSize == 128) {
5393 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5395 Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
5397 Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
5417MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
5422 if (DstSize == 128) {
5423 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5425 Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
5427 Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
5453MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
5457 if (DstSize == 128) {
5458 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5460 Op = AArch64::MOVIv2d_ns;
5462 Op = AArch64::MOVID;
5468 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5475MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
5480 if (DstSize == 128) {
5481 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5483 Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
5485 Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
5505MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
5509 bool IsWide =
false;
5510 if (DstSize == 128) {
5511 if (
Bits.getHiBits(64) !=
Bits.getLoBits(64))
5513 Op = AArch64::FMOVv4f32_ns;
5516 Op = AArch64::FMOVv2f32_ns;
5525 Op = AArch64::FMOVv2f64_ns;
5529 auto Mov = Builder.
buildInstr(
Op, {Dst}, {}).addImm(Val);
5534bool AArch64InstructionSelector::selectIndexedExtLoad(
5536 auto &ExtLd = cast<GIndexedAnyExtLoad>(
MI);
5538 Register WriteBack = ExtLd.getWritebackReg();
5541 LLT Ty =
MRI.getType(Dst);
5543 unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
5544 bool IsPre = ExtLd.isPre();
5545 bool IsSExt = isa<GIndexedSExtLoad>(ExtLd);
5546 bool InsertIntoXReg =
false;
5554 if (MemSizeBits == 8) {
5557 Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
5559 Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
5560 NewLdDstTy = IsDst64 ? s64 : s32;
5562 Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
5563 InsertIntoXReg = IsDst64;
5566 }
else if (MemSizeBits == 16) {
5569 Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
5571 Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
5572 NewLdDstTy = IsDst64 ? s64 : s32;
5574 Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
5575 InsertIntoXReg = IsDst64;
5578 }
else if (MemSizeBits == 32) {
5580 Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
5583 Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
5584 InsertIntoXReg = IsDst64;
5591 if (RBI.getRegBank(Dst,
MRI,
TRI)->getID() == AArch64::FPRRegBankID)
5599 .addImm(Cst->getSExtValue());
5604 if (InsertIntoXReg) {
5606 auto SubToReg = MIB.
buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
5609 .
addImm(AArch64::sub_32);
5610 RBI.constrainGenericRegister(SubToReg.getReg(0), AArch64::GPR64RegClass,
5616 MI.eraseFromParent();
5621bool AArch64InstructionSelector::selectIndexedLoad(
MachineInstr &
MI,
5623 auto &Ld = cast<GIndexedLoad>(
MI);
5625 Register WriteBack = Ld.getWritebackReg();
5628 assert(
MRI.getType(Dst).getSizeInBits() <= 128 &&
5629 "Unexpected type for indexed load");
5630 unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
5632 if (MemSize <
MRI.getType(Dst).getSizeInBytes())
5633 return selectIndexedExtLoad(
MI,
MRI);
5637 static constexpr unsigned GPROpcodes[] = {
5638 AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
5640 static constexpr unsigned FPROpcodes[] = {
5641 AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
5643 if (RBI.getRegBank(Dst,
MRI,
TRI)->getID() == AArch64::FPRRegBankID)
5644 Opc = FPROpcodes[
Log2_32(MemSize)];
5646 Opc = GPROpcodes[
Log2_32(MemSize)];
5648 static constexpr unsigned GPROpcodes[] = {
5649 AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
5651 static constexpr unsigned FPROpcodes[] = {
5652 AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
5653 AArch64::LDRDpost, AArch64::LDRQpost};
5654 if (RBI.getRegBank(Dst,
MRI,
TRI)->getID() == AArch64::FPRRegBankID)
5655 Opc = FPROpcodes[
Log2_32(MemSize)];
5657 Opc = GPROpcodes[
Log2_32(MemSize)];
5663 MIB.
buildInstr(Opc, {WriteBack, Dst}, {
Base}).addImm(Cst->getSExtValue());
5666 MI.eraseFromParent();
5670bool AArch64InstructionSelector::selectIndexedStore(
GIndexedStore &
I,
5676 LLT ValTy =
MRI.getType(Val);
5681 static constexpr unsigned GPROpcodes[] = {
5682 AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
5684 static constexpr unsigned FPROpcodes[] = {
5685 AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
5688 if (RBI.getRegBank(Val,
MRI,
TRI)->getID() == AArch64::FPRRegBankID)
5693 static constexpr unsigned GPROpcodes[] = {
5694 AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
5696 static constexpr unsigned FPROpcodes[] = {
5697 AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
5698 AArch64::STRDpost, AArch64::STRQpost};
5700 if (RBI.getRegBank(Val,
MRI,
TRI)->getID() == AArch64::FPRRegBankID)
5710 MIB.
buildInstr(Opc, {Dst}, {Val,
Base}).addImm(Cst->getSExtValue());
5711 Str.cloneMemRefs(
I);
5713 I.eraseFromParent();
5721 LLT DstTy =
MRI.getType(Dst);
5724 if (DstSize == 128) {
5726 MIRBuilder.
buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5731 if (DstSize == 64) {
5734 .
buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5737 .addReg(Mov.getReg(0), 0, AArch64::dsub);
5738 RBI.constrainGenericRegister(Dst, AArch64::FPR64RegClass,
MRI);
5771 if (
auto *NewOp = TryMOVIWithBits(DefBits))
5775 auto TryWithFNeg = [&](
APInt DefBits,
int NumBits,
5779 APInt NegBits(DstSize, 0);
5780 unsigned NumElts = DstSize / NumBits;
5781 for (
unsigned i = 0; i < NumElts; i++)
5782 NegBits |= Neg << (NumBits * i);
5783 NegBits = DefBits ^ NegBits;
5787 if (
auto *NewOp = TryMOVIWithBits(NegBits)) {
5788 Register NewDst =
MRI.createVirtualRegister(&AArch64::FPR128RegClass);
5790 return MIRBuilder.
buildInstr(NegOpc, {Dst}, {NewDst});
5795 if ((R = TryWithFNeg(DefBits, 32, AArch64::FNEGv4f32)) ||
5796 (R = TryWithFNeg(DefBits, 64, AArch64::FNEGv2f64)) ||
5797 (STI.hasFullFP16() &&
5798 (R = TryWithFNeg(DefBits, 16, AArch64::FNEGv8f16))))
5804 LLVM_DEBUG(
dbgs() <<
"Could not generate cp load for constant vector!");
5808 auto Copy = MIRBuilder.
buildCopy(Dst, CPLoad->getOperand(0));
5809 RBI.constrainGenericRegister(
5810 Dst, *
MRI.getRegClass(CPLoad->getOperand(0).getReg()),
MRI);
5814bool AArch64InstructionSelector::tryOptConstantBuildVec(
5816 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5818 assert(DstSize <= 128 &&
"Unexpected build_vec type!");
5824 for (
unsigned Idx = 1;
Idx <
I.getNumOperands(); ++
Idx) {
5830 const_cast<ConstantInt *
>(OpMI->getOperand(1).getCImm()));
5831 else if ((OpMI =
getOpcodeDef(TargetOpcode::G_FCONSTANT,
5832 I.getOperand(
Idx).getReg(),
MRI)))
5834 const_cast<ConstantFP *
>(OpMI->getOperand(1).getFPImm()));
5839 if (!emitConstantVector(
I.getOperand(0).getReg(), CV, MIB,
MRI))
5841 I.eraseFromParent();
5845bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5851 Register Dst =
I.getOperand(0).getReg();
5852 Register EltReg =
I.getOperand(1).getReg();
5853 LLT EltTy =
MRI.getType(EltReg);
5861 return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5869 getRegClassForTypeOnBank(
MRI.getType(Dst), DstRB);
5874 auto SubregToReg = MIB.
buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5878 I.eraseFromParent();
5880 return RBI.constrainGenericRegister(Dst, *DstRC,
MRI);
5883bool AArch64InstructionSelector::selectBuildVector(
MachineInstr &
I,
5885 assert(
I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5888 const LLT DstTy =
MRI.getType(
I.getOperand(0).getReg());
5889 const LLT EltTy =
MRI.getType(
I.getOperand(1).getReg());
5892 if (tryOptConstantBuildVec(
I, DstTy,
MRI))
5894 if (tryOptBuildVecToSubregToReg(
I,
MRI))
5897 if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
5904 I.getOperand(1).getReg(), MIB);
5914 for (
unsigned i = 2, e = DstSize / EltSize + 1; i <
e; ++i) {
5917 Register OpReg =
I.getOperand(i).getReg();
5919 if (!getOpcodeDef<GImplicitDef>(OpReg,
MRI)) {
5920 PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
5927 if (DstSize < 128) {
5930 getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec,
MRI,
TRI));
5933 if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
5941 if (
SubReg != AArch64::ssub &&
SubReg != AArch64::dsub) {
5942 LLVM_DEBUG(
dbgs() <<
"Unsupported destination size! (" << DstSize
5948 Register DstReg =
I.getOperand(0).getReg();
5950 MIB.
buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, 0,
SubReg);
5953 RBI.constrainGenericRegister(DstReg, *RC,
MRI);
5971 if (PrevMI == ScalarToVec && DstReg.
isVirtual()) {
5973 getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec,
MRI,
TRI));
5974 RBI.constrainGenericRegister(DstReg, *RC,
MRI);
5978 I.eraseFromParent();
5982bool AArch64InstructionSelector::selectVectorLoadIntrinsic(
unsigned Opc,
5985 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5986 assert(Opc &&
"Expected an opcode?");
5987 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
5989 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
5992 "Destination must be 64 bits or 128 bits?");
5993 unsigned SubReg =
Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5994 auto Ptr =
I.getOperand(
I.getNumOperands() - 1).getReg();
5995 assert(
MRI.getType(
Ptr).isPointer() &&
"Expected a pointer type?");
5997 Load.cloneMemRefs(
I);
5999 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6000 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6001 auto Vec = MIB.
buildInstr(TargetOpcode::COPY, {
I.getOperand(
Idx)}, {})
6002 .addReg(SelectedLoadDst, 0,
SubReg +
Idx);
6011bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
6013 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
6014 assert(Opc &&
"Expected an opcode?");
6015 assert(NumVecs > 1 && NumVecs < 5 &&
"Only support 2, 3, or 4 vectors");
6017 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6020 auto FirstSrcRegIt =
I.operands_begin() + NumVecs + 1;
6022 std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.
begin(),
6023 [](
auto MO) { return MO.getReg(); });
6027 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6042 .
addImm(LaneNo->getZExtValue())
6044 Load.cloneMemRefs(
I);
6046 Register SelectedLoadDst =
Load->getOperand(0).getReg();
6047 unsigned SubReg = AArch64::qsub0;
6048 for (
unsigned Idx = 0;
Idx < NumVecs; ++
Idx) {
6049 auto Vec = MIB.
buildInstr(TargetOpcode::COPY,
6050 {Narrow ?
DstOp(&AArch64::FPR128RegClass)
6053 .addReg(SelectedLoadDst, 0,
SubReg +
Idx);
6058 !emitNarrowVector(
I.getOperand(
Idx).getReg(), WideReg, MIB,
MRI))
6064void AArch64InstructionSelector::selectVectorStoreIntrinsic(
MachineInstr &
I,
6068 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6072 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6073 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6082bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
6085 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6089 std::transform(
I.operands_begin() + 1,
I.operands_begin() + 1 + NumVecs,
6090 Regs.
begin(), [](
auto MO) { return MO.getReg(); });
6094 return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
6107 .
addImm(LaneNo->getZExtValue())
6114bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
6117 unsigned IntrinID = cast<GIntrinsic>(
I).getIntrinsicID();
6128 case Intrinsic::aarch64_ldxp:
6129 case Intrinsic::aarch64_ldaxp: {
6131 IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6132 {
I.getOperand(0).
getReg(),
I.getOperand(1).getReg()},
6138 case Intrinsic::aarch64_neon_ld1x2: {
6139 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6142 Opc = AArch64::LD1Twov8b;
6144 Opc = AArch64::LD1Twov16b;
6146 Opc = AArch64::LD1Twov4h;
6148 Opc = AArch64::LD1Twov8h;
6150 Opc = AArch64::LD1Twov2s;
6152 Opc = AArch64::LD1Twov4s;
6154 Opc = AArch64::LD1Twov2d;
6155 else if (Ty ==
S64 || Ty == P0)
6156 Opc = AArch64::LD1Twov1d;
6159 selectVectorLoadIntrinsic(Opc, 2,
I);
6162 case Intrinsic::aarch64_neon_ld1x3: {
6163 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6166 Opc = AArch64::LD1Threev8b;
6168 Opc = AArch64::LD1Threev16b;
6170 Opc = AArch64::LD1Threev4h;
6172 Opc = AArch64::LD1Threev8h;
6174 Opc = AArch64::LD1Threev2s;
6176 Opc = AArch64::LD1Threev4s;
6178 Opc = AArch64::LD1Threev2d;
6179 else if (Ty ==
S64 || Ty == P0)
6180 Opc = AArch64::LD1Threev1d;
6183 selectVectorLoadIntrinsic(Opc, 3,
I);
6186 case Intrinsic::aarch64_neon_ld1x4: {
6187 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6190 Opc = AArch64::LD1Fourv8b;
6192 Opc = AArch64::LD1Fourv16b;
6194 Opc = AArch64::LD1Fourv4h;
6196 Opc = AArch64::LD1Fourv8h;
6198 Opc = AArch64::LD1Fourv2s;
6200 Opc = AArch64::LD1Fourv4s;
6202 Opc = AArch64::LD1Fourv2d;
6203 else if (Ty ==
S64 || Ty == P0)
6204 Opc = AArch64::LD1Fourv1d;
6207 selectVectorLoadIntrinsic(Opc, 4,
I);
6210 case Intrinsic::aarch64_neon_ld2: {
6211 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6214 Opc = AArch64::LD2Twov8b;
6216 Opc = AArch64::LD2Twov16b;
6218 Opc = AArch64::LD2Twov4h;
6220 Opc = AArch64::LD2Twov8h;
6222 Opc = AArch64::LD2Twov2s;
6224 Opc = AArch64::LD2Twov4s;
6226 Opc = AArch64::LD2Twov2d;
6227 else if (Ty ==
S64 || Ty == P0)
6228 Opc = AArch64::LD1Twov1d;
6231 selectVectorLoadIntrinsic(Opc, 2,
I);
6234 case Intrinsic::aarch64_neon_ld2lane: {
6235 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6238 Opc = AArch64::LD2i8;
6240 Opc = AArch64::LD2i16;
6242 Opc = AArch64::LD2i32;
6245 Opc = AArch64::LD2i64;
6248 if (!selectVectorLoadLaneIntrinsic(Opc, 2,
I))
6252 case Intrinsic::aarch64_neon_ld2r: {
6253 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6256 Opc = AArch64::LD2Rv8b;
6258 Opc = AArch64::LD2Rv16b;
6260 Opc = AArch64::LD2Rv4h;
6262 Opc = AArch64::LD2Rv8h;
6264 Opc = AArch64::LD2Rv2s;
6266 Opc = AArch64::LD2Rv4s;
6268 Opc = AArch64::LD2Rv2d;
6269 else if (Ty ==
S64 || Ty == P0)
6270 Opc = AArch64::LD2Rv1d;
6273 selectVectorLoadIntrinsic(Opc, 2,
I);
6276 case Intrinsic::aarch64_neon_ld3: {
6277 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6280 Opc = AArch64::LD3Threev8b;
6282 Opc = AArch64::LD3Threev16b;
6284 Opc = AArch64::LD3Threev4h;
6286 Opc = AArch64::LD3Threev8h;
6288 Opc = AArch64::LD3Threev2s;
6290 Opc = AArch64::LD3Threev4s;
6292 Opc = AArch64::LD3Threev2d;
6293 else if (Ty ==
S64 || Ty == P0)
6294 Opc = AArch64::LD1Threev1d;
6297 selectVectorLoadIntrinsic(Opc, 3,
I);
6300 case Intrinsic::aarch64_neon_ld3lane: {
6301 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6304 Opc = AArch64::LD3i8;
6306 Opc = AArch64::LD3i16;
6308 Opc = AArch64::LD3i32;
6311 Opc = AArch64::LD3i64;
6314 if (!selectVectorLoadLaneIntrinsic(Opc, 3,
I))
6318 case Intrinsic::aarch64_neon_ld3r: {
6319 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6322 Opc = AArch64::LD3Rv8b;
6324 Opc = AArch64::LD3Rv16b;
6326 Opc = AArch64::LD3Rv4h;
6328 Opc = AArch64::LD3Rv8h;
6330 Opc = AArch64::LD3Rv2s;
6332 Opc = AArch64::LD3Rv4s;
6334 Opc = AArch64::LD3Rv2d;
6335 else if (Ty ==
S64 || Ty == P0)
6336 Opc = AArch64::LD3Rv1d;
6339 selectVectorLoadIntrinsic(Opc, 3,
I);
6342 case Intrinsic::aarch64_neon_ld4: {
6343 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6346 Opc = AArch64::LD4Fourv8b;
6348 Opc = AArch64::LD4Fourv16b;
6350 Opc = AArch64::LD4Fourv4h;
6352 Opc = AArch64::LD4Fourv8h;
6354 Opc = AArch64::LD4Fourv2s;
6356 Opc = AArch64::LD4Fourv4s;
6358 Opc = AArch64::LD4Fourv2d;
6359 else if (Ty ==
S64 || Ty == P0)
6360 Opc = AArch64::LD1Fourv1d;
6363 selectVectorLoadIntrinsic(Opc, 4,
I);
6366 case Intrinsic::aarch64_neon_ld4lane: {
6367 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6370 Opc = AArch64::LD4i8;
6372 Opc = AArch64::LD4i16;
6374 Opc = AArch64::LD4i32;
6377 Opc = AArch64::LD4i64;
6380 if (!selectVectorLoadLaneIntrinsic(Opc, 4,
I))
6384 case Intrinsic::aarch64_neon_ld4r: {
6385 LLT Ty =
MRI.getType(
I.getOperand(0).getReg());
6388 Opc = AArch64::LD4Rv8b;
6390 Opc = AArch64::LD4Rv16b;
6392 Opc = AArch64::LD4Rv4h;
6394 Opc = AArch64::LD4Rv8h;
6396 Opc = AArch64::LD4Rv2s;
6398 Opc = AArch64::LD4Rv4s;
6400 Opc = AArch64::LD4Rv2d;
6401 else if (Ty ==
S64 || Ty == P0)
6402 Opc = AArch64::LD4Rv1d;
6405 selectVectorLoadIntrinsic(Opc, 4,
I);
6408 case Intrinsic::aarch64_neon_st1x2: {
6409 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6412 Opc = AArch64::ST1Twov8b;
6414 Opc = AArch64::ST1Twov16b;
6416 Opc = AArch64::ST1Twov4h;
6418 Opc = AArch64::ST1Twov8h;
6420 Opc = AArch64::ST1Twov2s;
6422 Opc = AArch64::ST1Twov4s;
6424 Opc = AArch64::ST1Twov2d;
6425 else if (Ty ==
S64 || Ty == P0)
6426 Opc = AArch64::ST1Twov1d;
6429 selectVectorStoreIntrinsic(
I, 2, Opc);
6432 case Intrinsic::aarch64_neon_st1x3: {
6433 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6436 Opc = AArch64::ST1Threev8b;
6438 Opc = AArch64::ST1Threev16b;
6440 Opc = AArch64::ST1Threev4h;
6442 Opc = AArch64::ST1Threev8h;
6444 Opc = AArch64::ST1Threev2s;
6446 Opc = AArch64::ST1Threev4s;
6448 Opc = AArch64::ST1Threev2d;
6449 else if (Ty ==
S64 || Ty == P0)
6450 Opc = AArch64::ST1Threev1d;
6453 selectVectorStoreIntrinsic(
I, 3, Opc);
6456 case Intrinsic::aarch64_neon_st1x4: {
6457 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6460 Opc = AArch64::ST1Fourv8b;
6462 Opc = AArch64::ST1Fourv16b;
6464 Opc = AArch64::ST1Fourv4h;
6466 Opc = AArch64::ST1Fourv8h;
6468 Opc = AArch64::ST1Fourv2s;
6470 Opc = AArch64::ST1Fourv4s;
6472 Opc = AArch64::ST1Fourv2d;
6473 else if (Ty ==
S64 || Ty == P0)
6474 Opc = AArch64::ST1Fourv1d;
6477 selectVectorStoreIntrinsic(
I, 4, Opc);
6480 case Intrinsic::aarch64_neon_st2: {
6481 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6484 Opc = AArch64::ST2Twov8b;
6486 Opc = AArch64::ST2Twov16b;
6488 Opc = AArch64::ST2Twov4h;
6490 Opc = AArch64::ST2Twov8h;
6492 Opc = AArch64::ST2Twov2s;
6494 Opc = AArch64::ST2Twov4s;
6496 Opc = AArch64::ST2Twov2d;
6497 else if (Ty ==
S64 || Ty == P0)
6498 Opc = AArch64::ST1Twov1d;
6501 selectVectorStoreIntrinsic(
I, 2, Opc);
6504 case Intrinsic::aarch64_neon_st3: {
6505 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6508 Opc = AArch64::ST3Threev8b;
6510 Opc = AArch64::ST3Threev16b;
6512 Opc = AArch64::ST3Threev4h;
6514 Opc = AArch64::ST3Threev8h;
6516 Opc = AArch64::ST3Threev2s;
6518 Opc = AArch64::ST3Threev4s;
6520 Opc = AArch64::ST3Threev2d;
6521 else if (Ty ==
S64 || Ty == P0)
6522 Opc = AArch64::ST1Threev1d;
6525 selectVectorStoreIntrinsic(
I, 3, Opc);
6528 case Intrinsic::aarch64_neon_st4: {
6529 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6532 Opc = AArch64::ST4Fourv8b;
6534 Opc = AArch64::ST4Fourv16b;
6536 Opc = AArch64::ST4Fourv4h;
6538 Opc = AArch64::ST4Fourv8h;
6540 Opc = AArch64::ST4Fourv2s;
6542 Opc = AArch64::ST4Fourv4s;
6544 Opc = AArch64::ST4Fourv2d;
6545 else if (Ty ==
S64 || Ty == P0)
6546 Opc = AArch64::ST1Fourv1d;
6549 selectVectorStoreIntrinsic(
I, 4, Opc);
6552 case Intrinsic::aarch64_neon_st2lane: {
6553 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6556 Opc = AArch64::ST2i8;
6558 Opc = AArch64::ST2i16;
6560 Opc = AArch64::ST2i32;
6563 Opc = AArch64::ST2i64;
6566 if (!selectVectorStoreLaneIntrinsic(
I, 2, Opc))
6570 case Intrinsic::aarch64_neon_st3lane: {
6571 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6574 Opc = AArch64::ST3i8;
6576 Opc = AArch64::ST3i16;
6578 Opc = AArch64::ST3i32;
6581 Opc = AArch64::ST3i64;
6584 if (!selectVectorStoreLaneIntrinsic(
I, 3, Opc))
6588 case Intrinsic::aarch64_neon_st4lane: {
6589 LLT Ty =
MRI.getType(
I.getOperand(1).getReg());
6592 Opc = AArch64::ST4i8;
6594 Opc = AArch64::ST4i16;
6596 Opc = AArch64::ST4i32;
6599 Opc = AArch64::ST4i64;
6602 if (!selectVectorStoreLaneIntrinsic(
I, 4, Opc))
6606 case Intrinsic::aarch64_mops_memset_tag: {
6619 Register DstDef =
I.getOperand(0).getReg();
6621 Register DstUse =
I.getOperand(2).getReg();
6622 Register ValUse =
I.getOperand(3).getReg();
6623 Register SizeUse =
I.getOperand(4).getReg();
6630 auto Memset = MIB.
buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
6631 {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
6638 I.eraseFromParent();
6642bool AArch64InstructionSelector::selectIntrinsic(
MachineInstr &
I,
6644 unsigned IntrinID = cast<GIntrinsic>(
I).getIntrinsicID();
6649 case Intrinsic::aarch64_crypto_sha1h: {
6650 Register DstReg =
I.getOperand(0).getReg();
6651 Register SrcReg =
I.getOperand(2).getReg();
6654 if (
MRI.getType(DstReg).getSizeInBits() != 32 ||
6655 MRI.getType(SrcReg).getSizeInBits() != 32)
6660 if (RBI.getRegBank(SrcReg,
MRI,
TRI)->getID() != AArch64::FPRRegBankID) {
6661 SrcReg =
MRI.createVirtualRegister(&AArch64::FPR32RegClass);
6665 RBI.constrainGenericRegister(
I.getOperand(2).getReg(),
6666 AArch64::GPR32RegClass,
MRI);
6669 if (RBI.getRegBank(DstReg,
MRI,
TRI)->getID() != AArch64::FPRRegBankID)
6670 DstReg =
MRI.createVirtualRegister(&AArch64::FPR32RegClass);
6673 auto SHA1Inst = MIB.
buildInstr(AArch64::SHA1Hrr, {DstReg}, {SrcReg});
6677 if (DstReg !=
I.getOperand(0).getReg()) {
6681 RBI.constrainGenericRegister(
I.getOperand(0).getReg(),
6682 AArch64::GPR32RegClass,
MRI);
6685 I.eraseFromParent();
6688 case Intrinsic::ptrauth_resign: {
6689 Register DstReg =
I.getOperand(0).getReg();
6690 Register ValReg =
I.getOperand(2).getReg();
6691 uint64_t AUTKey =
I.getOperand(3).getImm();
6692 Register AUTDisc =
I.getOperand(4).getReg();
6693 uint64_t PACKey =
I.getOperand(5).getImm();
6694 Register PACDisc =
I.getOperand(6).getReg();
6698 std::tie(AUTConstDiscC, AUTAddrDisc) =
6703 std::tie(PACConstDiscC, PACAddrDisc) =
6706 MIB.
buildCopy({AArch64::X16}, {ValReg});
6707 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6718 RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass,
MRI);
6719 I.eraseFromParent();
6722 case Intrinsic::ptrauth_auth: {
6723 Register DstReg =
I.getOperand(0).getReg();
6724 Register ValReg =
I.getOperand(2).getReg();
6725 uint64_t AUTKey =
I.getOperand(3).getImm();
6726 Register AUTDisc =
I.getOperand(4).getReg();
6730 std::tie(AUTConstDiscC, AUTAddrDisc) =
6733 MIB.
buildCopy({AArch64::X16}, {ValReg});
6734 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6742 RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass,
MRI);
6743 I.eraseFromParent();
6746 case Intrinsic::frameaddress:
6747 case Intrinsic::returnaddress: {
6751 unsigned Depth =
I.getOperand(2).getImm();
6752 Register DstReg =
I.getOperand(0).getReg();
6753 RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass,
MRI);
6755 if (
Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6756 if (!MFReturnAddr) {
6761 MF,
TII, AArch64::LR, AArch64::GPR64RegClass,
I.getDebugLoc());
6764 if (STI.hasPAuth()) {
6765 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6772 I.eraseFromParent();
6779 Register NextFrame =
MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
6781 MIB.
buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
6783 FrameAddr = NextFrame;
6786 if (IntrinID == Intrinsic::frameaddress)
6791 if (STI.hasPAuth()) {
6792 Register TmpReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
6793 MIB.
buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6794 MIB.
buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6803 I.eraseFromParent();
6806 case Intrinsic::aarch64_neon_tbl2:
6807 SelectTable(
I,
MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two,
false);
6809 case Intrinsic::aarch64_neon_tbl3:
6810 SelectTable(
I,
MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6813 case Intrinsic::aarch64_neon_tbl4:
6814 SelectTable(
I,
MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four,
false);
6816 case Intrinsic::aarch64_neon_tbx2:
6817 SelectTable(
I,
MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two,
true);
6819 case Intrinsic::aarch64_neon_tbx3:
6820 SelectTable(
I,
MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three,
true);
6822 case Intrinsic::aarch64_neon_tbx4:
6823 SelectTable(
I,
MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four,
true);
6825 case Intrinsic::swift_async_context_addr:
6834 I.eraseFromParent();
6869bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6871 Register DefReg =
I.getOperand(0).getReg();
6874 Register AddrDisc =
I.getOperand(3).getReg();
6875 uint64_t Disc =
I.getOperand(4).getImm();
6883 if (!isUInt<16>(Disc))
6885 "constant discriminator in ptrauth global out of range [0, 0xffff]");
6888 if (!STI.isTargetELF() && !STI.isTargetMachO())
6898 if (!
MRI.hasOneDef(OffsetReg))
6901 if (OffsetMI.
getOpcode() != TargetOpcode::G_CONSTANT)
6927 unsigned OpFlags = STI.ClassifyGlobalReference(GV, TM);
6930 "unsupported non-GOT op flags on ptrauth global reference");
6932 "unsupported non-GOT reference to weak ptrauth global");
6935 bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6942 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6943 MIB.
buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6944 MIB.
buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6947 .
addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6951 RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass,
MRI);
6952 I.eraseFromParent();
6964 "unsupported non-zero offset in weak ptrauth global reference");
6969 MIB.
buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6970 .addGlobalAddress(GV,
Offset)
6973 RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass,
MRI);
6975 I.eraseFromParent();
6979void AArch64InstructionSelector::SelectTable(
MachineInstr &
I,
6981 unsigned NumVec,
unsigned Opc1,
6982 unsigned Opc2,
bool isExt) {
6983 Register DstReg =
I.getOperand(0).getReg();
6988 for (
unsigned i = 0; i < NumVec; i++)
6989 Regs.
push_back(
I.getOperand(i + 2 + isExt).getReg());
6992 Register IdxReg =
I.getOperand(2 + NumVec + isExt).getReg();
7000 I.eraseFromParent();
7004AArch64InstructionSelector::selectShiftA_32(
const MachineOperand &Root)
const {
7006 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7007 return std::nullopt;
7008 uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
7013AArch64InstructionSelector::selectShiftB_32(
const MachineOperand &Root)
const {
7015 if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
7016 return std::nullopt;
7022AArch64InstructionSelector::selectShiftA_64(
const MachineOperand &Root)
const {
7024 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7025 return std::nullopt;
7026 uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
7031AArch64InstructionSelector::selectShiftB_64(
const MachineOperand &Root)
const {
7033 if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
7034 return std::nullopt;
7045AArch64InstructionSelector::select12BitValueWithLeftShift(
7048 if (Immed >> 12 == 0) {
7050 }
else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
7052 Immed = Immed >> 12;
7054 return std::nullopt;
7067AArch64InstructionSelector::selectArithImmed(
MachineOperand &Root)
const {
7074 if (MaybeImmed == std::nullopt)
7075 return std::nullopt;
7076 return select12BitValueWithLeftShift(*MaybeImmed);
7082AArch64InstructionSelector::selectNegArithImmed(
MachineOperand &Root)
const {
7086 return std::nullopt;
7088 if (MaybeImmed == std::nullopt)
7089 return std::nullopt;
7096 return std::nullopt;
7101 if (
MRI.getType(Root.
getReg()).getSizeInBits() == 32)
7104 Immed = ~Immed + 1ULL;
7106 if (Immed & 0xFFFFFFFFFF000000ULL)
7107 return std::nullopt;
7109 Immed &= 0xFFFFFFULL;
7110 return select12BitValueWithLeftShift(Immed);
7127std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7129 if (
MI.getOpcode() == AArch64::G_SHL) {
7133 MI.getOperand(2).getReg(),
MRI)) {
7134 const APInt ShiftVal = ValAndVeg->Value;
7137 return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7140 return std::nullopt;
7148bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7150 bool IsAddrOperand)
const {
7154 if (
MRI.hasOneNonDBGUse(DefReg) ||
7155 MI.getParent()->getParent()->getFunction().hasOptSize())
7158 if (IsAddrOperand) {
7160 if (
const auto Worth = isWorthFoldingIntoAddrMode(
MI,
MRI))
7164 if (
MI.getOpcode() == AArch64::G_PTR_ADD) {
7171 if (
const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst,
MRI))
7181 return all_of(
MRI.use_nodbg_instructions(DefReg),
7197AArch64InstructionSelector::selectExtendedSHL(
7199 unsigned SizeInBytes,
bool WantsExt)
const {
7200 assert(
Base.isReg() &&
"Expected base to be a register operand");
7201 assert(
Offset.isReg() &&
"Expected offset to be a register operand");
7206 unsigned OffsetOpc = OffsetInst->
getOpcode();
7207 bool LookedThroughZExt =
false;
7208 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7210 if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7211 return std::nullopt;
7215 LookedThroughZExt =
true;
7217 if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7218 return std::nullopt;
7221 int64_t LegalShiftVal =
Log2_32(SizeInBytes);
7222 if (LegalShiftVal == 0)
7223 return std::nullopt;
7224 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7225 return std::nullopt;
7236 if (OffsetOpc == TargetOpcode::G_SHL)
7237 return std::nullopt;
7243 return std::nullopt;
7248 int64_t ImmVal = ValAndVReg->Value.getSExtValue();
7252 if (OffsetOpc == TargetOpcode::G_MUL) {
7253 if (!llvm::has_single_bit<uint32_t>(ImmVal))
7254 return std::nullopt;
7260 if ((ImmVal & 0x7) != ImmVal)
7261 return std::nullopt;
7265 if (ImmVal != LegalShiftVal)
7266 return std::nullopt;
7268 unsigned SignExtend = 0;
7272 if (!LookedThroughZExt) {
7274 auto Ext = getExtendTypeForInst(*ExtInst,
MRI,
true);
7276 return std::nullopt;
7281 return std::nullopt;
7287 OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
7297 MIB.addImm(SignExtend);
7311AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
7314 return std::nullopt;
7331 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7332 return std::nullopt;
7338 return selectExtendedSHL(Root, PtrAdd->
getOperand(1),
7352AArch64InstructionSelector::selectAddrModeRegisterOffset(
7358 if (Gep->
getOpcode() != TargetOpcode::G_PTR_ADD)
7359 return std::nullopt;
7365 return std::nullopt;
7385AArch64InstructionSelector::selectAddrModeXRO(
MachineOperand &Root,
7386 unsigned SizeInBytes)
const {
7389 return std::nullopt;
7393 return std::nullopt;
7411 unsigned Scale =
Log2_32(SizeInBytes);
7412 int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7416 if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7417 ImmOff < (0x1000 << Scale))
7418 return std::nullopt;
7423 if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7427 if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7433 return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7434 (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7439 return std::nullopt;
7443 auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
7449 return selectAddrModeRegisterOffset(Root);
7459AArch64InstructionSelector::selectAddrModeWRO(
MachineOperand &Root,
7460 unsigned SizeInBytes)
const {
7465 if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd,
MRI,
true))
7466 return std::nullopt;
7487 auto ExtendedShl = selectExtendedSHL(Root, LHS, OffsetInst->
getOperand(0),
7496 if (!isWorthFoldingIntoExtendedReg(*OffsetInst,
MRI,
true))
7497 return std::nullopt;
7501 getExtendTypeForInst(*OffsetInst,
MRI,
true);
7503 return std::nullopt;
7508 AArch64::GPR32RegClass, MIB);
7515 MIB.addImm(SignExtend);
7526AArch64InstructionSelector::selectAddrModeUnscaled(
MachineOperand &Root,
7527 unsigned Size)
const {
7532 return std::nullopt;
7534 if (!isBaseWithConstantOffset(Root,
MRI))
7535 return std::nullopt;
7540 if (!OffImm.
isReg())
7541 return std::nullopt;
7543 if (
RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7544 return std::nullopt;
7548 return std::nullopt;
7551 if (RHSC >= -256 && RHSC < 256) {
7558 return std::nullopt;
7562AArch64InstructionSelector::tryFoldAddLowIntoImm(
MachineInstr &RootDef,
7565 if (RootDef.
getOpcode() != AArch64::G_ADD_LOW)
7566 return std::nullopt;
7569 return std::nullopt;
7574 return std::nullopt;
7578 return std::nullopt;
7582 return std::nullopt;
7584 unsigned OpFlags = STI.ClassifyGlobalReference(GV, MF.
getTarget());
7589 MIB.addGlobalAddress(GV,
Offset,
7599AArch64InstructionSelector::selectAddrModeIndexed(
MachineOperand &Root,
7600 unsigned Size)
const {
7605 return std::nullopt;
7608 if (RootDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX) {
7618 auto OpFns = tryFoldAddLowIntoImm(*RootDef,
Size,
MRI);
7623 if (isBaseWithConstantOffset(Root,
MRI)) {
7631 if ((RHSC & (
Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
7632 if (LHSDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
7647 if (selectAddrModeUnscaled(Root,
Size))
7648 return std::nullopt;
7659 switch (
MI.getOpcode()) {
7662 case TargetOpcode::G_SHL:
7664 case TargetOpcode::G_LSHR:
7666 case TargetOpcode::G_ASHR:
7668 case TargetOpcode::G_ROTR:
7676AArch64InstructionSelector::selectShiftedRegister(
MachineOperand &Root,
7677 bool AllowROR)
const {
7679 return std::nullopt;
7688 return std::nullopt;
7690 return std::nullopt;
7691 if (!isWorthFoldingIntoExtendedReg(*ShiftInst,
MRI,
false))
7692 return std::nullopt;
7698 return std::nullopt;
7705 unsigned NumBits =
MRI.getType(ShiftReg).getSizeInBits();
7706 unsigned Val = *Immed & (NumBits - 1);
7715 unsigned Opc =
MI.getOpcode();
7718 if (Opc == TargetOpcode::G_SEXT || Opc == TargetOpcode::G_SEXT_INREG) {
7720 if (Opc == TargetOpcode::G_SEXT)
7721 Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7723 Size =
MI.getOperand(2).getImm();
7724 assert(
Size != 64 &&
"Extend from 64 bits?");
7737 if (Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_ANYEXT) {
7738 unsigned Size =
MRI.getType(
MI.getOperand(1).getReg()).getSizeInBits();
7739 assert(
Size != 64 &&
"Extend from 64 bits?");
7754 if (Opc != TargetOpcode::G_AND)
7773Register AArch64InstructionSelector::moveScalarRegClass(
7776 auto Ty =
MRI.getType(Reg);
7785 return Copy.getReg(0);
7791AArch64InstructionSelector::selectArithExtendedRegister(
7794 return std::nullopt;
7803 return std::nullopt;
7805 if (!isWorthFoldingIntoExtendedReg(*RootDef,
MRI,
false))
7806 return std::nullopt;
7809 if (RootDef->
getOpcode() == TargetOpcode::G_SHL) {
7814 return std::nullopt;
7815 ShiftVal = *MaybeShiftVal;
7817 return std::nullopt;
7822 return std::nullopt;
7823 Ext = getExtendTypeForInst(*ExtDef,
MRI);
7825 return std::nullopt;
7829 Ext = getExtendTypeForInst(*RootDef,
MRI);
7831 return std::nullopt;
7840 if (isDef32(*ExtInst))
7841 return std::nullopt;
7848 ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
7852 MIB.addImm(getArithExtendImm(Ext, ShiftVal));
7857AArch64InstructionSelector::selectExtractHigh(
MachineOperand &Root)
const {
7859 return std::nullopt;
7864 while (Extract && Extract->MI->
getOpcode() == TargetOpcode::G_BITCAST &&
7865 STI.isLittleEndian())
7869 return std::nullopt;
7871 if (Extract->MI->
getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
7877 if (Extract->MI->
getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
7882 LaneIdx->Value.getSExtValue() == 1) {
7888 return std::nullopt;
7895 assert(
MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
7896 "Expected G_CONSTANT");
7897 std::optional<int64_t> CstVal =
7899 assert(CstVal &&
"Expected constant value");
7903void AArch64InstructionSelector::renderLogicalImm32(
7905 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
7906 "Expected G_CONSTANT");
7907 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7912void AArch64InstructionSelector::renderLogicalImm64(
7914 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
7915 "Expected G_CONSTANT");
7916 uint64_t CstVal =
I.getOperand(1).getCImm()->getZExtValue();
7924 assert(
MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
7925 "Expected G_UBSANTRAP");
7926 MIB.
addImm(
MI.getOperand(0).getImm() | (
'U' << 8));
7932 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7933 "Expected G_FCONSTANT");
7941 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7942 "Expected G_FCONSTANT");
7950 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7951 "Expected G_FCONSTANT");
7956void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
7958 assert(
MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7959 "Expected G_FCONSTANT");
7967bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
7969 if (!
MI.mayLoadOrStore())
7972 "Expected load/store to have only one mem op!");
7973 return (*
MI.memoperands_begin())->getSize() == NumBytes;
7976bool AArch64InstructionSelector::isDef32(
const MachineInstr &
MI)
const {
7978 if (
MRI.getType(
MI.getOperand(0).getReg()).getSizeInBits() != 32)
7985 switch (
MI.getOpcode()) {
7988 case TargetOpcode::COPY:
7989 case TargetOpcode::G_BITCAST:
7990 case TargetOpcode::G_TRUNC:
7991 case TargetOpcode::G_PHI:
8001 assert(
MI.getOpcode() == TargetOpcode::G_PHI &&
"Expected a G_PHI");
8004 assert(DstRB &&
"Expected PHI dst to have regbank assigned");
8015 auto *OpDef =
MRI.getVRegDef(OpReg);
8016 const LLT &Ty =
MRI.getType(OpReg);
8022 if (InsertPt != OpDefBB.
end() && InsertPt->isPHI())
8026 MRI.setRegBank(Copy.getReg(0), *DstRB);
8027 MO.setReg(Copy.getReg(0));
8036 for (
auto &BB : MF) {
8037 for (
auto &
MI : BB) {
8038 if (
MI.getOpcode() == TargetOpcode::G_PHI)
8043 for (
auto *
MI : Phis) {
8065 bool HasGPROp =
false, HasFPROp =
false;
8069 const LLT &Ty =
MRI.getType(MO.getReg());
8079 if (RB->
getID() == AArch64::GPRRegBankID)
8085 if (HasGPROp && HasFPROp)
8095 return new AArch64InstructionSelector(TM, Subtarget, RBI);
unsigned const MachineRegisterInfo * MRI
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 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).
static unsigned selectFPConvOpc(unsigned GenericOpc, LLT DstTy, LLT SrcTy)
#define GET_GLOBALISEL_PREDICATES_INIT
static std::pair< const TargetRegisterClass *, const TargetRegisterClass * > getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Helper function to get the source and destination register classes for a copy.
#define GET_GLOBALISEL_TEMPORARIES_INIT
static void changeFPCCToANDAArch64CC(CmpInst::Predicate CC, AArch64CC::CondCode &CondCode, AArch64CC::CondCode &CondCode2)
Convert an IR fp condition code to an AArch64 CC.
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 AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P)
static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID, unsigned OpSize)
Select the AArch64 opcode for the basic binary operation GenericOpc (such as G_OR or G_SDIV),...
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 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 bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)
static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI)
Given a shift instruction, return the correct shift type for that instruction.
static bool unsupportedBinOp(const MachineInstr &I, const AArch64RegisterBankInfo &RBI, const MachineRegisterInfo &MRI, const AArch64RegisterInfo &TRI)
Check whether I is a currently unsupported binary operation:
static bool canEmitConjunction(Register Val, bool &CanNegate, bool &MustBeFirst, bool WillNegate, MachineRegisterInfo &MRI, unsigned Depth=0)
Returns true if Val is a tree of AND/OR/CMP operations that can be expressed as a conjunction.
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.
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)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file contains constants used for implementing Dwarf debug support.
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)
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.
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static constexpr int Concat[]
AArch64FunctionInfo - This class is derived from MachineFunctionInfo and contains private AArch64-spe...
unsigned getVarArgsFPRSize() const
bool hasELFSignedGOT() const
int getVarArgsFPRIndex() const
int getVarArgsStackIndex() const
int getVarArgsGPRIndex() const
unsigned getVarArgsGPRSize() const
This class provides the information for the target register banks.
bool isCallingConvWin64(CallingConv::ID CC, bool IsVarArg) const
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
APInt trunc(unsigned width) const
Truncate to new width.
static 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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
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 getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
bool isIntPredicate() const
static Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
ConstantFP - Floating Point Values [float, double].
const APFloat & getValueAPF() const
bool isNegative() const
Return true if the sign bit is set.
bool isZero() const
Return true if the value is positive or negative zero.
This is the shared class of boolean and integer constants.
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 Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
const APInt & getUniqueInteger() const
If C is a constant integer then return its value, otherwise C must be a vector of constant integers,...
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
This class represents an Operation in the Expression.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
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.
std::optional< SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > > ComplexRendererFns
Represents indexed stores.
Represents any type of generic load or store.
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
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.
constexpr LLT multiplyElements(int Factor) const
Produce a vector type that is Factor times bigger, preserving the element type.
constexpr bool isPointerVector() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
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 LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
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.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
This is an important class for using LLVM in a threaded context.
TypeSize getValue() const
Describe properties that are true of each instruction in the target description file.
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.
The MachineConstantPool class keeps track of constants referenced by a function which must be spilled...
unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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.
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.
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 & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
void addMemOperand(MachineFunction &MF, MachineMemOperand *MO)
Add a MachineMemOperand to the machine instruction.
A description of a memory reference used in the backend.
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.
void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
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 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,...
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.
This class represents the LLVM 'select' instruction.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
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
getRegisterInfo - If register information is available, return it.
virtual const TargetLowering * getTargetLowering() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static constexpr TypeSize getFixed(ScalarTy ExactSize)
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static IntegerType * getInt8Ty(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
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 isAdvSIMDModImmType1(uint64_t Imm)
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.
@ C
The default llvm calling convention, compatible with C.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(int64_t 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)
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.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Undef
Value of the register doesn't matter.
Reg
All possible values of the reg field in the ModR/M byte.
NodeAddr< InstrNode * > Instr
This is an optimization pass for GlobalISel generic memory operations.
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.
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...
MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
bool 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...
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.
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
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.
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.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
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...
AtomicOrdering
Atomic ordering for LLVM's memory model.
DWARFExpression::Operation Op
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...
std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Class which stores all the state required in a MachineIRBuilder.
This class contains a discriminated union of information about pointers in memory operands,...
static MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.