45#define DEBUG_TYPE "gi-combiner"
48using namespace MIPatternMatch;
54 cl::desc(
"Force all indexed operations to be "
55 "legal for the GlobalISel combiner"));
62 : Builder(
B),
MRI(Builder.getMF().getRegInfo()), Observer(Observer), VT(VT),
63 MDT(MDT), IsPreLegalize(IsPreLegalize), LI(LI),
64 RBI(Builder.getMF().getSubtarget().getRegBankInfo()),
65 TRI(Builder.getMF().getSubtarget().getRegisterInfo()) {
88 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
107 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
108 return ByteWidth -
I - 1;
128static std::optional<bool>
132 unsigned Width = MemOffset2Idx.
size();
135 bool BigEndian =
true, LittleEndian =
true;
136 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
137 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
138 if (MemOffsetAndIdx == MemOffset2Idx.
end())
140 const int64_t
Idx = MemOffsetAndIdx->second - LowestIdx;
141 assert(
Idx >= 0 &&
"Expected non-negative byte offset?");
144 if (!BigEndian && !LittleEndian)
148 assert((BigEndian != LittleEndian) &&
149 "Pattern cannot be both big and little endian!");
156 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
177 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
178 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
205 unsigned ToOpcode)
const {
231 if (
MI.getOpcode() != TargetOpcode::COPY)
241 MI.eraseFromParent();
262 if (OrigDef->
isPHI() || isa<GUnmerge>(OrigDef))
269 std::optional<MachineOperand> MaybePoisonOperand;
271 if (!Operand.isReg())
277 if (!MaybePoisonOperand)
278 MaybePoisonOperand = Operand;
287 if (!MaybePoisonOperand) {
290 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
292 B.buildCopy(
DstOp, OrigOp);
297 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
298 LLT MaybePoisonOperandRegTy =
MRI.
getType(MaybePoisonOperandReg);
302 cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
305 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
316 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
317 "Invalid instruction");
327 assert(Def &&
"Operand not defined");
330 switch (Def->getOpcode()) {
331 case TargetOpcode::G_BUILD_VECTOR:
338 case TargetOpcode::G_IMPLICIT_DEF: {
347 "All undefs should have the same type");
351 EltIdx != EltEnd; ++EltIdx)
352 Ops.
push_back(Undef->getOperand(0).getReg());
363 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.
getType(Ops[0])}})) {
391 MI.eraseFromParent();
395 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
396 "Invalid instruction");
397 auto &Shuffle = cast<GShuffleVector>(
MI);
399 Register SrcVec1 = Shuffle.getSrc1Reg();
400 Register SrcVec2 = Shuffle.getSrc2Reg();
408 auto &Shuffle = cast<GShuffleVector>(
MI);
410 Register SrcVec1 = Shuffle.getSrc1Reg();
411 Register SrcVec2 = Shuffle.getSrc2Reg();
420 for (
int Val : Shuffle.getMask()) {
423 else if (Val < Width)
424 Extracts.
push_back(Unmerge1.getReg(Val));
426 Extracts.
push_back(Unmerge2.getReg(Val - Width));
428 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
429 if (Extracts.
size() == 1)
433 MI.eraseFromParent();
443 if (!ConcatMI1 || !ConcatMI2)
447 if (
MRI.
getType(ConcatMI1->getSourceReg(0)) !=
454 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
458 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
459 if (i + j >= Mask.size())
461 if (Mask[i + j] != -1)
465 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
468 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
469 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
470 if (i + j >= Mask.size())
472 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
478 Ops.
push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
480 Ops.
push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
481 ConcatMI1->getNumSources()));
489 {TargetOpcode::G_CONCAT_VECTORS,
490 {
MRI.
getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
503 assert(SrcTy.
isValid() &&
"Unexpected full undef vector in concat combine");
519 MI.eraseFromParent();
533 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
534 "Invalid instruction kind");
559 if (DstNumElts < 2 * SrcNumElts && DstNumElts != 1)
564 if (DstNumElts % SrcNumElts != 0)
570 unsigned NumConcat = DstNumElts / SrcNumElts;
573 for (
unsigned i = 0; i != DstNumElts; ++i) {
580 if ((
Idx % SrcNumElts != (i % SrcNumElts)) ||
581 (ConcatSrcs[i / SrcNumElts] >= 0 &&
582 ConcatSrcs[i / SrcNumElts] != (
int)(
Idx / SrcNumElts)))
585 ConcatSrcs[i / SrcNumElts] =
Idx / SrcNumElts;
592 for (
auto Src : ConcatSrcs) {
619 MI.eraseFromParent();
623 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
624 "Invalid instruction kind");
627 return Mask.size() == 1;
634 int I =
MI.getOperand(3).getShuffleMask()[0];
639 if (
I >= Src1NumElts) {
640 SrcReg =
MI.getOperand(2).getReg();
652 MI.eraseFromParent();
661 const LLT TyForCandidate,
662 unsigned OpcodeForCandidate,
667 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
678 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
681 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
682 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
683 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
689 if (!isa<GZExtLoad>(LoadMI) && CurrentUse.
Ty == TyForCandidate) {
691 OpcodeForCandidate == TargetOpcode::G_ZEXT)
693 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
694 OpcodeForCandidate == TargetOpcode::G_SEXT)
695 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
704 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
715static void InsertInsnsWithoutSideEffectsBeforeUse(
727 InsertBB = PredBB->
getMBB();
732 if (InsertBB ==
DefMI.getParent()) {
734 Inserter(InsertBB, std::next(InsertPt), UseMO);
753 unsigned CandidateLoadOpc;
755 case TargetOpcode::G_ANYEXT:
756 CandidateLoadOpc = TargetOpcode::G_LOAD;
758 case TargetOpcode::G_SEXT:
759 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
761 case TargetOpcode::G_ZEXT:
762 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
767 return CandidateLoadOpc;
798 if (!llvm::has_single_bit<uint32_t>(LoadValueTy.
getSizeInBits()))
806 unsigned PreferredOpcode =
808 ? TargetOpcode::G_ANYEXT
809 : isa<GSExtLoad>(&
MI) ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
810 Preferred = {
LLT(), PreferredOpcode,
nullptr};
812 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
813 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
814 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
815 const auto &MMO = LoadMI->
getMMO();
825 if (
LI->
getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
829 Preferred = ChoosePreferredUse(
MI, Preferred,
840 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
858 if (PreviouslyEmitted) {
868 EmittedInsns[InsertIntoBB] = NewMI;
881 for (
auto *UseMO :
Uses) {
891 if (UseDstReg != ChosenDstReg) {
892 if (Preferred.
Ty == UseDstTy) {
929 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
944 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
947 MI.getOperand(0).setReg(ChosenDstReg);
953 assert(
MI.getOpcode() == TargetOpcode::G_AND);
972 APInt MaskVal = MaybeMask->Value;
993 if (MaskSizeBits > LoadSizeBits.
getValue())
1013 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
1019 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.
getType(PtrReg)}, {MemDesc}}))
1023 B.setInstrAndDebugLoc(*LoadMI);
1024 auto &MF =
B.getMF();
1026 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
1027 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1036 "shouldn't consider debug uses");
1044 if (DefOrUse ==
MBB.
end())
1046 return &*DefOrUse == &
DefMI;
1052 "shouldn't consider debug uses");
1055 else if (
DefMI.getParent() !=
UseMI.getParent())
1062 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1071 LoadUser = TruncSrc;
1073 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1076 if (
auto *LoadMI = getOpcodeDef<GSExtLoad>(LoadUser,
MRI)) {
1078 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1082 if (LoadSizeBits == SizeInBits)
1089 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1091 MI.eraseFromParent();
1095 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1096 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1106 auto *LoadDef = getOpcodeDef<GLoad>(SrcReg,
MRI);
1110 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1115 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1118 if (NewSizeBits < 8)
1130 if (LoadDef->isSimple())
1132 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1142 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1147 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1148 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1150 unsigned ScalarSizeBits;
1151 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1160 auto &MMO = LoadDef->
getMMO();
1163 auto PtrInfo = MMO.getPointerInfo();
1167 MI.eraseFromParent();
1178 auto *MF =
MI->getMF();
1179 auto *
Addr = getOpcodeDef<GPtrAdd>(
MI->getPointerReg(),
MRI);
1185 AM.
BaseOffs = CstOff->getSExtValue();
1190 MF->getDataLayout(), AM,
1192 MF->getFunction().getContext()),
1193 MI->getMMO().getAddrSpace());
1198 case TargetOpcode::G_LOAD:
1199 return TargetOpcode::G_INDEXED_LOAD;
1200 case TargetOpcode::G_STORE:
1201 return TargetOpcode::G_INDEXED_STORE;
1202 case TargetOpcode::G_ZEXTLOAD:
1203 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1204 case TargetOpcode::G_SEXTLOAD:
1205 return TargetOpcode::G_INDEXED_SEXTLOAD;
1211bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1221 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1222 OpTys = {PtrTy, Ty, Ty};
1224 OpTys = {Ty, PtrTy};
1232 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1233 "considered for post-indexing."));
1237 bool &RematOffset)
const {
1250 if (!isIndexedLoadStoreLegal(LdSt))
1259 unsigned NumUsesChecked = 0;
1264 auto *PtrAdd = dyn_cast<GPtrAdd>(&
Use);
1272 if (StoredValDef == &
Use)
1275 Offset = PtrAdd->getOffsetReg();
1277 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1283 RematOffset =
false;
1287 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1293 if (&BasePtrUse == PtrDef)
1298 auto *BasePtrLdSt = dyn_cast<GLoadStore>(&BasePtrUse);
1299 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1301 isIndexedLoadStoreLegal(*BasePtrLdSt))
1306 if (
auto *BasePtrUseDef = dyn_cast<GPtrAdd>(&BasePtrUse)) {
1307 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1311 if (BaseUseUse.getParent() != LdSt.
getParent())
1314 if (
auto *UseUseLdSt = dyn_cast<GLoadStore>(&BaseUseUse))
1323 Addr = PtrAdd->getReg(0);
1324 Base = PtrAdd->getBaseReg();
1346 if (!isIndexedLoadStoreLegal(LdSt))
1350 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1353 if (
auto *St = dyn_cast<GStore>(&LdSt)) {
1355 if (
Base == St->getValueReg())
1360 if (St->getValueReg() ==
Addr)
1366 if (AddrUse.getParent() != LdSt.
getParent())
1371 bool RealUse =
false;
1378 if (
auto *UseLdSt = dyn_cast<GLoadStore>(&AddrUse)) {
1390 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1393 auto *LoadMI = getOpcodeDef<GLoad>(
MI.getOperand(1).getReg(),
MRI);
1407 if (!LoadMI->isSimple())
1419 const unsigned MaxIter = 20;
1422 if (
II->isLoadFoldBarrier())
1424 if (Iter++ == MaxIter)
1440 int Elt = CVal->getZExtValue();
1453 Register VecPtr = LoadMI->getPointerReg();
1462 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1485 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1495 auto &LdSt = cast<GLoadStore>(
MI);
1500 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1502 if (!MatchInfo.
IsPre &&
1503 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1513 unsigned Opcode =
MI.getOpcode();
1514 bool IsStore = Opcode == TargetOpcode::G_STORE;
1522 *OldCst->getOperand(1).getCImm());
1523 MatchInfo.
Offset = NewCst.getReg(0);
1529 MIB.
addUse(
MI.getOperand(0).getReg());
1531 MIB.
addDef(
MI.getOperand(0).getReg());
1539 MI.eraseFromParent();
1547 unsigned Opcode =
MI.getOpcode();
1548 bool IsDiv, IsSigned;
1553 case TargetOpcode::G_SDIV:
1554 case TargetOpcode::G_UDIV: {
1556 IsSigned = Opcode == TargetOpcode::G_SDIV;
1559 case TargetOpcode::G_SREM:
1560 case TargetOpcode::G_UREM: {
1562 IsSigned = Opcode == TargetOpcode::G_SREM;
1568 unsigned DivOpcode, RemOpcode, DivremOpcode;
1570 DivOpcode = TargetOpcode::G_SDIV;
1571 RemOpcode = TargetOpcode::G_SREM;
1572 DivremOpcode = TargetOpcode::G_SDIVREM;
1574 DivOpcode = TargetOpcode::G_UDIV;
1575 RemOpcode = TargetOpcode::G_UREM;
1576 DivremOpcode = TargetOpcode::G_UDIVREM;
1595 if (
MI.getParent() ==
UseMI.getParent() &&
1596 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1597 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1610 unsigned Opcode =
MI.getOpcode();
1611 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1614 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1615 DestDivReg =
MI.getOperand(0).getReg();
1619 DestRemReg =
MI.getOperand(0).getReg();
1623 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1633 : TargetOpcode::G_UDIVREM,
1634 {DestDivReg, DestRemReg},
1636 MI.eraseFromParent();
1642 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1661 assert(std::next(BrIt) ==
MBB->
end() &&
"expected G_BR to be a terminator");
1663 BrCond = &*std::prev(BrIt);
1664 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1670 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1688 MI.getOperand(0).setMBB(FallthroughBB);
1703 return Helper.lowerMemcpyInline(
MI) ==
1708 unsigned MaxLen)
const {
1720 switch (
MI.getOpcode()) {
1723 case TargetOpcode::G_FNEG: {
1724 Result.changeSign();
1727 case TargetOpcode::G_FABS: {
1731 case TargetOpcode::G_FPTRUNC: {
1733 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1738 case TargetOpcode::G_FSQRT: {
1742 Result =
APFloat(sqrt(Result.convertToDouble()));
1745 case TargetOpcode::G_FLOG2: {
1766 MI.eraseFromParent();
1777 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1787 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1800 Type *AccessTy =
nullptr;
1801 auto &MF = *
MI.getMF();
1803 if (
auto *LdSt = dyn_cast<GLoadStore>(&
UseMI)) {
1805 MF.getFunction().getContext());
1810 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1815 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1818 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1819 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1820 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1829 unsigned PtrAddFlags =
MI.getFlags();
1830 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1846 MatchInfo.
Flags = Flags;
1852 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1858 MI.getOperand(1).setReg(MatchInfo.
Base);
1859 MI.getOperand(2).setReg(NewOffset.getReg(0));
1873 unsigned Opcode =
MI.getOpcode();
1874 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1875 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1876 Opcode == TargetOpcode::G_USHLSAT) &&
1877 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1897 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1902 if (Opcode == TargetOpcode::G_USHLSAT &&
1911 unsigned Opcode =
MI.getOpcode();
1912 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1913 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1914 Opcode == TargetOpcode::G_USHLSAT) &&
1915 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1919 auto Imm = MatchInfo.
Imm;
1921 if (Imm >= ScalarSizeInBits) {
1923 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1925 MI.eraseFromParent();
1930 Imm = ScalarSizeInBits - 1;
1936 MI.getOperand(1).setReg(MatchInfo.
Reg);
1937 MI.getOperand(2).setReg(NewImm);
1953 unsigned ShiftOpcode =
MI.getOpcode();
1954 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1955 ShiftOpcode == TargetOpcode::G_ASHR ||
1956 ShiftOpcode == TargetOpcode::G_LSHR ||
1957 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1958 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1959 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1962 Register LogicDest =
MI.getOperand(1).getReg();
1967 unsigned LogicOpcode = LogicMI->
getOpcode();
1968 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1969 LogicOpcode != TargetOpcode::G_XOR)
1973 const Register C1 =
MI.getOperand(2).getReg();
1975 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1978 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1982 if (
MI->getOpcode() != ShiftOpcode ||
1992 ShiftVal = MaybeImmVal->Value.getSExtValue();
2003 if (matchFirstShift(LogicMIOp1, C0Val)) {
2005 MatchInfo.
Shift2 = LogicMIOp1;
2006 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2008 MatchInfo.
Shift2 = LogicMIOp2;
2012 MatchInfo.
ValSum = C0Val + C1Val;
2018 MatchInfo.
Logic = LogicMI;
2024 unsigned Opcode =
MI.getOpcode();
2025 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2026 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2027 Opcode == TargetOpcode::G_SSHLSAT) &&
2028 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2046 Register Shift2Const =
MI.getOperand(2).getReg();
2058 MI.eraseFromParent();
2063 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2066 auto &Shl = cast<GenericMachineInstr>(
MI);
2086 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2087 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2090 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2091 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2092 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {
S1, S2});
2098 unsigned &ShiftVal)
const {
2099 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2105 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2106 return (
static_cast<int32_t
>(ShiftVal) != -1);
2110 unsigned &ShiftVal)
const {
2111 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2116 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2117 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2138 auto NegCst =
B.buildConstant(Ty, -Imm);
2140 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2141 MI.getOperand(2).setReg(NegCst.getReg(0));
2143 if (Imm.isMinSignedValue())
2153 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2168 if (!MaybeShiftAmtVal)
2182 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2183 MatchData.
Reg = ExtSrc;
2184 MatchData.
Imm = ShiftAmt;
2188 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2194 int64_t ShiftAmtVal = MatchData.
Imm;
2201 MI.eraseFromParent();
2208 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2211 auto *Unmerge = getOpcodeDef<GUnmerge>(MergedValues[0],
MRI);
2212 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2215 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2216 if (MergedValues[
I] != Unmerge->getReg(
I))
2219 MatchInfo = Unmerge->getSourceReg();
2233 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2234 "Expected an unmerge");
2235 auto &Unmerge = cast<GUnmerge>(
MI);
2238 auto *SrcInstr = getOpcodeDef<GMergeLikeInstr>(SrcReg,
MRI);
2246 if (SrcMergeTy != Dst0Ty && !SameSize)
2250 for (
unsigned Idx = 0;
Idx < SrcInstr->getNumSources(); ++
Idx)
2257 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2258 "Expected an unmerge");
2260 "Not enough operands to replace all defs");
2261 unsigned NumElems =
MI.getNumOperands() - 1;
2265 bool CanReuseInputDirectly = DstTy == SrcTy;
2266 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2278 if (CanReuseInputDirectly)
2283 MI.eraseFromParent();
2288 unsigned SrcIdx =
MI.getNumOperands() - 1;
2289 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2291 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2292 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2303 for (
unsigned Idx = 0;
Idx != SrcIdx; ++
Idx) {
2305 Val = Val.
lshr(ShiftAmt);
2313 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2314 "Expected an unmerge");
2316 "Not enough operands to replace all defs");
2317 unsigned NumElems =
MI.getNumOperands() - 1;
2318 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2323 MI.eraseFromParent();
2329 unsigned SrcIdx =
MI.getNumOperands() - 1;
2330 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2332 unsigned NumElems =
MI.getNumOperands() - 1;
2333 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
2335 B.buildUndef(DstReg);
2343 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2344 "Expected an unmerge");
2349 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2358 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2359 Register Dst0Reg =
MI.getOperand(0).getReg();
2361 MI.eraseFromParent();
2365 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2366 "Expected an unmerge");
2367 Register Dst0Reg =
MI.getOperand(0).getReg();
2374 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2391 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2392 "Expected an unmerge");
2394 Register Dst0Reg =
MI.getOperand(0).getReg();
2399 "Expecting a G_ZEXT");
2409 "ZExt src doesn't fit in destination");
2414 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs();
Idx != EndIdx; ++
Idx) {
2419 MI.eraseFromParent();
2423 unsigned TargetShiftSize,
2424 unsigned &ShiftVal)
const {
2425 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2426 MI.getOpcode() == TargetOpcode::G_LSHR ||
2427 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2435 if (
Size <= TargetShiftSize)
2443 ShiftVal = MaybeImmVal->Value.getSExtValue();
2444 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2453 unsigned HalfSize =
Size / 2;
2454 assert(ShiftVal >= HalfSize);
2459 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2461 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2462 Register Narrowed = Unmerge.getReg(1);
2469 if (NarrowShiftAmt != 0) {
2476 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2477 Register Narrowed = Unmerge.getReg(0);
2482 if (NarrowShiftAmt != 0) {
2490 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2492 HalfTy, Unmerge.getReg(1),
2495 if (ShiftVal == HalfSize) {
2499 }
else if (ShiftVal ==
Size - 1) {
2507 HalfTy, Unmerge.getReg(1),
2516 MI.eraseFromParent();
2532 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2542 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2545 MI.eraseFromParent();
2550 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2553 MI.eraseFromParent();
2558 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2565 PtrReg.second =
false;
2575 PtrReg.second =
true;
2587 const bool DoCommute = PtrReg.second;
2596 MI.eraseFromParent();
2600 APInt &NewCst)
const {
2601 auto &PtrAdd = cast<GPtrAdd>(
MI);
2612 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2621 APInt &NewCst)
const {
2622 auto &PtrAdd = cast<GPtrAdd>(
MI);
2626 PtrAdd.eraseFromParent();
2631 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2636 SrcReg = OriginalSrcReg;
2645 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2664 if (ShiftSize > 32 && TruncSize < 32)
2677 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2678 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2695 case TargetOpcode::G_SHL: {
2704 case TargetOpcode::G_LSHR:
2705 case TargetOpcode::G_ASHR: {
2712 if (
User.getOpcode() == TargetOpcode::G_STORE)
2716 if (NewShiftTy == SrcTy)
2730 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2733 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2738 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2740 LLT NewShiftTy = MatchInfo.second;
2754 if (NewShiftTy == DstTy)
2764 return MO.isReg() &&
2765 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2771 return !MO.isReg() ||
2772 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2777 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2779 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2783 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2784 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2789 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2790 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2796 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2797 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2798 "Expected an insert/extract element op");
2804 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2812 unsigned &
OpIdx)
const {
2818 OpIdx = Cst->isZero() ? 3 : 2;
2863 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2890 return MO.isReg() && MO.getReg().isPhysical();
2900 return I1->isIdenticalTo(*I2);
2915 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2927 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2928 MaybeCst->getSExtValue() ==
C;
2935 std::optional<FPValueAndVReg> MaybeCst;
2939 return MaybeCst->Value.isExactlyValue(
C);
2943 unsigned OpIdx)
const {
2944 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2949 MI.eraseFromParent();
2954 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2958 MI.eraseFromParent();
2962 unsigned ConstIdx)
const {
2963 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2976 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2977 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2978 "This is not a funnel shift operation");
2980 Register ConstReg =
MI.getOperand(3).getReg();
2985 assert((VRegAndVal) &&
"Value is not a constant");
2988 APInt NewConst = VRegAndVal->Value.
urem(
2993 MI.getOpcode(), {MI.getOperand(0)},
2994 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2996 MI.eraseFromParent();
3000 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3014 unsigned OpIdx)
const {
3021 unsigned OpIdx)
const {
3023 return MO.
isReg() &&
3028 unsigned OpIdx)
const {
3035 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3037 MI.eraseFromParent();
3042 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3044 MI.eraseFromParent();
3048 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3050 MI.eraseFromParent();
3055 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3057 MI.eraseFromParent();
3061 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3063 MI.eraseFromParent();
3067 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3070 Register &NewLHS = std::get<0>(MatchInfo);
3071 Register &NewRHS = std::get<1>(MatchInfo);
3079 NewLHS = MaybeNewLHS;
3088 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3101 TargetOpcode::G_INSERT_VECTOR_ELT)
3107 MatchInfo.
resize(NumElts);
3111 if (IntImm >= NumElts || IntImm < 0)
3113 if (!MatchInfo[IntImm])
3114 MatchInfo[IntImm] = TmpReg;
3118 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3120 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3129 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3136 auto GetUndef = [&]() {
3148 MI.eraseFromParent();
3152 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3154 std::tie(SubLHS, SubRHS) = MatchInfo;
3156 MI.eraseFromParent();
3167 unsigned LogicOpcode =
MI.getOpcode();
3168 assert(LogicOpcode == TargetOpcode::G_AND ||
3169 LogicOpcode == TargetOpcode::G_OR ||
3170 LogicOpcode == TargetOpcode::G_XOR);
3183 if (!LeftHandInst || !RightHandInst)
3185 unsigned HandOpcode = LeftHandInst->
getOpcode();
3186 if (HandOpcode != RightHandInst->
getOpcode())
3200 if (!XTy.
isValid() || XTy != YTy)
3205 switch (HandOpcode) {
3208 case TargetOpcode::G_ANYEXT:
3209 case TargetOpcode::G_SEXT:
3210 case TargetOpcode::G_ZEXT: {
3214 case TargetOpcode::G_TRUNC: {
3228 case TargetOpcode::G_AND:
3229 case TargetOpcode::G_ASHR:
3230 case TargetOpcode::G_LSHR:
3231 case TargetOpcode::G_SHL: {
3236 ExtraHandOpSrcReg = ZOp.
getReg();
3258 if (ExtraHandOpSrcReg.
isValid())
3270 "Expected at least one instr to build?");
3272 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3273 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3275 for (
auto &OperandFn : InstrToBuild.OperandFns)
3278 MI.eraseFromParent();
3282 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3283 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3284 int64_t ShlCst, AshrCst;
3290 if (ShlCst != AshrCst)
3293 {TargetOpcode::G_SEXT_INREG, {
MRI.
getType(Src)}}))
3295 MatchInfo = std::make_tuple(Src, ShlCst);
3300 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3301 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3304 std::tie(Src, ShiftAmt) = MatchInfo;
3307 MI.eraseFromParent();
3314 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3329 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3332 auto Zero =
B.buildConstant(Ty, 0);
3355 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3379 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3386 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3403 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3421 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3428 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3439 unsigned ExtBits =
MI.getOperand(2).getImm();
3445 int64_t Cst,
bool IsVector,
bool IsFP) {
3447 return (ScalarSizeBits == 1 && Cst == -1) ||
3470 unsigned NumOperands =
BuildMI->getNumSources();
3478 for (
I = 0;
I < NumOperands; ++
I) {
3483 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3486 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3489 auto UnmergeSrcMI =
MRI.
getVRegDef(SrcMI->getOperand(1).getReg());
3490 if (UnmergeMI != UnmergeSrcMI)
3501 for (;
I < NumOperands; ++
I) {
3505 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3510 MatchInfo = cast<GUnmerge>(UnmergeMI)->getSourceReg();
3519 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3527 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3530 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3548 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3553 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3561 MI.eraseFromParent();
3566 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3586 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3591 switch (Def->getOpcode()) {
3596 case TargetOpcode::G_ICMP:
3602 case TargetOpcode::G_FCMP:
3608 case TargetOpcode::G_AND:
3609 case TargetOpcode::G_OR:
3615 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3616 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3643 for (
Register Reg : RegsToNegate) {
3648 switch (Def->getOpcode()) {
3651 case TargetOpcode::G_ICMP:
3652 case TargetOpcode::G_FCMP: {
3659 case TargetOpcode::G_AND:
3662 case TargetOpcode::G_OR:
3670 MI.eraseFromParent();
3674 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3676 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3680 Register SharedReg =
MI.getOperand(2).getReg();
3701 return Y == SharedReg;
3705 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3708 std::tie(
X,
Y) = MatchInfo;
3712 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3713 MI.getOperand(2).setReg(
Y);
3718 auto &PtrAdd = cast<GPtrAdd>(
MI);
3719 Register DstReg = PtrAdd.getReg(0);
3728 return ConstVal && *ConstVal == 0;
3737 auto &PtrAdd = cast<GPtrAdd>(
MI);
3739 PtrAdd.eraseFromParent();
3746 Register Pow2Src1 =
MI.getOperand(2).getReg();
3753 MI.eraseFromParent();
3757 unsigned &SelectOpNo)
const {
3767 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3769 OtherOperandReg =
LHS;
3772 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3789 unsigned BinOpcode =
MI.getOpcode();
3794 bool CanFoldNonConst =
3795 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3800 if (CanFoldNonConst)
3822 unsigned BinOpcode =
MI.getOpcode();
3829 if (SelectOperand == 1) {
3843 MI.eraseFromParent();
3846std::optional<SmallVector<Register, 8>>
3847CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3848 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3877 const unsigned MaxIter =
3879 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3888 return std::nullopt;
3904 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3905 return std::nullopt;
3917static std::optional<std::pair<GZExtLoad *, int64_t>>
3921 "Expected Reg to only have one non-debug use?");
3930 if (Shift % MemSizeInBits != 0)
3931 return std::nullopt;
3934 auto *Load = getOpcodeDef<GZExtLoad>(MaybeLoad,
MRI);
3936 return std::nullopt;
3938 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
3939 return std::nullopt;
3941 return std::make_pair(Load, Shift / MemSizeInBits);
3944std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
3945CombinerHelper::findLoadOffsetsForLoadOrCombine(
3948 const unsigned MemSizeInBits)
const {
3980 for (
auto Reg : RegsToVisit) {
3985 return std::nullopt;
3988 std::tie(Load, DstPos) = *LoadAndPos;
3996 return std::nullopt;
3999 auto &LoadMMO =
Load->getMMO();
4003 return std::nullopt;
4010 LoadPtr =
Load->getOperand(1).getReg();
4016 return std::nullopt;
4023 if (BasePtr != LoadPtr)
4024 return std::nullopt;
4026 if (
Idx < LowestIdx) {
4028 LowestIdxLoad =
Load;
4036 return std::nullopt;
4044 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4045 EarliestLoad =
Load;
4046 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4053 "Expected to find a load for each register?");
4054 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4055 LatestLoad &&
"Expected at least two loads?");
4064 const unsigned MaxIter = 20;
4070 if (
MI.isLoadFoldBarrier())
4071 return std::nullopt;
4072 if (Iter++ == MaxIter)
4073 return std::nullopt;
4076 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4082 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4102 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4106 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4113 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4114 if (NarrowMemSizeInBits % 8 != 0)
4127 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4128 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4131 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4138 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4141 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4153 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4154 const unsigned ZeroByteOffset =
4158 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4159 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4160 ZeroOffsetIdx->second != LowestIdx)
4184 MIB.setInstrAndDebugLoc(*LatestLoad);
4186 MIB.buildLoad(LoadDst,
Ptr, *NewMMO);
4188 MIB.buildBSwap(Dst, LoadDst);
4195 auto &
PHI = cast<GPhi>(
MI);
4208 case TargetOpcode::G_ANYEXT:
4210 case TargetOpcode::G_ZEXT:
4211 case TargetOpcode::G_SEXT:
4225 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4228 case TargetOpcode::G_LOAD:
4229 case TargetOpcode::G_TRUNC:
4230 case TargetOpcode::G_SEXT:
4231 case TargetOpcode::G_ZEXT:
4232 case TargetOpcode::G_ANYEXT:
4233 case TargetOpcode::G_CONSTANT:
4237 if (InSrcs.
size() > 2)
4249 auto &
PHI = cast<GPhi>(
MI);
4258 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4259 auto SrcReg =
PHI.getIncomingValue(
I);
4261 if (!SrcMIs.
insert(SrcMI))
4267 if (InsertPt !=
MBB->
end() && InsertPt->isPHI())
4273 OldToNewSrcMap[SrcMI] = NewExt;
4282 NewPhi.
addMBB(MO.getMBB());
4286 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4294 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4306 unsigned VecIdx = Cst->Value.getZExtValue();
4311 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4315 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4316 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4336 if (ScalarTy != DstTy) {
4339 MI.eraseFromParent();
4347 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4348 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4371 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4376 unsigned Idx = Cst->getZExtValue();
4380 SrcDstPairs.emplace_back(
4381 std::make_pair(
MI.getOperand(
Idx + 1).getReg(), &
II));
4384 return ExtractedElts.
all();
4389 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4390 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4391 for (
auto &Pair : SrcDstPairs) {
4392 auto *ExtMI = Pair.second;
4394 ExtMI->eraseFromParent();
4396 MI.eraseFromParent();
4403 MI.eraseFromParent();
4414 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4420 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4421 unsigned FshOpc = 0;
4432 int64_t CstShlAmt, CstLShrAmt;
4435 CstShlAmt + CstLShrAmt ==
BitWidth) {
4436 FshOpc = TargetOpcode::G_FSHR;
4443 FshOpc = TargetOpcode::G_FSHL;
4449 FshOpc = TargetOpcode::G_FSHR;
4460 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4467 unsigned Opc =
MI.getOpcode();
4468 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4473 unsigned RotateOpc =
4474 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4479 unsigned Opc =
MI.getOpcode();
4480 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4481 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4484 : TargetOpcode::G_ROTR));
4485 MI.removeOperand(2);
4491 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4492 MI.getOpcode() == TargetOpcode::G_ROTR);
4496 bool OutOfRange =
false;
4497 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4498 if (
auto *CI = dyn_cast<ConstantInt>(
C))
4499 OutOfRange |= CI->getValue().uge(Bitsize);
4506 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4507 MI.getOpcode() == TargetOpcode::G_ROTR);
4515 MI.getOperand(2).setReg(Amt);
4520 int64_t &MatchInfo)
const {
4521 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4533 if (KnownRHS.isUnknown())
4536 std::optional<bool> KnownVal;
4537 if (KnownRHS.isZero()) {
4566 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4591 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4597 unsigned Op = TargetOpcode::COPY;
4598 if (DstSize != LHSSize)
4599 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4610 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4620 int64_t AndMaskBits;
4628 if (AndMaskBits & OrMaskBits)
4634 if (
MI.getOperand(1).getReg() == AndMaskReg)
4635 MI.getOperand(2).setReg(AndMaskReg);
4636 MI.getOperand(1).setReg(Src);
4646 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4653 int64_t Width =
MI.getOperand(2).getImm();
4665 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4666 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4667 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4684 int64_t AndImm, LSBImm;
4693 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4694 if (MaybeMask & (MaybeMask + 1))
4703 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4704 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4705 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4713 const unsigned Opcode =
MI.getOpcode();
4714 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4716 const Register Dst =
MI.getOperand(0).getReg();
4718 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4719 ? TargetOpcode::G_SBFX
4720 : TargetOpcode::G_UBFX;
4741 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4745 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4749 const int64_t Pos = ShrAmt - ShlAmt;
4750 const int64_t Width =
Size - ShrAmt;
4753 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4754 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4755 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4763 const unsigned Opcode =
MI.getOpcode();
4764 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4766 const Register Dst =
MI.getOperand(0).getReg();
4783 if (ShrAmt < 0 || ShrAmt >=
Size)
4787 if (0 == (SMask >> ShrAmt)) {
4789 B.buildConstant(Dst, 0);
4796 UMask |= maskTrailingOnes<uint64_t>(ShrAmt);
4797 UMask &= maskTrailingOnes<uint64_t>(
Size);
4802 const int64_t Pos = ShrAmt;
4807 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4811 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4812 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4813 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4818bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4820 auto &PtrAdd = cast<GPtrAdd>(
MI);
4822 Register Src1Reg = PtrAdd.getBaseReg();
4823 auto *Src1Def = getOpcodeDef<GPtrAdd>(Src1Reg,
MRI);
4827 Register Src2Reg = PtrAdd.getOffsetReg();
4839 const APInt &C1APIntVal = *C1;
4840 const APInt &C2APIntVal = *C2;
4841 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4847 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4848 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4849 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4856 auto *LdStMI = dyn_cast<GLoadStore>(ConvUseMI);
4867 PtrAdd.getMF()->getFunction().getContext());
4868 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4869 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4875 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4887 Register Src1Reg =
MI.getOperand(1).getReg();
4888 if (
RHS->getOpcode() != TargetOpcode::G_ADD)
4900 unsigned PtrAddFlags =
MI.getFlags();
4901 unsigned AddFlags =
RHS->getFlags();
4919 MI.getOperand(1).setReg(NewBase.getReg(0));
4920 MI.getOperand(2).setReg(
RHS->getOperand(2).getReg());
4924 return !reassociationCanBreakAddressingModePattern(
MI);
4934 std::optional<ValueAndVReg> LHSCstOff;
4939 auto *LHSPtrAdd = cast<GPtrAdd>(
LHS);
4944 unsigned PtrAddFlags =
MI.getFlags();
4945 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
4947 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
4949 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
4963 LHSPtrAdd->moveBefore(&
MI);
4966 auto NewCst =
B.buildConstant(
MRI.
getType(RHSReg), LHSCstOff->Value);
4968 MI.getOperand(2).setReg(NewCst.getReg(0));
4972 LHSPtrAdd->getOperand(2).setReg(RHSReg);
4973 LHSPtrAdd->setFlags(Flags);
4976 return !reassociationCanBreakAddressingModePattern(
MI);
4983 auto *LHSPtrAdd = dyn_cast<GPtrAdd>(
LHS);
4987 Register Src2Reg =
MI.getOperand(2).getReg();
4988 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
4989 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5002 unsigned PtrAddFlags =
MI.getFlags();
5003 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5016 auto NewCst =
B.buildConstant(
MRI.
getType(Src2Reg), *C1 + *C2);
5018 MI.getOperand(1).setReg(LHSSrc1);
5019 MI.getOperand(2).setReg(NewCst.getReg(0));
5023 return !reassociationCanBreakAddressingModePattern(
MI);
5028 auto &PtrAdd = cast<GPtrAdd>(
MI);
5080 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5081 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5089 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5090 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5103 unsigned Opc =
MI.getOpcode();
5116 APInt &MatchInfo)
const {
5121 MatchInfo = *MaybeCst;
5129 APInt &MatchInfo)
const {
5135 MatchInfo = *MaybeCst;
5147 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5153 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5154 MI.getOpcode() == TargetOpcode::G_FMAD);
5155 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5172 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5195 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5219 case TargetOpcode::G_ADD:
5220 case TargetOpcode::G_SUB:
5221 case TargetOpcode::G_MUL:
5222 case TargetOpcode::G_AND:
5223 case TargetOpcode::G_OR:
5224 case TargetOpcode::G_XOR:
5232 auto Mask = Cst->Value;
5237 unsigned NarrowWidth = Mask.countr_one();
5243 auto &MF = *
MI.getMF();
5246 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5247 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5261 MI.getOperand(1).setReg(Ext.getReg(0));
5269 unsigned Opc =
MI.getOpcode();
5270 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5277 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5278 : TargetOpcode::G_SADDO;
5280 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5289 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5290 MI.getOpcode() == TargetOpcode::G_SMULO);
5299 B.buildConstant(Dst, 0);
5300 B.buildConstant(Carry, 0);
5309 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5310 MI.getOpcode() == TargetOpcode::G_SADDE ||
5311 MI.getOpcode() == TargetOpcode::G_USUBE ||
5312 MI.getOpcode() == TargetOpcode::G_SSUBE);
5317 switch (
MI.getOpcode()) {
5318 case TargetOpcode::G_UADDE:
5319 NewOpcode = TargetOpcode::G_UADDO;
5321 case TargetOpcode::G_SADDE:
5322 NewOpcode = TargetOpcode::G_SADDO;
5324 case TargetOpcode::G_USUBE:
5325 NewOpcode = TargetOpcode::G_USUBO;
5327 case TargetOpcode::G_SSUBE:
5328 NewOpcode = TargetOpcode::G_SSUBO;
5332 MI.setDesc(
B.getTII().get(NewOpcode));
5333 MI.removeOperand(4);
5341 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5375 B.buildSub(Dst, Zero, ReplaceReg);
5384 unsigned Opcode =
MI.getOpcode();
5385 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5386 auto &UDivorRem = cast<GenericMachineInstr>(
MI);
5387 Register Dst = UDivorRem.getReg(0);
5398 bool UseSRL =
false;
5403 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5405 if (IsSplat && !Factors.
empty()) {
5411 auto *CI = cast<ConstantInt>(
C);
5412 APInt Divisor = CI->getValue();
5421 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5422 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5433 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5434 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5437 Factor = Factors[0];
5445 return MIB.buildMul(Ty, Res, Factor);
5448 unsigned KnownLeadingZeros =
5451 bool UseNPQ =
false;
5453 auto BuildUDIVPattern = [&](
const Constant *
C) {
5454 auto *CI = cast<ConstantInt>(
C);
5455 const APInt &Divisor = CI->getValue();
5457 bool SelNPQ =
false;
5459 unsigned PreShift = 0, PostShift = 0;
5464 if (!Divisor.
isOne()) {
5470 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5472 Magic = std::move(magics.
Magic);
5475 "We shouldn't generate an undefined shift!");
5477 "We shouldn't generate an undefined shift!");
5481 SelNPQ = magics.
IsAdd;
5485 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5486 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5488 MIB.buildConstant(ScalarTy,
5493 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5501 assert(Matched &&
"Expected unary predicate match to succeed");
5503 Register PreShift, PostShift, MagicFactor, NPQFactor;
5504 auto *RHSDef = getOpcodeDef<GBuildVector>(
RHS,
MRI);
5506 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5507 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5508 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5509 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5512 "Non-build_vector operation should have been a scalar");
5513 PreShift = PreShifts[0];
5514 MagicFactor = MagicFactors[0];
5515 PostShift = PostShifts[0];
5519 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5522 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5525 Register NPQ = MIB.buildSub(Ty,
LHS, Q).getReg(0);
5530 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5532 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5534 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5537 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5538 auto One = MIB.buildConstant(Ty, 1);
5539 auto IsOne = MIB.buildICmp(
5542 auto ret = MIB.buildSelect(Ty, IsOne,
LHS, Q);
5544 if (Opcode == TargetOpcode::G_UREM) {
5545 auto Prod = MIB.buildMul(Ty, ret,
RHS);
5546 return MIB.buildSub(Ty,
LHS, Prod);
5552 unsigned Opcode =
MI.getOpcode();
5553 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5558 auto &MF = *
MI.getMF();
5567 if (MF.getFunction().hasMinSize())
5570 if (Opcode == TargetOpcode::G_UDIV &&
5587 {TargetOpcode::G_ICMP,
5591 if (Opcode == TargetOpcode::G_UREM &&
5606 unsigned Opcode =
MI.getOpcode();
5607 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5614 auto &MF = *
MI.getMF();
5623 if (MF.getFunction().hasMinSize())
5627 if (Opcode == TargetOpcode::G_SDIV &&
5641 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5644 if (Opcode == TargetOpcode::G_SREM &&
5659 unsigned Opcode =
MI.getOpcode();
5660 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5661 Opcode == TargetOpcode::G_SREM);
5662 auto &SDivorRem = cast<GenericMachineInstr>(
MI);
5663 Register Dst = SDivorRem.getReg(0);
5673 bool UseSRA =
false;
5679 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5681 if (IsSplat && !ExactFactors.
empty()) {
5683 ExactFactors.
push_back(ExactFactors[0]);
5687 auto *CI = cast<ConstantInt>(
C);
5688 APInt Divisor = CI->getValue();
5698 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5699 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5707 assert(Matched &&
"Expected unary predicate match to succeed");
5711 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5712 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5714 Shift = ExactShifts[0];
5715 Factor = ExactFactors[0];
5723 return MIB.buildMul(Ty, Res, Factor);
5728 auto BuildSDIVPattern = [&](
const Constant *
C) {
5729 auto *CI = cast<ConstantInt>(
C);
5730 const APInt &Divisor = CI->getValue();
5734 int NumeratorFactor = 0;
5745 NumeratorFactor = 1;
5748 NumeratorFactor = -1;
5751 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5752 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5754 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5755 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5763 assert(Matched &&
"Expected unary predicate match to succeed");
5765 Register MagicFactor, Factor, Shift, ShiftMask;
5766 auto *RHSDef = getOpcodeDef<GBuildVector>(
RHS,
MRI);
5768 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5769 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5770 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5771 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5774 "Non-build_vector operation should have been a scalar");
5775 MagicFactor = MagicFactors[0];
5776 Factor = Factors[0];
5778 ShiftMask = ShiftMasks[0];
5782 Q = MIB.buildSMulH(Ty,
LHS, MagicFactor).getReg(0);
5785 Factor = MIB.buildMul(Ty,
LHS, Factor).getReg(0);
5786 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5789 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5792 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5793 auto T = MIB.buildLShr(Ty, Q, SignShift);
5794 T = MIB.buildAnd(Ty,
T, ShiftMask);
5795 auto ret = MIB.buildAdd(Ty, Q,
T);
5797 if (Opcode == TargetOpcode::G_SREM) {
5798 auto Prod = MIB.buildMul(Ty, ret,
RHS);
5799 return MIB.buildSub(Ty,
LHS, Prod);
5805 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5806 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5807 "Expected SDIV or UDIV");
5808 auto &Div = cast<GenericMachineInstr>(
MI);
5810 auto MatchPow2 = [&](
const Constant *
C) {
5811 auto *CI = dyn_cast<ConstantInt>(
C);
5812 return CI && (CI->getValue().isPowerOf2() ||
5813 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5819 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5820 auto &SDiv = cast<GenericMachineInstr>(
MI);
5874 MI.eraseFromParent();
5878 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5879 auto &UDiv = cast<GenericMachineInstr>(
MI);
5888 MI.eraseFromParent();
5892 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5898 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5899 if (
auto *CI = dyn_cast<ConstantInt>(
C))
5900 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5924 MI.eraseFromParent();
5935 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
5937 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
5956 MI.eraseFromParent();
5967 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
5969 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
5988 MI.eraseFromParent();
5999 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6001 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6019 unsigned Opc =
MI.getOpcode();
6020 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6021 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6022 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6034 Opc = TargetOpcode::G_FSUB;
6039 Opc = TargetOpcode::G_FADD;
6045 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6046 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6055 MI.setDesc(
B.getTII().get(
Opc));
6056 MI.getOperand(1).setReg(
X);
6057 MI.getOperand(2).setReg(
Y);
6065 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6068 MatchInfo =
MI.getOperand(2).getReg();
6078 if (LHSCst->Value.isNegZero())
6082 if (LHSCst->Value.isPosZero())
6099 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6107 MRI.use_instr_nodbg_end()) >
6109 MRI.use_instr_nodbg_end());
6113 bool &AllowFusionGlobally,
6115 bool CanReassociate)
const {
6117 auto *MF =
MI.getMF();
6118 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6128 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6131 if (!HasFMAD && !HasFMA)
6139 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6146 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6148 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6156 unsigned PreferredFusedOpcode =
6157 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6171 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6172 {
LHS.MI->getOperand(1).getReg(),
6173 LHS.MI->getOperand(2).getReg(),
RHS.Reg});
6182 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6183 {
RHS.MI->getOperand(1).getReg(),
6184 RHS.MI->getOperand(2).getReg(),
LHS.Reg});
6195 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6197 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6201 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6208 unsigned PreferredFusedOpcode =
6209 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6223 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6228 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6229 {FpExtX.getReg(0), FpExtY.getReg(0),
RHS.Reg});
6238 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6243 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6244 {FpExtX.getReg(0), FpExtY.getReg(0),
LHS.Reg});
6255 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6257 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6267 unsigned PreferredFusedOpcode =
6268 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6281 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
6283 TargetOpcode::G_FMUL) &&
6290 else if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
6292 TargetOpcode::G_FMUL) &&
6301 Register X = FMA->getOperand(1).getReg();
6302 Register Y = FMA->getOperand(2).getReg();
6308 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6309 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6321 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6323 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6330 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6337 unsigned PreferredFusedOpcode =
6338 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6351 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6352 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6354 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6356 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6363 if (
LHS.MI->getOpcode() == PreferredFusedOpcode &&
6367 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6372 LHS.MI->getOperand(1).getReg(),
6373 LHS.MI->getOperand(2).getReg(),
B);
6384 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6387 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6392 X =
B.buildFPExt(DstType,
X).getReg(0);
6393 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6404 if (
RHS.MI->getOpcode() == PreferredFusedOpcode &&
6408 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6413 RHS.MI->getOperand(1).getReg(),
6414 RHS.MI->getOperand(2).getReg(),
B);
6425 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6428 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6433 X =
B.buildFPExt(DstType,
X).getReg(0);
6434 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6448 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6450 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6462 int FirstMulHasFewerUses =
true;
6466 FirstMulHasFewerUses =
false;
6468 unsigned PreferredFusedOpcode =
6469 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6472 if (FirstMulHasFewerUses &&
6477 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6478 {
LHS.MI->getOperand(1).getReg(),
6479 LHS.MI->getOperand(2).getReg(), NegZ});
6488 B.buildFNeg(DstTy,
RHS.MI->getOperand(1).getReg()).
getReg(0);
6489 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6490 {NegY,
RHS.MI->getOperand(2).getReg(),
LHS.Reg});
6501 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6503 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6511 unsigned PreferredFusedOpcode =
6512 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6523 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6524 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6536 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6549 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6551 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6559 unsigned PreferredFusedOpcode =
6560 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6572 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6573 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6574 {FpExtX, FpExtY, NegZ});
6586 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6589 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6590 {NegY, FpExtZ, LHSReg});
6601 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6603 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6607 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6612 unsigned PreferredFusedOpcode =
6613 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6617 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6618 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6619 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6630 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6636 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6646 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6659 unsigned &IdxToPropagate)
const {
6661 switch (
MI.getOpcode()) {
6664 case TargetOpcode::G_FMINNUM:
6665 case TargetOpcode::G_FMAXNUM:
6666 PropagateNaN =
false;
6668 case TargetOpcode::G_FMINIMUM:
6669 case TargetOpcode::G_FMAXIMUM:
6670 PropagateNaN =
true;
6674 auto MatchNaN = [&](
unsigned Idx) {
6679 IdxToPropagate = PropagateNaN ?
Idx : (
Idx == 1 ? 2 : 1);
6683 return MatchNaN(1) || MatchNaN(2);
6687 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6697 Reg == MaybeSameReg;
6732 std::optional<ValueAndVReg> ShiftAmount;
6763 std::optional<ValueAndVReg> ShiftAmt;
6770 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6774unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6776 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6777 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6778 "Expected a NaN behaviour?");
6788 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6789 return TargetOpcode::G_FMAXNUM;
6790 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6791 return TargetOpcode::G_FMAXIMUM;
6792 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6793 return TargetOpcode::G_FMAXNUM;
6794 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6795 return TargetOpcode::G_FMAXIMUM;
6801 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6802 return TargetOpcode::G_FMINNUM;
6803 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6804 return TargetOpcode::G_FMINIMUM;
6805 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6806 return TargetOpcode::G_FMINNUM;
6807 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6809 return TargetOpcode::G_FMINIMUM;
6813CombinerHelper::SelectPatternNaNBehaviour
6815 bool IsOrderedComparison)
const {
6819 if (!LHSSafe && !RHSSafe)
6820 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6821 if (LHSSafe && RHSSafe)
6822 return SelectPatternNaNBehaviour::RETURNS_ANY;
6825 if (IsOrderedComparison)
6826 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6827 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6830 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6831 : SelectPatternNaNBehaviour::RETURNS_NAN;
6853 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6855 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6857 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6860 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6861 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6862 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6863 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6865 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6868 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6873 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
6878 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6880 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6885 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
6893 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6900 Register TrueVal =
MI.getOperand(2).getReg();
6901 Register FalseVal =
MI.getOperand(3).getReg();
6902 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6907 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6920 if (MatchedSub &&
X != OpLHS)
6928 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
6932 B.buildICmp(Pred, Dst,
Y, Zero);
6939static std::optional<unsigned>
6941 std::optional<int64_t> &Result) {
6942 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
6943 Opcode == TargetOpcode::G_ASHR) &&
6944 "Expect G_SHL, G_LSHR or G_ASHR.");
6945 auto SignificantBits = 0;
6947 case TargetOpcode::G_SHL:
6951 case TargetOpcode::G_LSHR:
6955 case TargetOpcode::G_ASHR:
6964 Result = std::nullopt;
6975 Register ShiftVal =
MI.getOperand(1).getReg();
6976 Register ShiftReg =
MI.getOperand(2).getReg();
6978 auto IsShiftTooBig = [&](
const Constant *
C) {
6979 auto *CI = dyn_cast<ConstantInt>(
C);
6983 MatchInfo = std::nullopt;
6987 MI.getOpcode(), MatchInfo);
6988 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
6994 unsigned LHSOpndIdx = 1;
6995 unsigned RHSOpndIdx = 2;
6996 switch (
MI.getOpcode()) {
6997 case TargetOpcode::G_UADDO:
6998 case TargetOpcode::G_SADDO:
6999 case TargetOpcode::G_UMULO:
7000 case TargetOpcode::G_SMULO:
7014 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7019 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7026 std::optional<FPValueAndVReg> ValAndVReg;
7034 unsigned LHSOpndIdx = 1;
7035 unsigned RHSOpndIdx = 2;
7036 switch (
MI.getOpcode()) {
7037 case TargetOpcode::G_UADDO:
7038 case TargetOpcode::G_SADDO:
7039 case TargetOpcode::G_UMULO:
7040 case TargetOpcode::G_SMULO:
7047 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7048 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7049 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7050 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7054bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7057 return isConstantSplatVector(Src, 1, AllowUndefs);
7059 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
7062 return IConstant && IConstant->Value == 1;
7067bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7070 return isConstantSplatVector(Src, 0, AllowUndefs);
7072 if (AllowUndefs && getOpcodeDef<GImplicitDef>(Src,
MRI) !=
nullptr)
7075 return IConstant && IConstant->Value == 0;
7082bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7083 bool AllowUndefs)
const {
7089 for (
unsigned I = 0;
I < NumSources; ++
I) {
7092 if (ImplicitDef && AllowUndefs)
7094 if (ImplicitDef && !AllowUndefs)
7096 std::optional<ValueAndVReg> IConstant =
7098 if (IConstant && IConstant->Value == SplatValue)
7108CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7111 return IConstant->Value;
7115 return std::nullopt;
7118 std::optional<APInt>
Value = std::nullopt;
7119 for (
unsigned I = 0;
I < NumSources; ++
I) {
7120 std::optional<ValueAndVReg> IConstant =
7123 return std::nullopt;
7127 return std::nullopt;
7133bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7143 for (
unsigned I = 0;
I < NumSources; ++
I) {
7144 std::optional<ValueAndVReg> IConstant =
7153bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7171 std::optional<ValueAndVReg> TrueOpt =
7173 std::optional<ValueAndVReg> FalseOpt =
7176 if (!TrueOpt || !FalseOpt)
7179 APInt TrueValue = TrueOpt->Value;
7180 APInt FalseValue = FalseOpt->Value;
7185 B.setInstrAndDebugLoc(*
Select);
7186 B.buildZExtOrTrunc(Dest,
Cond);
7194 B.setInstrAndDebugLoc(*
Select);
7195 B.buildSExtOrTrunc(Dest,
Cond);
7203 B.setInstrAndDebugLoc(*
Select);
7205 B.buildNot(Inner,
Cond);
7206 B.buildZExtOrTrunc(Dest, Inner);
7214 B.setInstrAndDebugLoc(*
Select);
7216 B.buildNot(Inner,
Cond);
7217 B.buildSExtOrTrunc(Dest, Inner);
7223 if (TrueValue - 1 == FalseValue) {
7225 B.setInstrAndDebugLoc(*
Select);
7227 B.buildZExtOrTrunc(Inner,
Cond);
7228 B.buildAdd(Dest, Inner, False);
7234 if (TrueValue + 1 == FalseValue) {
7236 B.setInstrAndDebugLoc(*
Select);
7238 B.buildSExtOrTrunc(Inner,
Cond);
7239 B.buildAdd(Dest, Inner, False);
7247 B.setInstrAndDebugLoc(*
Select);
7249 B.buildZExtOrTrunc(Inner,
Cond);
7252 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7253 B.buildShl(Dest, Inner, ShAmtC, Flags);
7261 B.setInstrAndDebugLoc(*
Select);
7263 B.buildNot(Not,
Cond);
7265 B.buildZExtOrTrunc(Inner, Not);
7268 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7269 B.buildShl(Dest, Inner, ShAmtC, Flags);
7277 B.setInstrAndDebugLoc(*
Select);
7279 B.buildSExtOrTrunc(Inner,
Cond);
7280 B.buildOr(Dest, Inner, False, Flags);
7288 B.setInstrAndDebugLoc(*
Select);
7290 B.buildNot(Not,
Cond);
7292 B.buildSExtOrTrunc(Inner, Not);
7293 B.buildOr(Dest, Inner, True, Flags);
7302bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7319 if (CondTy != TrueTy)
7324 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7326 B.setInstrAndDebugLoc(*
Select);
7328 B.buildZExtOrTrunc(Ext,
Cond);
7329 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7330 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7337 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7339 B.setInstrAndDebugLoc(*
Select);
7341 B.buildZExtOrTrunc(Ext,
Cond);
7342 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7343 B.buildAnd(DstReg, Ext, FreezeTrue);
7349 if (isOneOrOneSplat(False,
true)) {
7351 B.setInstrAndDebugLoc(*
Select);
7354 B.buildNot(Inner,
Cond);
7357 B.buildZExtOrTrunc(Ext, Inner);
7358 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7359 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7365 if (isZeroOrZeroSplat(True,
true)) {
7367 B.setInstrAndDebugLoc(*
Select);
7370 B.buildNot(Inner,
Cond);
7373 B.buildZExtOrTrunc(Ext, Inner);
7374 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7375 B.buildAnd(DstReg, Ext, FreezeFalse);
7406 Register CmpLHS = Cmp->getLHSReg();
7407 Register CmpRHS = Cmp->getRHSReg();
7410 if (True == CmpRHS && False == CmpLHS) {
7418 if (True != CmpLHS || False != CmpRHS)
7458 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7459 Register DestReg =
MI.getOperand(0).getReg();
7472 if (
isLegal({NewOpc, {DestTy}})) {
7474 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7486 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7489 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7499bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7501 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7502 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7506 unsigned Flags = Logic->
getFlags();
7509 GICmp *Cmp1 = getOpcodeDef<GICmp>(LHS,
MRI);
7514 GICmp *Cmp2 = getOpcodeDef<GICmp>(RHS,
MRI);
7525 std::optional<ValueAndVReg> MaybeC1 =
7529 C1 = MaybeC1->Value;
7531 std::optional<ValueAndVReg> MaybeC2 =
7535 C2 = MaybeC2->Value;
7556 std::optional<APInt> Offset1;
7557 std::optional<APInt> Offset2;
7559 if (
GAdd *
Add = getOpcodeDef<GAdd>(R1,
MRI)) {
7560 std::optional<ValueAndVReg> MaybeOffset1 =
7563 R1 =
Add->getLHSReg();
7564 Offset1 = MaybeOffset1->Value;
7568 std::optional<ValueAndVReg> MaybeOffset2 =
7571 R2 =
Add->getLHSReg();
7572 Offset2 = MaybeOffset2->Value;
7591 bool CreateMask =
false;
7604 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7617 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7627 if (CreateMask &&
Offset != 0) {
7628 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7629 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7630 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7631 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7632 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7633 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7634 B.buildZExtOrTrunc(DstReg, ICmp);
7635 }
else if (CreateMask &&
Offset == 0) {
7636 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7637 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7638 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7639 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7640 B.buildZExtOrTrunc(DstReg, ICmp);
7641 }
else if (!CreateMask &&
Offset != 0) {
7642 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7643 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7644 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7645 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7646 B.buildZExtOrTrunc(DstReg, ICmp);
7647 }
else if (!CreateMask &&
Offset == 0) {
7648 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7649 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7650 B.buildZExtOrTrunc(DstReg, ICmp);
7658bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7664 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7667 GFCmp *Cmp1 = getOpcodeDef<GFCmp>(LHS,
MRI);
7672 GFCmp *Cmp2 = getOpcodeDef<GFCmp>(RHS,
MRI);
7682 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7696 if (LHS0 == RHS1 && LHS1 == RHS0) {
7702 if (LHS0 == RHS0 && LHS1 == RHS1) {
7706 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7713 auto False =
B.buildConstant(CmpTy, 0);
7714 B.buildZExtOrTrunc(DestReg, False);
7721 B.buildZExtOrTrunc(DestReg, True);
7723 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7724 B.buildZExtOrTrunc(DestReg, Cmp);
7736 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7739 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7748 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7751 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7766 bool IsSigned =
Add->isSigned();
7775 B.buildUndef(Carry);
7781 if (isConstantOrConstantVectorI(
LHS) && !isConstantOrConstantVectorI(
RHS)) {
7784 B.buildSAddo(Dst, Carry,
RHS,
LHS);
7790 B.buildUAddo(Dst, Carry,
RHS,
LHS);
7795 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(
LHS);
7796 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(
RHS);
7802 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7803 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7805 B.buildConstant(Dst, Result);
7806 B.buildConstant(Carry, Overflow);
7814 B.buildCopy(Dst,
LHS);
7815 B.buildConstant(Carry, 0);
7827 std::optional<APInt> MaybeAddRHS =
7828 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7831 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7832 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7836 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7837 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7843 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7844 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7869 B.buildConstant(Carry, 0);
7877 B.buildConstant(Carry, 1);
7892 B.buildConstant(Carry, 0);
7908 B.buildConstant(Carry, 0);
7916 B.buildConstant(Carry, 1);
7934 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
7940 auto [Dst,
Base] =
MI.getFirst2Regs();
7946 MI.removeFromParent();
7958 std::optional<SrcOp> Res;
7960 while (ExpVal > 0) {
7979 MI.eraseFromParent();
7998 auto Const =
B.buildConstant(DstTy, C1 - C2);
7999 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8021 auto Const =
B.buildConstant(DstTy, C2 - C1);
8022 B.buildSub(Dst, Const,
Add->getLHSReg());
8031 const GSub *Sub1 = cast<GSub>(&
MI);
8044 auto Const =
B.buildConstant(DstTy, C1 + C2);
8054 const GSub *Sub1 = cast<GSub>(&
MI);
8067 auto Const =
B.buildConstant(DstTy, C1 - C2);
8090 auto Const =
B.buildConstant(DstTy, C2 - C1);
8091 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8099 const GUnmerge *Unmerge = cast<GUnmerge>(&
MI);
8129 const GAnyExt *
Any = dyn_cast<GAnyExt>(Source);
8135 if (
const GBuildVector *BV = dyn_cast<GBuildVector>(NextSource)) {
8142 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8146 LLT SmallBvTy = DstTy;
8150 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8155 {TargetOpcode::G_ANYEXT,
8167 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8182 bool Changed =
false;
8183 auto &Shuffle = cast<GShuffleVector>(
MI);
8188 const unsigned NumDstElts = OrigMask.
size();
8189 for (
unsigned i = 0; i != NumDstElts; ++i) {
8190 int Idx = OrigMask[i];
8191 if (
Idx >= (
int)NumSrcElems) {
8202 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8203 std::move(NewMask));
8210 const unsigned MaskSize = Mask.size();
8211 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8216 if (
Idx < (
int)NumElems)
8217 Mask[
I] =
Idx + NumElems;
8219 Mask[
I] =
Idx - NumElems;
8226 auto &Shuffle = cast<GShuffleVector>(
MI);
8229 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8232 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8238 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8244 bool TouchesSrc1 =
false;
8245 bool TouchesSrc2 =
false;
8246 const unsigned NumElems = Mask.size();
8247 for (
unsigned Idx = 0;
Idx < NumElems; ++
Idx) {
8251 if (Mask[
Idx] < (
int)NumSrcElems)
8257 if (TouchesSrc1 == TouchesSrc2)
8260 Register NewSrc1 = Shuffle.getSrc1Reg();
8263 NewSrc1 = Shuffle.getSrc2Reg();
8268 auto Undef =
B.buildUndef(Src1Ty);
8269 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1, Undef, NewMask);
8306 B.buildConstant(Carry, 0);
8331 B.buildConstant(Carry, 0);
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static std::optional< unsigned > getMinUselessShift(KnownBits ValueKB, unsigned Opcode, std::optional< int64_t > &Result)
Return the minimum useless shift amount that results in complete loss of the source value.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
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
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
Interface for Targets to specify which operations they can successfully select and how the others sho...
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
mir Rename Register Operands
This file declares the MachineIRBuilder class.
Register const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
This file describes how to lower LLVM code to machine code.
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
unsigned countl_one() const
Count the number of leading one bits.
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
LLVM_ABI AttributeSet getAttributes(unsigned Index) const
The attributes for the specified index are returned.
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ 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
@ 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
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
static LLVM_ABI bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
void applyPtrAddZero(MachineInstr &MI) const
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
void applyUDivOrURemByConst(MachineInstr &MI) const
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchShuffleToExtract(MachineInstr &MI) const
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchPtrAddZero(MachineInstr &MI) const
}
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
bool matchShiftsTooBig(MachineInstr &MI, std::optional< int64_t > &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
void applyCombineShuffleToBuildVector(MachineInstr &MI) const
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
const DataLayout & getDataLayout() const
bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
void applyUMulHToLShr(MachineInstr &MI) const
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
const TargetLowering & getTargetLowering() const
bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
void applySDivByPow2(MachineInstr &MI) const
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
bool tryEmitMemcpyInline(MachineInstr &MI) const
Emit loads and stores that perform the given memcpy.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
void applyCombineCopy(MachineInstr &MI) const
bool matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
bool matchSextTruncSextLoad(MachineInstr &MI) const
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchCombineCopy(MachineInstr &MI) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchRedundantSExtInReg(MachineInstr &MI) const
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is zero.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
bool tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool isPreLegalize() const
void applyCombineShuffleVector(MachineInstr &MI, const ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is known to be a power of 2.
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVMContext & getContext() const
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
bool matchCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
bool isLegal(const LegalityQuery &Query) const
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
void eraseInst(MachineInstr &MI) const
Erase MI.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
bool matchConstantFPOp(const MachineOperand &MOP, double C) const
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
bool tryCombineShuffleVector(MachineInstr &MI) const
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
void applyFunnelShiftToRotate(MachineInstr &MI) const
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal) const
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applySDivOrSRemByConst(MachineInstr &MI) const
void applyShuffleToExtract(MachineInstr &MI) const
MachineInstr * buildSDivOrSRemUsingMul(MachineInstr &MI) const
Given an G_SDIV MI or G_SREM MI expressing a signed divide by constant, return an expression that imp...
bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
void applyCommuteBinOpOperands(MachineInstr &MI) const
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
void applySextTruncSextLoad(MachineInstr &MI) const
const MachineFunction & getMachineFunction() const
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
LLVM_ABI void finishedChangingAllUsesOfReg()
All instructions reported as changing by changingAllUsesOfReg() have finished being changed.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
virtual void erasingInstr(MachineInstr &MI)=0
An instruction is about to be erased.
LLVM_ABI void changingAllUsesOfReg(const MachineRegisterInfo &MRI, Register Reg)
All the instructions using the given register are being changed.
Simple wrapper observer that takes several observers, and calls each one for each event.
KnownBits getKnownBits(Register R)
unsigned computeNumSignBits(Register R, const APInt &DemandedElts, unsigned Depth=0)
APInt getKnownZeroes(Register R)
Represents a G_IMPLICIT_DEF.
Represents any type of generic load or store.
Register getPointerReg() const
Get the source register of the pointer value.
Represents a logical binary operation.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
bool isAtomic() const
Returns true if the attached MachineMemOperand has the atomic flag set.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
bool isSimple() const
Returns true if the memory operation is neither atomic or volatile.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
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.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
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 ElementCount getElementCount() const
constexpr LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
constexpr unsigned getAddressSpace() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
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.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
bool isLegalOrCustom(const LegalityQuery &Query) const
LegalizeActionStep getAction(const LegalityQuery &Query) const
Determine what action should be taken to legalize the described instruction.
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
LLVM_ABI bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineInstr *A, const MachineInstr *B) const
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.
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.
Helper class to build MachineInstr.
MachineInstrBuilder buildFMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder insertInstr(MachineInstrBuilder MIB)
Insert an existing instruction at the insertion point.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
LLVMContext & getContext() const
MachineInstrBuilder buildAdd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ADD Op0, Op1.
MachineInstrBuilder buildUndef(const DstOp &Res)
Build and insert Res = IMPLICIT_DEF.
MachineInstrBuilder buildNot(const DstOp &Dst, const SrcOp &Src0)
Build and insert a bitwise not, NegOne = G_CONSTANT -1 Res = G_OR Op0, NegOne.
MachineInstrBuilder buildCTTZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTTZ Op0, Src0.
MachineInstrBuilder buildAShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_SELECT Tst, Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildCast(const DstOp &Dst, const SrcOp &Src)
Build and insert an appropriate cast between two registers of equal size.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildTruncSSatU(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_TRUNC_SSAT_U Op.
MachineInstrBuilder buildURem(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_UREM Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildNeg(const DstOp &Dst, const SrcOp &Src0)
Build and insert integer negation Zero = G_CONSTANT 0 Res = G_SUB Zero, Op0.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineInstrBuilder buildFDiv(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FDIV Op0, Op1.
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildPtrAdd(const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_PTR_ADD Op0, Op1.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
MachineInstrBuilder buildExtractVectorElementConstant(const DstOp &Res, const SrcOp &Val, const int Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTruncSSatS(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_TRUNC_SSAT_S Op.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
MachineInstrBuilder buildExtOrTrunc(unsigned ExtOpc, const DstOp &Res, const SrcOp &Op)
Build and insert Res = ExtOpc, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes of...
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
MachineInstrBuilder buildFNeg(const DstOp &Dst, const SrcOp &Src0, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FNEG Op0.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildInstrNoInsert(unsigned Opcode)
Build but don't insert <empty> = Opcode <empty>.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
MachineInstrBuilder buildXor(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_XOR Op0, Op1.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildPtrToInt(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_PTRTOINT instruction.
MachineInstrBuilder buildFCanonicalize(const DstOp &Dst, const SrcOp &Src0, std::optional< unsigned > Flags=std::nullopt)
Build and insert Dst = G_FCANONICALIZE Src0.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
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 & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
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.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
LLVM_ABI bool isDereferenceableInvariantLoad() const
Return true if this load instruction never traps and points to a memory location whose value doesn't ...
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
LLVM_ABI void cloneMemRefs(MachineFunction &MF, const MachineInstr &MI)
Clone another MachineInstr's memory reference descriptor list and replace ours with it.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
mop_range uses()
Returns all operands which may be register uses.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
const RegClassOrRegBank & getRegClassOrRegBank(Register Reg) const
Return the register bank or register class of Reg.
void setRegClassOrRegBank(Register Reg, const RegClassOrRegBank &RCOrRB)
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
LLVM_ABI Register cloneVirtualRegister(Register VReg, StringRef Name="")
Create and return a new virtual register in the function with the same attributes as the given regist...
LLVM_ABI bool constrainRegAttrs(Register Reg, Register ConstrainingReg, unsigned MinNumRegs=0)
Constrain the register class or the register bank of the virtual register Reg (and low-level type) to...
iterator_range< use_iterator > use_operands(Register Reg) const
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
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.
virtual bool isExtendLikelyToBeFolded(MachineInstr &ExtMI, MachineRegisterInfo &MRI) const
Given the generic extension instruction ExtMI, returns true if this extension is a likely candidate f...
virtual bool produceSameValue(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo *MRI=nullptr) const
Return true if two machine instructions would produce identical values.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual bool isTruncateFree(Type *FromTy, Type *ToTy) const
Return true if it's free to truncate a value of type FromTy to type ToTy.
virtual LLVM_READONLY LLT getPreferredShiftAmountTy(LLT ShiftValueTy) const
Return the preferred type to use for a shift opcode, given the shifted amount type is ShiftValueTy.
bool isBeneficialToExpandPowI(int64_t Exponent, bool OptForSize) const
Return true if it is beneficial to expand an @llvm.powi.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual bool isReassocProfitable(SelectionDAG &DAG, SDValue N0, SDValue N1) const
virtual const TargetLowering * getTargetLowering() const
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
LLVM_ABI Value(Type *Ty, unsigned scid)
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
operand_type_match m_Reg()
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(APInt RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
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.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
SpecificConstantMatch m_SpecificICst(APInt RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false > m_GBuildVectorTrunc(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP, true > m_c_GICmp(const Pred &P, const LHS &L, const RHS &R)
G_ICMP matcher that also matches commuted compares.
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
class_match< BinaryOperator > m_BinOp()
Match an arbitrary binary operation and ignore it.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
LLVM_ABI 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.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
LLVM_ABI bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
LLVM_ABI std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
LLVM_ABI std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
LLVM_ABI unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc)
Returns the inverse opcode of MinMaxOpc, which is a generic min/max opcode like G_SMIN.
@ Xor
Bitwise or logical XOR of integers.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
constexpr unsigned BitWidth
LLVM_ABI int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
LLVM_ABI bool isKnownNeverNaN(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if the floating-point scalar value is not a NaN or if the floating-point vector value has...
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
LLVM_ABI bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return true if the given value is known to have exactly one bit set when defined.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
LLVM_ABI std::optional< int64_t > getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static constexpr roundingMode rmNearestTiesToEven
static LLVM_ABI const fltSemantics & IEEEdouble() LLVM_READNONE
This struct is a compact representation of a valid (non-zero power of two) alignment.
Simple struct used to hold a Register value and the instruction which defines it.
SmallVector< InstructionBuildSteps, 2 > InstrsToBuild
Describes instructions to be built during a combine.
bool isNonNegative() const
Returns true if this value is known to be non-negative.
unsigned countMinLeadingOnes() const
Returns the minimum number of leading one bits.
unsigned countMinTrailingZeros() const
Returns the minimum number of trailing zero bits.
bool isUnknown() const
Returns true if we don't know any bits.
unsigned getBitWidth() const
Get the bit width of this value.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
bool isNegative() const
Returns true if this value is known to be negative.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
LegalizeAction Action
The action to take or the final answer.
This class contains a discriminated union of information about pointers in memory operands,...
LLVM_ABI unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
Magic data for optimising signed division by a constant.
unsigned ShiftAmount
shift amount
static LLVM_ABI SignedDivisionByConstantInfo get(const APInt &D)
Calculate the magic numbers required to implement a signed integer division by a constant as a sequen...
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...
unsigned PostShift
post-shift amount