45#define DEBUG_TYPE "gi-combiner"
54 cl::desc(
"Force all indexed operations to be "
55 "legal for the GlobalISel combiner"));
64 TII(
Builder.getMF().getSubtarget().getInstrInfo()),
65 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
66 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
71 return *
Builder.getMF().getSubtarget().getTargetLowering();
85 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
93 LLT Ty = MRI.getType(V);
104 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
105 return ByteWidth -
I - 1;
125static std::optional<bool>
129 unsigned Width = MemOffset2Idx.
size();
132 bool BigEndian =
true, LittleEndian =
true;
133 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
134 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
135 if (MemOffsetAndIdx == MemOffset2Idx.
end())
137 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
138 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
141 if (!BigEndian && !LittleEndian)
145 assert((BigEndian != LittleEndian) &&
146 "Pattern cannot be both big and little endian!");
153 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
181 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
182 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
189 if (
MRI.constrainRegAttrs(ToReg, FromReg))
190 MRI.replaceRegWith(FromReg, ToReg);
192 Builder.buildCopy(FromReg, ToReg);
194 Observer.finishedChangingAllUsesOfReg();
209 unsigned ToOpcode)
const {
224 MRI.setRegBank(Reg, *RegBank);
228 if (
MI.getOpcode() != TargetOpcode::COPY)
238 MI.eraseFromParent();
243 assert(
MI.getOpcode() == TargetOpcode::G_FREEZE &&
"Invalid instruction");
249 if (!
MRI.hasOneNonDBGUse(OrigOp))
270 std::optional<MachineOperand> MaybePoisonOperand;
272 if (!Operand.isReg())
278 if (!MaybePoisonOperand)
279 MaybePoisonOperand = Operand;
288 if (!MaybePoisonOperand) {
293 B.buildCopy(
DstOp, OrigOp);
298 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
299 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
302 {TargetOpcode::G_FREEZE, {MaybePoisonOperandRegTy}}))
310 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
321 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
322 "Invalid instruction");
334 if (!
MRI.hasOneNonDBGUse(Reg))
336 switch (Def->getOpcode()) {
337 case TargetOpcode::G_BUILD_VECTOR:
342 Ops.push_back(BuildVecMO.getReg());
344 case TargetOpcode::G_IMPLICIT_DEF: {
345 LLT OpType =
MRI.getType(Reg);
352 OpType.getScalarType() &&
353 "All undefs should have the same type");
356 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
357 EltIdx != EltEnd; ++EltIdx)
358 Ops.push_back(
Undef->getOperand(0).getReg());
367 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
369 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
384 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
397 MI.eraseFromParent();
406 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
411 LLT InputTy =
MRI.getType(BCSrc);
413 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
418 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
422 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
438 Ops.push_back(BCSrc);
459 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
460 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
461 MI.eraseFromParent();
467 Register SrcVec1 = Shuffle.getSrc1Reg();
468 Register SrcVec2 = Shuffle.getSrc2Reg();
469 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
470 int Width =
MRI.getType(SrcVec1).getNumElements();
472 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
473 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
477 for (
int Val : Shuffle.getMask()) {
480 else if (Val < Width)
481 Extracts.
push_back(Unmerge1.getReg(Val));
483 Extracts.
push_back(Unmerge2.getReg(Val - Width));
485 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
486 if (Extracts.
size() == 1)
487 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
489 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
490 MI.eraseFromParent();
507 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
509 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
513 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
514 if (i + j >= Mask.size())
516 if (Mask[i + j] != -1)
520 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
523 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
524 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
525 if (i + j >= Mask.size())
527 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
544 {TargetOpcode::G_CONCAT_VECTORS,
545 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
556 SrcTy =
MRI.getType(Reg);
558 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
565 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
571 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
574 MI.eraseFromParent();
579 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
580 "Invalid instruction kind");
581 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
583 LLT SrcType =
MRI.getType(Src1);
585 unsigned DstNumElts = DstType.getNumElements();
586 unsigned SrcNumElts = SrcType.getNumElements();
603 if (DstNumElts < 2 * SrcNumElts)
608 if (DstNumElts % SrcNumElts != 0)
614 unsigned NumConcat = DstNumElts / SrcNumElts;
617 for (
unsigned i = 0; i != DstNumElts; ++i) {
624 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
625 (ConcatSrcs[i / SrcNumElts] >= 0 &&
626 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
629 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
636 for (
auto Src : ConcatSrcs) {
640 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
642 Ops.push_back(UndefReg);
655 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
663 MI.eraseFromParent();
672 const LLT TyForCandidate,
673 unsigned OpcodeForCandidate,
678 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
689 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
692 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
693 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
694 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
702 OpcodeForCandidate == TargetOpcode::G_ZEXT)
704 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
705 OpcodeForCandidate == TargetOpcode::G_SEXT)
706 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
715 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
726static void InsertInsnsWithoutSideEffectsBeforeUse(
738 InsertBB = PredBB->
getMBB();
743 if (InsertBB ==
DefMI.getParent()) {
745 Inserter(InsertBB, std::next(InsertPt), UseMO);
764 unsigned CandidateLoadOpc;
766 case TargetOpcode::G_ANYEXT:
767 CandidateLoadOpc = TargetOpcode::G_LOAD;
769 case TargetOpcode::G_SEXT:
770 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
772 case TargetOpcode::G_ZEXT:
773 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
778 return CandidateLoadOpc;
795 LLT LoadValueTy =
MRI.getType(LoadReg);
817 unsigned PreferredOpcode =
819 ? TargetOpcode::G_ANYEXT
821 Preferred = {
LLT(), PreferredOpcode,
nullptr};
822 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
823 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
824 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
825 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
826 const auto &MMO = LoadMI->
getMMO();
834 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
836 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
840 Preferred = ChoosePreferredUse(
MI, Preferred,
841 MRI.getType(
UseMI.getOperand(0).getReg()),
851 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
869 if (PreviouslyEmitted) {
876 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
877 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
879 EmittedInsns[InsertIntoBB] = NewMI;
885 MI.setDesc(
Builder.getTII().get(LoadOpc));
892 for (
auto *UseMO :
Uses) {
898 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
901 const LLT UseDstTy =
MRI.getType(UseDstReg);
902 if (UseDstReg != ChosenDstReg) {
903 if (Preferred.
Ty == UseDstTy) {
940 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
955 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
958 MI.getOperand(0).setReg(ChosenDstReg);
964 assert(
MI.getOpcode() == TargetOpcode::G_AND);
975 if (
MRI.getType(Dst).isVector())
983 APInt MaskVal = MaybeMask->Value;
998 LLT RegTy =
MRI.getType(LoadReg);
1001 unsigned MaskSizeBits = MaskVal.
countr_one();
1004 !
MRI.hasOneNonDBGUse(LoadReg))
1009 if (MaskSizeBits > LoadSizeBits)
1028 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1033 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1037 B.setInstrAndDebugLoc(*LoadMI);
1038 auto &MF =
B.getMF();
1040 auto *NewMMO = MF.getMachineMemOperand(MMO, PtrInfo, MemDesc.
MemoryTy);
1041 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1051 "shouldn't consider debug uses");
1059 if (DefOrUse ==
MBB.end())
1061 return &*DefOrUse == &
DefMI;
1067 "shouldn't consider debug uses");
1070 else if (
DefMI.getParent() !=
UseMI.getParent())
1077 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1081 if (
MRI.getType(SrcReg).isVector())
1086 LoadUser = TruncSrc;
1088 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1093 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1095 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1097 if (LoadSizeBits == SizeInBits)
1104 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1105 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1108 LLT RegTy =
MRI.getType(DstReg);
1121 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1123 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1129 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1132 if (NewSizeBits < 8)
1145 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1150 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1153 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1158 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1159 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1161 unsigned ScalarSizeBits;
1162 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1171 auto &MMO = LoadDef->
getMMO();
1172 Builder.setInstrAndDebugLoc(*LoadDef);
1174 auto PtrInfo = MMO.getPointerInfo();
1175 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1176 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1179 MI.eraseFromParent();
1190 auto *MF =
MI->getMF();
1197 AM.
BaseOffs = CstOff->getSExtValue();
1202 MF->getDataLayout(), AM,
1204 MF->getFunction().getContext()),
1205 MI->getMMO().getAddrSpace());
1210 case TargetOpcode::G_LOAD:
1211 return TargetOpcode::G_INDEXED_LOAD;
1212 case TargetOpcode::G_STORE:
1213 return TargetOpcode::G_INDEXED_STORE;
1214 case TargetOpcode::G_ZEXTLOAD:
1215 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1216 case TargetOpcode::G_SEXTLOAD:
1217 return TargetOpcode::G_INDEXED_SEXTLOAD;
1223bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1233 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1234 OpTys = {PtrTy, Ty, Ty};
1236 OpTys = {Ty, PtrTy};
1238 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1244 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1245 "considered for post-indexing."));
1249 bool &RematOffset)
const {
1262 if (!isIndexedLoadStoreLegal(LdSt))
1273 unsigned NumUsesChecked = 0;
1286 if (StoredValDef == &
Use)
1289 Offset = PtrAdd->getOffsetReg();
1291 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1299 RematOffset =
false;
1303 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1308 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1309 if (&BasePtrUse == PtrDef)
1315 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1317 isIndexedLoadStoreLegal(*BasePtrLdSt))
1323 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1324 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1327 if (BaseUseUse.getParent() != LdSt.
getParent())
1339 Addr = PtrAdd->getReg(0);
1340 Base = PtrAdd->getBaseReg();
1355 MRI.hasOneNonDBGUse(Addr))
1362 if (!isIndexedLoadStoreLegal(LdSt))
1366 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1371 if (
Base == St->getValueReg())
1376 if (St->getValueReg() == Addr)
1381 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1382 if (AddrUse.getParent() != LdSt.
getParent())
1387 bool RealUse =
false;
1388 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1406 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1416 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1423 if (!LoadMI->isSimple())
1435 const unsigned MaxIter = 20;
1438 if (
II->isLoadFoldBarrier())
1440 if (Iter++ == MaxIter)
1456 int Elt = CVal->getZExtValue();
1469 Register VecPtr = LoadMI->getPointerReg();
1470 LLT PtrTy =
MRI.getType(VecPtr);
1478 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1501 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1516 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1518 if (!MatchInfo.
IsPre &&
1519 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1529 unsigned Opcode =
MI.getOpcode();
1530 bool IsStore = Opcode == TargetOpcode::G_STORE;
1536 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1538 *OldCst->getOperand(1).getCImm());
1539 MatchInfo.
Offset = NewCst.getReg(0);
1542 auto MIB =
Builder.buildInstr(NewOpcode);
1544 MIB.addDef(MatchInfo.
Addr);
1545 MIB.addUse(
MI.getOperand(0).getReg());
1547 MIB.addDef(
MI.getOperand(0).getReg());
1548 MIB.addDef(MatchInfo.
Addr);
1551 MIB.addUse(MatchInfo.
Base);
1552 MIB.addUse(MatchInfo.
Offset);
1553 MIB.addImm(MatchInfo.
IsPre);
1554 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1555 MI.eraseFromParent();
1563 unsigned Opcode =
MI.getOpcode();
1564 bool IsDiv, IsSigned;
1569 case TargetOpcode::G_SDIV:
1570 case TargetOpcode::G_UDIV: {
1572 IsSigned = Opcode == TargetOpcode::G_SDIV;
1575 case TargetOpcode::G_SREM:
1576 case TargetOpcode::G_UREM: {
1578 IsSigned = Opcode == TargetOpcode::G_SREM;
1584 unsigned DivOpcode, RemOpcode, DivremOpcode;
1586 DivOpcode = TargetOpcode::G_SDIV;
1587 RemOpcode = TargetOpcode::G_SREM;
1588 DivremOpcode = TargetOpcode::G_SDIVREM;
1590 DivOpcode = TargetOpcode::G_UDIV;
1591 RemOpcode = TargetOpcode::G_UREM;
1592 DivremOpcode = TargetOpcode::G_UDIVREM;
1610 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1611 if (
MI.getParent() ==
UseMI.getParent() &&
1612 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1613 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1626 unsigned Opcode =
MI.getOpcode();
1627 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1630 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1631 DestDivReg =
MI.getOperand(0).getReg();
1635 DestRemReg =
MI.getOperand(0).getReg();
1639 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1646 Builder.setInstrAndDebugLoc(*FirstInst);
1648 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1649 : TargetOpcode::G_UDIVREM,
1650 {DestDivReg, DestRemReg},
1652 MI.eraseFromParent();
1658 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1675 if (BrIt ==
MBB->begin())
1677 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1679 BrCond = &*std::prev(BrIt);
1680 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1686 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1687 MBB->isLayoutSuccessor(BrCondTarget);
1693 Builder.setInstrAndDebugLoc(*BrCond);
1698 auto True =
Builder.buildConstant(
1704 MI.getOperand(0).setMBB(FallthroughBB);
1717 unsigned MaxLen)
const {
1718 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1720 DstAlignCanChange, MemOps);
1725 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1730 DstAlignCanChange, MemOps) ==
1732 assert(
Changed &&
"expected memcpy-family instruction to lower");
1737 unsigned MaxLen)
const {
1749 switch (
MI.getOpcode()) {
1752 case TargetOpcode::G_FNEG: {
1753 Result.changeSign();
1756 case TargetOpcode::G_FABS: {
1760 case TargetOpcode::G_FCEIL:
1763 case TargetOpcode::G_FFLOOR:
1766 case TargetOpcode::G_INTRINSIC_TRUNC:
1769 case TargetOpcode::G_INTRINSIC_ROUND:
1772 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1775 case TargetOpcode::G_FRINT:
1776 case TargetOpcode::G_FNEARBYINT:
1780 case TargetOpcode::G_FPEXT:
1781 case TargetOpcode::G_FPTRUNC: {
1788 case TargetOpcode::G_FSQRT: {
1792 Result =
APFloat(sqrt(Result.convertToDouble()));
1795 case TargetOpcode::G_FLOG2: {
1815 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1816 MI.eraseFromParent();
1827 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1850 Type *AccessTy =
nullptr;
1851 auto &MF = *
MI.getMF();
1852 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1855 MF.getFunction().getContext());
1860 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1865 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1867 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1868 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1869 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1870 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1879 unsigned PtrAddFlags =
MI.getFlags();
1895 MatchInfo.
Flags = Flags;
1901 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1903 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1907 MI.getOperand(1).setReg(MatchInfo.
Base);
1908 MI.getOperand(2).setReg(NewOffset.getReg(0));
1922 unsigned Opcode =
MI.getOpcode();
1923 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1924 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1925 Opcode == TargetOpcode::G_USHLSAT) &&
1926 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1946 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1951 if (Opcode == TargetOpcode::G_USHLSAT &&
1952 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1960 unsigned Opcode =
MI.getOpcode();
1961 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1962 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1963 Opcode == TargetOpcode::G_USHLSAT) &&
1964 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1966 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1967 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1968 auto Imm = MatchInfo.
Imm;
1970 if (
Imm >= ScalarSizeInBits) {
1972 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1973 Builder.buildConstant(
MI.getOperand(0), 0);
1974 MI.eraseFromParent();
1979 Imm = ScalarSizeInBits - 1;
1982 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1985 MI.getOperand(1).setReg(MatchInfo.
Reg);
1986 MI.getOperand(2).setReg(NewImm);
2002 unsigned ShiftOpcode =
MI.getOpcode();
2003 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2004 ShiftOpcode == TargetOpcode::G_ASHR ||
2005 ShiftOpcode == TargetOpcode::G_LSHR ||
2006 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2007 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2008 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2011 Register LogicDest =
MI.getOperand(1).getReg();
2012 if (!
MRI.hasOneNonDBGUse(LogicDest))
2018 unsigned LogicOpcode = LogicMI->
getOpcode();
2019 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2020 LogicOpcode != TargetOpcode::G_XOR)
2024 const Register C1 =
MI.getOperand(2).getReg();
2026 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2029 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2031 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2033 if (
MI->getOpcode() != ShiftOpcode ||
2034 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2043 ShiftVal = MaybeImmVal->Value.getSExtValue();
2057 if (matchFirstShift(LogicMIOp1, C0Val)) {
2059 MatchInfo.
Shift2 = LogicMIOp1;
2060 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2062 MatchInfo.
Shift2 = LogicMIOp2;
2066 MatchInfo.
ValSum = C0Val + C1Val;
2069 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2072 MatchInfo.
Logic = LogicMI;
2078 unsigned Opcode =
MI.getOpcode();
2079 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2080 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2081 Opcode == TargetOpcode::G_SSHLSAT) &&
2082 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2084 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2085 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2091 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2100 Register Shift2Const =
MI.getOperand(2).getReg();
2102 .buildInstr(Opcode, {DestType},
2112 MI.eraseFromParent();
2124 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2128 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2143 LLT InnerShiftTy =
MRI.getType(InnerShift);
2145 if ((N1C + N001C).ult(InnerShiftSize)) {
2151 if ((N001C + OpSizeInBits) == InnerShiftSize)
2153 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2154 MatchInfo.
Mask =
true;
2164 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2171 if (MatchInfo.
Mask ==
true) {
2179 Builder.buildTrunc(Dst, Shift);
2180 MI.eraseFromParent();
2184 unsigned &ShiftVal)
const {
2185 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2191 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2192 return (
static_cast<int32_t
>(ShiftVal) != -1);
2196 unsigned &ShiftVal)
const {
2197 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2199 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2202 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2203 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2224 auto NegCst =
B.buildConstant(Ty, -
Imm);
2226 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2227 MI.getOperand(2).setReg(NegCst.getReg(0));
2229 if (
Imm.isMinSignedValue())
2239 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2253 if (!MaybeShiftAmtVal)
2257 LLT SrcTy =
MRI.getType(ExtSrc);
2267 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2268 MatchData.
Reg = ExtSrc;
2269 MatchData.
Imm = ShiftAmt;
2271 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2272 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2273 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2279 int64_t ShiftAmtVal = MatchData.
Imm;
2281 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2282 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2284 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2285 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2286 MI.eraseFromParent();
2299 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2300 "Expected an unmerge");
2309 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2310 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2312 if (SrcMergeTy != Dst0Ty && !SameSize)
2316 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2317 Operands.push_back(SrcInstr->getSourceReg(Idx));
2323 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2324 "Expected an unmerge");
2326 "Not enough operands to replace all defs");
2327 unsigned NumElems =
MI.getNumOperands() - 1;
2330 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2331 bool CanReuseInputDirectly = DstTy == SrcTy;
2332 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2333 Register DstReg =
MI.getOperand(Idx).getReg();
2338 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2339 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2340 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2341 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2344 if (CanReuseInputDirectly)
2347 Builder.buildCast(DstReg, SrcReg);
2349 MI.eraseFromParent();
2354 unsigned SrcIdx =
MI.getNumOperands() - 1;
2355 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2361 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2364 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2366 Val = Val.
lshr(ShiftAmt);
2374 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2375 "Expected an unmerge");
2377 "Not enough operands to replace all defs");
2378 unsigned NumElems =
MI.getNumOperands() - 1;
2379 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2380 Register DstReg =
MI.getOperand(Idx).getReg();
2381 Builder.buildConstant(DstReg, Csts[Idx]);
2384 MI.eraseFromParent();
2390 unsigned SrcIdx =
MI.getNumOperands() - 1;
2391 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2393 unsigned NumElems =
MI.getNumOperands() - 1;
2394 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2395 Register DstReg =
MI.getOperand(Idx).getReg();
2396 B.buildUndef(DstReg);
2404 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2405 "Expected an unmerge");
2406 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2407 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2410 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2411 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2419 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2420 Register Dst0Reg =
MI.getOperand(0).getReg();
2421 Builder.buildTrunc(Dst0Reg, SrcReg);
2422 MI.eraseFromParent();
2426 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2427 "Expected an unmerge");
2428 Register Dst0Reg =
MI.getOperand(0).getReg();
2429 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2435 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2436 LLT SrcTy =
MRI.getType(SrcReg);
2437 if (SrcTy.isVector())
2447 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2452 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2453 "Expected an unmerge");
2455 Register Dst0Reg =
MI.getOperand(0).getReg();
2460 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2461 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2464 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2467 "ZExt src doesn't fit in destination");
2472 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2474 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2477 MI.eraseFromParent();
2481 unsigned TargetShiftSize,
2482 unsigned &ShiftVal)
const {
2483 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2484 MI.getOpcode() == TargetOpcode::G_LSHR ||
2485 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2487 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2492 unsigned Size = Ty.getSizeInBits();
2493 if (
Size <= TargetShiftSize)
2501 ShiftVal = MaybeImmVal->Value.getSExtValue();
2502 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2509 LLT Ty =
MRI.getType(SrcReg);
2510 unsigned Size = Ty.getSizeInBits();
2511 unsigned HalfSize =
Size / 2;
2512 assert(ShiftVal >= HalfSize);
2516 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2517 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2519 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2520 Register Narrowed = Unmerge.getReg(1);
2527 if (NarrowShiftAmt != 0) {
2528 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2529 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2532 auto Zero =
Builder.buildConstant(HalfTy, 0);
2533 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2534 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2535 Register Narrowed = Unmerge.getReg(0);
2540 if (NarrowShiftAmt != 0) {
2541 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2542 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2545 auto Zero =
Builder.buildConstant(HalfTy, 0);
2546 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2548 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2550 HalfTy, Unmerge.getReg(1),
2551 Builder.buildConstant(HalfTy, HalfSize - 1));
2553 if (ShiftVal == HalfSize) {
2556 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2557 }
else if (ShiftVal ==
Size - 1) {
2565 HalfTy, Unmerge.getReg(1),
2566 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2574 MI.eraseFromParent();
2590 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2592 Builder.buildZExtOrTrunc(DstReg, Reg);
2593 MI.eraseFromParent();
2598 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2603 SrcReg = OriginalSrcReg;
2604 LLT DstTy =
MRI.getType(DstReg);
2612 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2615 LLT DstTy =
MRI.getType(DstReg);
2620 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2621 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2631 if (ShiftSize > 32 && TruncSize < 32)
2644 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2645 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2649 if (!
MRI.hasOneNonDBGUse(SrcReg))
2652 LLT SrcTy =
MRI.getType(SrcReg);
2653 LLT DstTy =
MRI.getType(DstReg);
2662 case TargetOpcode::G_SHL: {
2671 case TargetOpcode::G_LSHR:
2672 case TargetOpcode::G_ASHR: {
2678 for (
auto &
User :
MRI.use_instructions(DstReg))
2679 if (
User.getOpcode() == TargetOpcode::G_STORE)
2683 if (NewShiftTy == SrcTy)
2697 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2700 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2705 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2707 LLT NewShiftTy = MatchInfo.second;
2710 LLT DstTy =
MRI.getType(Dst);
2714 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2717 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2718 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2719 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2723 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2726 if (NewShiftTy == DstTy)
2729 Builder.buildTrunc(Dst, NewShift);
2736 return !MO.isReg() ||
2737 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2742 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2744 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2748 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2749 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2755 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2756 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2757 "Expected an insert/extract element op");
2758 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2763 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2771 unsigned &OpIdx)
const {
2776 OpIdx = Cst->isZero() ? 3 : 2;
2821 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2848 return MO.isReg() && MO.getReg().isPhysical();
2858 return I1->isIdenticalTo(*I2);
2866 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2873 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2883 std::optional<FPValueAndVReg> MaybeCst;
2887 return MaybeCst->Value.isExactlyValue(
C);
2891 unsigned OpIdx)
const {
2892 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2894 Register Replacement =
MI.getOperand(OpIdx).getReg();
2897 MI.eraseFromParent();
2902 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2906 MI.eraseFromParent();
2910 unsigned ConstIdx)
const {
2911 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2912 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2924 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2925 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2926 "This is not a funnel shift operation");
2928 Register ConstReg =
MI.getOperand(3).getReg();
2929 LLT ConstTy =
MRI.getType(ConstReg);
2930 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2933 assert((VRegAndVal) &&
"Value is not a constant");
2936 APInt NewConst = VRegAndVal->Value.
urem(
2941 MI.getOpcode(), {MI.getOperand(0)},
2942 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2944 MI.eraseFromParent();
2948 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2962 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2964 MI.eraseFromParent();
2969 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2971 MI.eraseFromParent();
2975 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2977 MI.eraseFromParent();
2982 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2984 MI.eraseFromParent();
2988 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2990 MI.eraseFromParent();
2995 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
2998 LLT DstTy =
MRI.getType(DstReg);
3007 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3008 TargetOpcode::G_INSERT_VECTOR_ELT)
3014 MatchInfo.
resize(NumElts);
3018 if (IntImm >= NumElts || IntImm < 0)
3020 if (!MatchInfo[IntImm])
3021 MatchInfo[IntImm] = TmpReg;
3025 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3027 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3036 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3043 auto GetUndef = [&]() {
3046 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3054 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3055 MI.eraseFromParent();
3068 unsigned InnerOpc = InnerDef->
getOpcode();
3069 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3093 if (!TryMatch(InnerLHS, InnerRHS) &&
3094 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3098 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3099 : TargetOpcode::G_ADD;
3102 MatchInfo = [=](MachineIRBuilder &
Builder) {
3103 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3104 auto NewNot =
Builder.buildNot(Ty, NewInner);
3105 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3117 unsigned RootOpc =
MI.getOpcode();
3119 LLT Ty =
MRI.getType(Dst);
3124 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3125 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3136 unsigned LogicOpcode =
MI.getOpcode();
3137 assert(LogicOpcode == TargetOpcode::G_AND ||
3138 LogicOpcode == TargetOpcode::G_OR ||
3139 LogicOpcode == TargetOpcode::G_XOR);
3146 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3152 if (!LeftHandInst || !RightHandInst)
3154 unsigned HandOpcode = LeftHandInst->
getOpcode();
3155 if (HandOpcode != RightHandInst->
getOpcode())
3169 if (!XTy.
isValid() || XTy != YTy)
3174 switch (HandOpcode) {
3177 case TargetOpcode::G_ANYEXT:
3178 case TargetOpcode::G_SEXT:
3179 case TargetOpcode::G_ZEXT: {
3183 case TargetOpcode::G_TRUNC: {
3188 LLT DstTy =
MRI.getType(Dst);
3197 case TargetOpcode::G_AND:
3198 case TargetOpcode::G_ASHR:
3199 case TargetOpcode::G_LSHR:
3200 case TargetOpcode::G_SHL: {
3205 ExtraHandOpSrcReg = ZOp.
getReg();
3216 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3227 if (ExtraHandOpSrcReg.
isValid())
3239 "Expected at least one instr to build?");
3241 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3242 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3244 for (
auto &OperandFn : InstrToBuild.OperandFns)
3247 MI.eraseFromParent();
3251 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3252 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3253 int64_t ShlCst, AshrCst;
3259 if (ShlCst != AshrCst)
3262 {TargetOpcode::G_SEXT_INREG,
3265 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3267 MatchInfo = std::make_tuple(Src, ShlCst);
3272 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3273 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3276 std::tie(Src, ShiftAmt) = MatchInfo;
3277 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3278 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3279 MI.eraseFromParent();
3286 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3289 LLT Ty =
MRI.getType(Dst);
3301 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3304 auto Zero =
B.buildConstant(Ty, 0);
3327 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3351 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3358 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3375 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3393 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3400 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3411 unsigned ExtBits =
MI.getOperand(2).getImm();
3412 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3413 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3417 int64_t Cst,
bool IsVector,
bool IsFP) {
3419 return (ScalarSizeBits == 1 && Cst == -1) ||
3441 unsigned BuildUseCount = BV.getNumSources();
3442 if (BuildUseCount % 2 != 0)
3445 unsigned NumUnmerge = BuildUseCount / 2;
3451 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3454 UnmergeSrc = Unmerge->getSourceReg();
3456 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3457 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3464 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3469 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3470 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3473 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3476 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3481 if (Unmerge->getNumDefs() != NumUnmerge)
3485 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3488 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3499 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3500 B.setInstrAndDebugLoc(
MI);
3502 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3503 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3505 MI.eraseFromParent();
3527 unsigned NumOperands =
BuildMI->getNumSources();
3537 for (
I = 0;
I < NumOperands; ++
I) {
3549 UnmergeMI != UnmergeSrcMI)
3560 for (;
I < NumOperands; ++
I) {
3567 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3574 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3575 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3583 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3586 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3598 LLT DstTy =
MRI.getType(DstReg);
3599 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3604 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3609 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3613 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3616 Builder.buildTrunc(DstReg, MidReg);
3617 MI.eraseFromParent();
3622 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3623 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3624 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3632 if (!
MRI.hasOneNonDBGUse(XorSrc))
3642 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3644 if (!
MRI.hasOneNonDBGUse(Reg))
3649 switch (Def->getOpcode()) {
3654 case TargetOpcode::G_ICMP:
3660 case TargetOpcode::G_FCMP:
3666 case TargetOpcode::G_AND:
3667 case TargetOpcode::G_OR:
3673 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3674 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3682 if (Ty.isVector()) {
3686 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), SplatCst,
true, IsFP))
3700 for (
Register Reg : RegsToNegate) {
3705 switch (Def->getOpcode()) {
3708 case TargetOpcode::G_ICMP:
3709 case TargetOpcode::G_FCMP: {
3716 case TargetOpcode::G_AND:
3717 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3719 case TargetOpcode::G_OR:
3720 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3727 MI.eraseFromParent();
3731 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3733 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3737 Register SharedReg =
MI.getOperand(2).getReg();
3751 if (!
MRI.hasOneNonDBGUse(AndReg))
3758 return Y == SharedReg;
3762 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3765 std::tie(
X,
Y) = MatchInfo;
3768 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3769 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3770 MI.getOperand(2).setReg(
Y);
3776 Register DstReg = PtrAdd.getReg(0);
3777 LLT Ty =
MRI.getType(DstReg);
3780 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3783 if (Ty.isPointer()) {
3785 return ConstVal && *ConstVal == 0;
3788 assert(Ty.isVector() &&
"Expecting a vector type");
3799 Register Pow2Src1 =
MI.getOperand(2).getReg();
3800 LLT Ty =
MRI.getType(DstReg);
3803 auto NegOne =
Builder.buildConstant(Ty, -1);
3804 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3806 MI.eraseFromParent();
3810 unsigned &SelectOpNo)
const {
3822 !
MRI.hasOneNonDBGUse(LHS)) {
3823 OtherOperandReg = LHS;
3827 !
MRI.hasOneNonDBGUse(RHS))
3845 unsigned BinOpcode =
MI.getOpcode();
3850 bool CanFoldNonConst =
3851 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3856 if (CanFoldNonConst)
3881 LLT Ty =
MRI.getType(Dst);
3882 unsigned BinOpcode =
MI.getOpcode();
3889 if (SelectOperand == 1) {
3893 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3895 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3897 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3899 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3902 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3903 MI.eraseFromParent();
3906std::optional<SmallVector<Register, 8>>
3907CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3908 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3937 const unsigned MaxIter =
3939 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3948 return std::nullopt;
3964 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3965 return std::nullopt;
3977static std::optional<std::pair<GZExtLoad *, int64_t>>
3981 "Expected Reg to only have one non-debug use?");
3990 if (Shift % MemSizeInBits != 0)
3991 return std::nullopt;
3996 return std::nullopt;
3998 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
3999 return std::nullopt;
4001 return std::make_pair(
Load, Shift / MemSizeInBits);
4004std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4005CombinerHelper::findLoadOffsetsForLoadOrCombine(
4008 const unsigned MemSizeInBits)
const {
4011 SmallSetVector<const MachineInstr *, 8> Loads;
4017 GZExtLoad *LowestIdxLoad =
nullptr;
4020 SmallSet<int64_t, 8> SeenIdx;
4024 MachineBasicBlock *
MBB =
nullptr;
4025 const MachineMemOperand *MMO =
nullptr;
4028 GZExtLoad *EarliestLoad =
nullptr;
4031 GZExtLoad *LatestLoad =
nullptr;
4040 for (
auto Reg : RegsToVisit) {
4045 return std::nullopt;
4048 std::tie(
Load, DstPos) = *LoadAndPos;
4052 MachineBasicBlock *LoadMBB =
Load->getParent();
4056 return std::nullopt;
4059 auto &LoadMMO =
Load->getMMO();
4063 return std::nullopt;
4070 LoadPtr =
Load->getOperand(1).getReg();
4075 if (!SeenIdx.
insert(Idx).second)
4076 return std::nullopt;
4083 if (BasePtr != LoadPtr)
4084 return std::nullopt;
4086 if (Idx < LowestIdx) {
4088 LowestIdxLoad =
Load;
4095 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4096 return std::nullopt;
4105 EarliestLoad =
Load;
4113 "Expected to find a load for each register?");
4114 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4115 LatestLoad &&
"Expected at least two loads?");
4124 const unsigned MaxIter = 20;
4130 if (
MI.isLoadFoldBarrier())
4131 return std::nullopt;
4132 if (Iter++ == MaxIter)
4133 return std::nullopt;
4136 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4142 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4155 LLT Ty =
MRI.getType(Dst);
4161 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4162 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4166 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4173 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4174 if (NarrowMemSizeInBits % 8 != 0)
4187 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4188 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4191 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4198 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4201 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4213 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4214 const unsigned ZeroByteOffset =
4218 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4219 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4220 ZeroOffsetIdx->second != LowestIdx)
4230 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4244 MIB.setInstrAndDebugLoc(*LatestLoad);
4245 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4246 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4248 MIB.buildBSwap(Dst, LoadDst);
4260 if (
MRI.getType(DstReg).isVector())
4264 if (!
MRI.hasOneNonDBGUse(DstReg))
4266 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4268 case TargetOpcode::G_ANYEXT:
4270 case TargetOpcode::G_ZEXT:
4271 case TargetOpcode::G_SEXT:
4278 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4285 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4287 switch (
DefMI->getOpcode()) {
4288 case TargetOpcode::G_LOAD:
4289 case TargetOpcode::G_TRUNC:
4290 case TargetOpcode::G_SEXT:
4291 case TargetOpcode::G_ZEXT:
4292 case TargetOpcode::G_ANYEXT:
4293 case TargetOpcode::G_CONSTANT:
4297 if (InSrcs.
size() > 2)
4311 LLT ExtTy =
MRI.getType(DstReg);
4318 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4319 auto SrcReg =
PHI.getIncomingValue(
I);
4323 if (!SrcMIs.
insert(SrcMI))
4329 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4330 InsertPt =
MBB->getFirstNonPHI();
4335 OldToNewSrcMap[SrcMI] = NewExt;
4340 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4341 NewPhi.addDef(DstReg);
4344 NewPhi.addMBB(MO.getMBB());
4347 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4348 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4356 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4360 LLT SrcTy =
MRI.getType(SrcVec);
4361 if (SrcTy.isScalableVector())
4365 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4368 unsigned VecIdx = Cst->Value.getZExtValue();
4380 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4381 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4385 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4397 LLT ScalarTy =
MRI.getType(Reg);
4399 LLT DstTy =
MRI.getType(DstReg);
4401 if (ScalarTy != DstTy) {
4403 Builder.buildTrunc(DstReg, Reg);
4404 MI.eraseFromParent();
4412 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4413 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4431 LLT DstTy =
MRI.getType(DstReg);
4436 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4441 unsigned Idx = Cst->getZExtValue();
4444 ExtractedElts.
set(Idx);
4445 SrcDstPairs.emplace_back(
4446 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4449 return ExtractedElts.
all();
4454 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4455 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4456 for (
auto &Pair : SrcDstPairs) {
4457 auto *ExtMI = Pair.second;
4459 ExtMI->eraseFromParent();
4461 MI.eraseFromParent();
4468 MI.eraseFromParent();
4478 bool AllowScalarConstants,
4480 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4483 LLT Ty =
MRI.getType(Dst);
4484 unsigned BitWidth = Ty.getScalarSizeInBits();
4486 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4487 unsigned FshOpc = 0;
4498 int64_t CstShlAmt = 0, CstLShrAmt;
4501 CstShlAmt + CstLShrAmt ==
BitWidth) {
4502 FshOpc = TargetOpcode::G_FSHR;
4508 FshOpc = TargetOpcode::G_FSHL;
4513 FshOpc = TargetOpcode::G_FSHR;
4518 LLT AmtTy =
MRI.getType(Amt);
4520 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4524 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4531 unsigned Opc =
MI.getOpcode();
4532 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4537 unsigned RotateOpc =
4538 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4543 unsigned Opc =
MI.getOpcode();
4544 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4545 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4547 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4548 : TargetOpcode::G_ROTR));
4549 MI.removeOperand(2);
4555 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4556 MI.getOpcode() == TargetOpcode::G_ROTR);
4558 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4560 bool OutOfRange =
false;
4561 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4563 OutOfRange |= CI->getValue().uge(Bitsize);
4570 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4571 MI.getOpcode() == TargetOpcode::G_ROTR);
4573 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4575 LLT AmtTy =
MRI.getType(Amt);
4576 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4577 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4579 MI.getOperand(2).setReg(Amt);
4584 int64_t &MatchInfo)
const {
4585 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4596 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4597 if (KnownRHS.isUnknown())
4600 std::optional<bool> KnownVal;
4601 if (KnownRHS.isZero()) {
4611 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4621 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4630 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4646 LLT DstTy =
MRI.getType(Dst);
4654 auto KnownLHS =
VT->getKnownBits(LHS);
4655 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4658 LLT LHSTy =
MRI.getType(LHS);
4661 unsigned Op = TargetOpcode::COPY;
4662 if (DstSize != LHSSize)
4663 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4674 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4678 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4684 int64_t AndMaskBits;
4692 if (AndMaskBits & OrMaskBits)
4698 if (
MI.getOperand(1).getReg() == AndMaskReg)
4699 MI.getOperand(2).setReg(AndMaskReg);
4700 MI.getOperand(1).setReg(Src);
4710 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4713 LLT Ty =
MRI.getType(Src);
4715 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4717 int64_t Width =
MI.getOperand(2).getImm();
4725 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4729 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4730 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4731 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4741 LLT Ty =
MRI.getType(Dst);
4745 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4748 int64_t AndImm, LSBImm;
4750 const unsigned Size = Ty.getScalarSizeInBits();
4758 uint64_t MaybeMask =
static_cast<uint64_t
>(AndImm);
4763 if (MaybeMask & (MaybeMask + 1))
4767 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4775 if (
static_cast<uint64_t
>(LSBImm) + Width >
Size)
4779 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4780 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4781 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4789 const unsigned Opcode =
MI.getOpcode();
4790 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4792 const Register Dst =
MI.getOperand(0).getReg();
4794 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4795 ? TargetOpcode::G_SBFX
4796 : TargetOpcode::G_UBFX;
4799 LLT Ty =
MRI.getType(Dst);
4801 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4807 const unsigned Size = Ty.getScalarSizeInBits();
4817 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4821 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4825 const int64_t Pos = ShrAmt - ShlAmt;
4826 const int64_t Width =
Size - ShrAmt;
4829 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4830 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4831 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4839 const unsigned Opcode =
MI.getOpcode();
4840 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4842 const Register Dst =
MI.getOperand(0).getReg();
4843 LLT Ty =
MRI.getType(Dst);
4845 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4858 const unsigned Size = Ty.getScalarSizeInBits();
4859 if (ShrAmt < 0 || ShrAmt >=
Size)
4863 if (0 == (SMask >> ShrAmt)) {
4865 B.buildConstant(Dst, 0);
4878 const int64_t Pos = ShrAmt;
4883 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4887 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4888 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4889 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4894bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4898 Register Src1Reg = PtrAdd.getBaseReg();
4903 Register Src2Reg = PtrAdd.getOffsetReg();
4905 if (
MRI.hasOneNonDBGUse(Src1Reg))
4915 const APInt &C1APIntVal = *C1;
4916 const APInt &C2APIntVal = *C2;
4917 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4919 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4922 MachineInstr *ConvUseMI = &
UseMI;
4923 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4924 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4925 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4927 if (!
MRI.hasOneNonDBGUse(DefReg))
4929 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4938 TargetLoweringBase::AddrMode AM;
4941 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4943 PtrAdd.getMF()->getFunction().getContext());
4944 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4945 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4951 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4963 Register Src1Reg =
MI.getOperand(1).getReg();
4964 if (RHS->getOpcode() != TargetOpcode::G_ADD)
4976 unsigned PtrAddFlags =
MI.getFlags();
4977 unsigned AddFlags = RHS->getFlags();
4990 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
4993 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
4995 MI.getOperand(1).setReg(NewBase.getReg(0));
4996 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5000 return !reassociationCanBreakAddressingModePattern(
MI);
5010 std::optional<ValueAndVReg> LHSCstOff;
5020 unsigned PtrAddFlags =
MI.getFlags();
5021 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5023 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5025 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5039 LHSPtrAdd->moveBefore(&
MI);
5042 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5044 MI.getOperand(2).setReg(NewCst.getReg(0));
5047 Observer.changingInstr(*LHSPtrAdd);
5048 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5049 LHSPtrAdd->setFlags(Flags);
5052 return !reassociationCanBreakAddressingModePattern(
MI);
5063 Register Src2Reg =
MI.getOperand(2).getReg();
5064 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5065 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5078 unsigned PtrAddFlags =
MI.getFlags();
5079 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5092 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5094 MI.getOperand(1).setReg(LHSSrc1);
5095 MI.getOperand(2).setReg(NewCst.getReg(0));
5099 return !reassociationCanBreakAddressingModePattern(
MI);
5139 LLT OpRHSTy =
MRI.getType(OpRHS);
5156 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5157 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5165 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5166 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5179 unsigned Opc =
MI.getOpcode();
5192 APInt &MatchInfo)
const {
5193 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5197 MatchInfo = *MaybeCst;
5208 MI.getOperand(1).getReg(),
MRI);
5213 if (Csts.size() == 1)
5214 B.buildConstant(Dst, Csts[0]);
5216 B.buildBuildVectorConstant(Dst, Csts);
5222 APInt &MatchInfo)
const {
5228 MatchInfo = *MaybeCst;
5240 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5246 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5247 MI.getOpcode() == TargetOpcode::G_FMAD);
5248 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5265 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5288 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5292 LLT WideTy =
MRI.getType(Dst);
5296 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5312 case TargetOpcode::G_ADD:
5313 case TargetOpcode::G_SUB:
5314 case TargetOpcode::G_MUL:
5315 case TargetOpcode::G_AND:
5316 case TargetOpcode::G_OR:
5317 case TargetOpcode::G_XOR:
5325 auto Mask = Cst->Value;
5330 unsigned NarrowWidth = Mask.countr_one();
5336 auto &MF = *
MI.getMF();
5339 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5340 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5348 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5349 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5351 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5352 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5354 MI.getOperand(1).setReg(Ext.getReg(0));
5362 unsigned Opc =
MI.getOpcode();
5363 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5370 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5371 : TargetOpcode::G_SADDO;
5372 MI.setDesc(
Builder.getTII().get(NewOpc));
5373 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5382 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5383 MI.getOpcode() == TargetOpcode::G_SMULO);
5392 B.buildConstant(Dst, 0);
5393 B.buildConstant(Carry, 0);
5402 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5403 MI.getOpcode() == TargetOpcode::G_SADDE ||
5404 MI.getOpcode() == TargetOpcode::G_USUBE ||
5405 MI.getOpcode() == TargetOpcode::G_SSUBE);
5410 switch (
MI.getOpcode()) {
5411 case TargetOpcode::G_UADDE:
5412 NewOpcode = TargetOpcode::G_UADDO;
5414 case TargetOpcode::G_SADDE:
5415 NewOpcode = TargetOpcode::G_SADDO;
5417 case TargetOpcode::G_USUBE:
5418 NewOpcode = TargetOpcode::G_USUBO;
5420 case TargetOpcode::G_SSUBE:
5421 NewOpcode = TargetOpcode::G_SSUBO;
5425 MI.setDesc(
B.getTII().get(NewOpcode));
5426 MI.removeOperand(4);
5434 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5467 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5468 B.buildSub(Dst, Zero, ReplaceReg);
5477 unsigned Opcode =
MI.getOpcode();
5478 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5480 Register Dst = UDivorRem.getReg(0);
5481 Register LHS = UDivorRem.getReg(1);
5482 Register RHS = UDivorRem.getReg(2);
5483 LLT Ty =
MRI.getType(Dst);
5491 bool UseSRL =
false;
5496 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5498 if (IsSplat && !Factors.
empty()) {
5505 APInt Divisor = CI->getValue();
5514 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5515 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5525 if (Ty.isVector()) {
5526 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5527 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5530 Factor = Factors[0];
5538 return MIB.buildMul(Ty, Res, Factor);
5541 unsigned KnownLeadingZeros =
5542 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5544 bool UseNPQ =
false;
5546 auto BuildUDIVPattern = [&](
const Constant *
C) {
5548 const APInt &Divisor = CI->getValue();
5550 bool SelNPQ =
false;
5552 unsigned PreShift = 0, PostShift = 0;
5557 if (!Divisor.
isOne()) {
5563 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5565 Magic = std::move(magics.
Magic);
5568 "We shouldn't generate an undefined shift!");
5570 "We shouldn't generate an undefined shift!");
5574 SelNPQ = magics.
IsAdd;
5578 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5579 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5581 MIB.buildConstant(ScalarTy,
5586 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5594 assert(Matched &&
"Expected unary predicate match to succeed");
5596 Register PreShift, PostShift, MagicFactor, NPQFactor;
5599 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5600 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5601 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5602 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5605 "Non-build_vector operation should have been a scalar");
5606 PreShift = PreShifts[0];
5607 MagicFactor = MagicFactors[0];
5608 PostShift = PostShifts[0];
5612 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5615 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5618 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5623 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5625 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5627 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5630 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5631 auto One = MIB.buildConstant(Ty, 1);
5632 auto IsOne = MIB.buildICmp(
5636 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5638 if (Opcode == TargetOpcode::G_UREM) {
5639 auto Prod = MIB.buildMul(Ty, ret, RHS);
5640 return MIB.buildSub(Ty, LHS, Prod);
5646 unsigned Opcode =
MI.getOpcode();
5647 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5650 LLT DstTy =
MRI.getType(Dst);
5652 auto &MF = *
MI.getMF();
5662 if (MF.getFunction().hasMinSize())
5665 if (Opcode == TargetOpcode::G_UDIV &&
5668 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5683 {TargetOpcode::G_ICMP,
5687 if (Opcode == TargetOpcode::G_UREM &&
5693 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5702 unsigned Opcode =
MI.getOpcode();
5703 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5706 LLT DstTy =
MRI.getType(Dst);
5710 auto &MF = *
MI.getMF();
5720 if (MF.getFunction().hasMinSize())
5724 if (Opcode == TargetOpcode::G_SDIV &&
5727 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5739 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5742 if (Opcode == TargetOpcode::G_SREM &&
5748 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5757 unsigned Opcode =
MI.getOpcode();
5758 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5759 Opcode == TargetOpcode::G_SREM);
5761 Register Dst = SDivorRem.getReg(0);
5762 Register LHS = SDivorRem.getReg(1);
5763 Register RHS = SDivorRem.getReg(2);
5764 LLT Ty =
MRI.getType(Dst);
5771 bool UseSRA =
false;
5777 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5779 if (IsSplat && !ExactFactors.
empty()) {
5781 ExactFactors.
push_back(ExactFactors[0]);
5786 APInt Divisor = CI->getValue();
5796 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5797 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5805 assert(Matched &&
"Expected unary predicate match to succeed");
5808 if (Ty.isVector()) {
5809 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5810 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5812 Shift = ExactShifts[0];
5813 Factor = ExactFactors[0];
5821 return MIB.buildMul(Ty, Res, Factor);
5826 auto BuildSDIVPattern = [&](
const Constant *
C) {
5828 const APInt &Divisor = CI->getValue();
5832 int NumeratorFactor = 0;
5843 NumeratorFactor = 1;
5846 NumeratorFactor = -1;
5849 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5850 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5852 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5853 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5861 assert(Matched &&
"Expected unary predicate match to succeed");
5863 Register MagicFactor, Factor, Shift, ShiftMask;
5866 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5867 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5868 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5869 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5872 "Non-build_vector operation should have been a scalar");
5873 MagicFactor = MagicFactors[0];
5874 Factor = Factors[0];
5876 ShiftMask = ShiftMasks[0];
5880 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5883 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5884 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5887 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5890 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5891 auto T = MIB.buildLShr(Ty, Q, SignShift);
5892 T = MIB.buildAnd(Ty,
T, ShiftMask);
5893 auto ret = MIB.buildAdd(Ty, Q,
T);
5895 if (Opcode == TargetOpcode::G_SREM) {
5896 auto Prod = MIB.buildMul(Ty, ret, RHS);
5897 return MIB.buildSub(Ty, LHS, Prod);
5903 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5904 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5905 "Expected SDIV or UDIV");
5908 auto MatchPow2 = [&](
const Constant *
C) {
5910 return CI && (CI->getValue().isPowerOf2() ||
5911 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5917 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5922 LLT Ty =
MRI.getType(Dst);
5942 unsigned BitWidth = Ty.getScalarSizeInBits();
5943 auto Zero =
Builder.buildConstant(Ty, 0);
5946 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5947 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5949 auto Sign =
Builder.buildAShr(
5953 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5959 auto One =
Builder.buildConstant(Ty, 1);
5960 auto MinusOne =
Builder.buildConstant(Ty, -1);
5964 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5965 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5969 auto Neg =
Builder.buildNeg(Ty, AShr);
5971 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5972 MI.eraseFromParent();
5976 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5981 LLT Ty =
MRI.getType(Dst);
5984 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5985 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
5986 MI.eraseFromParent();
5990 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
5995 LLT Ty =
MRI.getType(Dst);
6014 unsigned BitWidth = Ty.getScalarSizeInBits();
6015 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6016 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6018 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6019 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6020 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6023 MI.eraseFromParent();
6027 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6030 LLT Ty =
MRI.getType(Dst);
6031 LLT RHSTy =
MRI.getType(RHS);
6033 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6035 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6050 LLT Ty =
MRI.getType(Dst);
6056 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6057 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6058 Builder.buildLShr(Dst, LHS, Trunc);
6059 MI.eraseFromParent();
6066 LLT DstTy =
MRI.getType(Dst);
6067 LLT SrcTy =
MRI.getType(Src);
6069 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6070 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6073 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6102 Builder.buildTruncSSatS(Dst, MatchInfo);
6103 MI.eraseFromParent();
6110 LLT DstTy =
MRI.getType(Dst);
6111 LLT SrcTy =
MRI.getType(Src);
6113 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6114 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6117 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6135 Builder.buildTruncSSatU(Dst, MatchInfo);
6136 MI.eraseFromParent();
6143 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6144 LLT SrcTy =
MRI.getType(Val);
6146 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6147 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6150 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6159 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6168 unsigned Opc =
MI.getOpcode();
6169 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB);
6181 Opc = TargetOpcode::G_FSUB;
6186 Opc = TargetOpcode::G_FADD;
6192 MI.setDesc(
B.getTII().get(
Opc));
6193 MI.getOperand(1).setReg(
X);
6194 MI.getOperand(2).setReg(
Y);
6202 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6205 MatchInfo =
MI.getOperand(2).getReg();
6206 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6208 const auto LHSCst = Ty.isVector()
6215 if (LHSCst->Value.isNegZero())
6219 if (LHSCst->Value.isPosZero())
6229 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6236 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6250 bool &AllowFusionGlobally,
6252 bool CanReassociate)
const {
6254 auto *MF =
MI.getMF();
6255 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6256 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6264 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6267 if (!HasFMAD && !HasFMA)
6272 AllowFusionGlobally = HasFMAD;
6277 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6284 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6286 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6298 unsigned PreferredFusedOpcode =
6299 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6312 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6314 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6315 {LHS.MI->getOperand(1).getReg(),
6316 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6325 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6327 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6328 {RHS.MI->getOperand(1).getReg(),
6329 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6341 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6343 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6347 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6356 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6358 unsigned PreferredFusedOpcode =
6359 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6362 bool LHSContractable =
6365 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6368 bool RHSContractable =
6371 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6375 if (LHSContractable || RHSContractable) {
6378 if (!LHSContractable ||
6379 (RHSContractable &&
hasMoreUses(*LHSFpExtSrc, *RHSFpExtSrc,
MRI))) {
6381 LHSFpExtSrc = RHSFpExtSrc;
6384 unsigned Flags =
MI.getFlags() & LHSFpExtSrc->
getFlags();
6388 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6389 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6400 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6402 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6414 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6416 unsigned PreferredFusedOpcode =
6417 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6422 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6425 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6426 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6431 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6434 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6435 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6444 Register X = FMA->getOperand(1).getReg();
6445 Register Y = FMA->getOperand(2).getReg();
6448 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6449 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6452 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6453 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6454 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6455 {
X,
Y, InnerFMA}, OuterFlags);
6466 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6468 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6475 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6476 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6486 unsigned PreferredFusedOpcode =
6487 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6501 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6502 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6503 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6504 {FpExtU, FpExtV, Z}, InnerFlags)
6506 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6507 {
X,
Y, InnerFMA}, OuterFlags);
6513 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6517 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6519 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6520 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6524 LHS.MI->getOperand(1).getReg(),
6525 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6536 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6541 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6543 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6544 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6548 X =
B.buildFPExt(DstType,
X).getReg(0);
6549 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6552 InnerFlags, OuterFlags,
B);
6561 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6565 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6567 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6568 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6572 RHS.MI->getOperand(1).getReg(),
6573 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6584 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6589 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6591 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6592 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6596 X =
B.buildFPExt(DstType,
X).getReg(0);
6597 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6600 InnerFlags, OuterFlags,
B);
6612 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6614 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6626 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6630 int FirstMulHasFewerUses =
true;
6634 FirstMulHasFewerUses =
false;
6636 unsigned PreferredFusedOpcode =
6637 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6640 if (FirstMulHasFewerUses &&
6643 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6645 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6646 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6647 {LHS.MI->getOperand(1).getReg(),
6648 LHS.MI->getOperand(2).getReg(), NegZ},
6656 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6659 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6660 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6661 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6672 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6674 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6680 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6682 unsigned PreferredFusedOpcode =
6683 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6691 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6695 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6696 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6707 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6709 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6723 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6725 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6731 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6733 unsigned PreferredFusedOpcode =
6734 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6741 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6747 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6748 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6749 {FpExtX, FpExtY, NegZ}, Flags);
6758 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6762 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6765 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6766 {NegY, FpExtZ, LHSReg}, Flags);
6777 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6779 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6783 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6784 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6788 unsigned PreferredFusedOpcode =
6789 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6793 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6794 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6795 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
6806 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6808 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6810 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6813 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6823 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6825 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6837 unsigned &IdxToPropagate)
const {
6839 switch (
MI.getOpcode()) {
6842 case TargetOpcode::G_FMINNUM:
6843 case TargetOpcode::G_FMAXNUM:
6844 PropagateNaN =
false;
6846 case TargetOpcode::G_FMINIMUM:
6847 case TargetOpcode::G_FMAXIMUM:
6848 PropagateNaN =
true;
6852 auto MatchNaN = [&](
unsigned Idx) {
6853 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6857 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6861 return MatchNaN(1) || MatchNaN(2);
6869 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6879 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
6896 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6897 if (&U == &
MI || U.getParent() !=
MI.getParent())
6899 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6900 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
6901 !IsOne(U.getOperand(1).getReg())) {
6914 return MatchInfo.
size() >= MinUses;
6922 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6923 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6924 MatchInfo[0]->getOperand(2).getReg(),
6925 MatchInfo[0]->getFlags());
6930 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6931 Div->getOperand(0).getReg(),
MI->getFlags());
6932 MI->eraseFromParent();
6954 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6963 return MRI.getType(MatchInfo) == DstVecTy;
6966 std::optional<ValueAndVReg> ShiftAmount;
6975 return MRI.getType(MatchInfo) == DstVecTy;
6990 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6997 std::optional<ValueAndVReg> ShiftAmt;
7003 LLT MatchTy =
MRI.getType(MatchInfo);
7004 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7005 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7008unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7010 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7011 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7012 "Expected a NaN behaviour?");
7022 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7023 return TargetOpcode::G_FMAXNUM;
7024 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7025 return TargetOpcode::G_FMAXIMUM;
7026 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7027 return TargetOpcode::G_FMAXNUM;
7028 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7029 return TargetOpcode::G_FMAXIMUM;
7035 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7036 return TargetOpcode::G_FMINNUM;
7037 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7038 return TargetOpcode::G_FMINIMUM;
7039 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7040 return TargetOpcode::G_FMINNUM;
7041 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7043 return TargetOpcode::G_FMINIMUM;
7047CombinerHelper::SelectPatternNaNBehaviour
7049 bool IsOrderedComparison)
const {
7050 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7051 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7053 if (!LHSSafe && !RHSSafe)
7054 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7055 if (LHSSafe && RHSSafe)
7056 return SelectPatternNaNBehaviour::RETURNS_ANY;
7059 if (IsOrderedComparison)
7060 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7061 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7064 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7065 : SelectPatternNaNBehaviour::RETURNS_NAN;
7074 LLT DstTy =
MRI.getType(Dst);
7087 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7089 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7091 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7094 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7095 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7096 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7097 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7099 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7102 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7107 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7112 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7114 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7118 MatchInfo = [=](MachineIRBuilder &
B) {
7119 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7127 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7134 Register TrueVal =
MI.getOperand(2).getReg();
7135 Register FalseVal =
MI.getOperand(3).getReg();
7136 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7141 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7154 if (MatchedSub &&
X != OpLHS)
7162 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7165 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7166 B.buildICmp(Pred, Dst,
Y, Zero);
7173static std::optional<unsigned>
7175 std::optional<int64_t> &Result) {
7176 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7177 Opcode == TargetOpcode::G_ASHR) &&
7178 "Expect G_SHL, G_LSHR or G_ASHR.");
7179 auto SignificantBits = 0;
7181 case TargetOpcode::G_SHL:
7185 case TargetOpcode::G_LSHR:
7189 case TargetOpcode::G_ASHR:
7198 Result = std::nullopt;
7209 Register ShiftVal =
MI.getOperand(1).getReg();
7210 Register ShiftReg =
MI.getOperand(2).getReg();
7211 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7212 auto IsShiftTooBig = [&](
const Constant *
C) {
7217 MatchInfo = std::nullopt;
7221 MI.getOpcode(), MatchInfo);
7222 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7228 unsigned LHSOpndIdx = 1;
7229 unsigned RHSOpndIdx = 2;
7230 switch (
MI.getOpcode()) {
7231 case TargetOpcode::G_UADDO:
7232 case TargetOpcode::G_SADDO:
7233 case TargetOpcode::G_UMULO:
7234 case TargetOpcode::G_SMULO:
7241 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7242 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7252 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7256 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7263 std::optional<FPValueAndVReg> ValAndVReg;
7271 unsigned LHSOpndIdx = 1;
7272 unsigned RHSOpndIdx = 2;
7273 switch (
MI.getOpcode()) {
7274 case TargetOpcode::G_UADDO:
7275 case TargetOpcode::G_SADDO:
7276 case TargetOpcode::G_UMULO:
7277 case TargetOpcode::G_SMULO:
7284 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7285 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7286 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7287 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7291bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7293 if (SrcTy.isFixedVector())
7295 if (SrcTy.isScalar()) {
7299 return IConstant && IConstant->Value == 1;
7304bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7305 LLT SrcTy =
MRI.getType(Src);
7307 return isConstantSplatVector(Src, 0, AllowUndefs);
7312 return IConstant && IConstant->Value == 0;
7319bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7320 bool AllowUndefs)
const {
7326 for (
unsigned I = 0;
I < NumSources; ++
I) {
7327 GImplicitDef *ImplicitDef =
7329 if (ImplicitDef && AllowUndefs)
7331 if (ImplicitDef && !AllowUndefs)
7333 std::optional<ValueAndVReg> IConstant =
7335 if (IConstant && IConstant->Value == SplatValue)
7345CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7348 return IConstant->Value;
7352 return std::nullopt;
7355 std::optional<APInt>
Value = std::nullopt;
7356 for (
unsigned I = 0;
I < NumSources; ++
I) {
7357 std::optional<ValueAndVReg> IConstant =
7360 return std::nullopt;
7362 Value = IConstant->Value;
7363 else if (*
Value != IConstant->Value)
7364 return std::nullopt;
7370bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7380 for (
unsigned I = 0;
I < NumSources; ++
I) {
7381 std::optional<ValueAndVReg> IConstant =
7390bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7397 LLT CondTy =
MRI.getType(
Select->getCondReg());
7398 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7408 std::optional<ValueAndVReg> TrueOpt =
7410 std::optional<ValueAndVReg> FalseOpt =
7413 if (!TrueOpt || !FalseOpt)
7416 APInt TrueValue = TrueOpt->Value;
7417 APInt FalseValue = FalseOpt->Value;
7421 MatchInfo = [=](MachineIRBuilder &
B) {
7422 B.setInstrAndDebugLoc(*
Select);
7423 B.buildZExtOrTrunc(Dest,
Cond);
7430 MatchInfo = [=](MachineIRBuilder &
B) {
7431 B.setInstrAndDebugLoc(*
Select);
7432 B.buildSExtOrTrunc(Dest,
Cond);
7439 MatchInfo = [=](MachineIRBuilder &
B) {
7440 B.setInstrAndDebugLoc(*
Select);
7441 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7442 B.buildNot(Inner,
Cond);
7443 B.buildZExtOrTrunc(Dest, Inner);
7450 MatchInfo = [=](MachineIRBuilder &
B) {
7451 B.setInstrAndDebugLoc(*
Select);
7452 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7453 B.buildNot(Inner,
Cond);
7454 B.buildSExtOrTrunc(Dest, Inner);
7460 if (TrueValue - 1 == FalseValue) {
7461 MatchInfo = [=](MachineIRBuilder &
B) {
7462 B.setInstrAndDebugLoc(*
Select);
7463 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7464 B.buildZExtOrTrunc(Inner,
Cond);
7465 B.buildAdd(Dest, Inner, False);
7471 if (TrueValue + 1 == FalseValue) {
7472 MatchInfo = [=](MachineIRBuilder &
B) {
7473 B.setInstrAndDebugLoc(*
Select);
7474 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7475 B.buildSExtOrTrunc(Inner,
Cond);
7476 B.buildAdd(Dest, Inner, False);
7483 MatchInfo = [=](MachineIRBuilder &
B) {
7484 B.setInstrAndDebugLoc(*
Select);
7485 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7486 B.buildZExtOrTrunc(Inner,
Cond);
7489 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7490 B.buildShl(Dest, Inner, ShAmtC, Flags);
7497 MatchInfo = [=](MachineIRBuilder &
B) {
7498 B.setInstrAndDebugLoc(*
Select);
7500 B.buildNot(Not,
Cond);
7501 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7502 B.buildZExtOrTrunc(Inner, Not);
7505 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7506 B.buildShl(Dest, Inner, ShAmtC, Flags);
7513 MatchInfo = [=](MachineIRBuilder &
B) {
7514 B.setInstrAndDebugLoc(*
Select);
7515 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7516 B.buildSExtOrTrunc(Inner,
Cond);
7517 B.buildOr(Dest, Inner, False, Flags);
7524 MatchInfo = [=](MachineIRBuilder &
B) {
7525 B.setInstrAndDebugLoc(*
Select);
7527 B.buildNot(Not,
Cond);
7528 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7529 B.buildSExtOrTrunc(Inner, Not);
7530 B.buildOr(Dest, Inner, True, Flags);
7539bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7546 LLT CondTy =
MRI.getType(
Select->getCondReg());
7547 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7556 if (CondTy != TrueTy)
7561 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7562 MatchInfo = [=](MachineIRBuilder &
B) {
7563 B.setInstrAndDebugLoc(*
Select);
7564 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7565 B.buildZExtOrTrunc(Ext,
Cond);
7566 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7567 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7574 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7575 MatchInfo = [=](MachineIRBuilder &
B) {
7576 B.setInstrAndDebugLoc(*
Select);
7577 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7578 B.buildZExtOrTrunc(Ext,
Cond);
7579 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7580 B.buildAnd(DstReg, Ext, FreezeTrue);
7586 if (isOneOrOneSplat(False,
true)) {
7587 MatchInfo = [=](MachineIRBuilder &
B) {
7588 B.setInstrAndDebugLoc(*
Select);
7590 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7591 B.buildNot(Inner,
Cond);
7593 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7594 B.buildZExtOrTrunc(Ext, Inner);
7595 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7596 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7602 if (isZeroOrZeroSplat(True,
true)) {
7603 MatchInfo = [=](MachineIRBuilder &
B) {
7604 B.setInstrAndDebugLoc(*
Select);
7606 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7607 B.buildNot(Inner,
Cond);
7609 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7610 B.buildZExtOrTrunc(Ext, Inner);
7611 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7612 B.buildAnd(DstReg, Ext, FreezeFalse);
7634 LLT DstTy =
MRI.getType(DstReg);
7639 if (!
MRI.hasOneNonDBGUse(CondReg))
7648 if (True == CmpRHS && False == CmpLHS) {
7656 if (True != CmpLHS || False != CmpRHS)
7696 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7697 Register DestReg =
MI.getOperand(0).getReg();
7698 LLT DestTy =
MRI.getType(DestReg);
7712 if (
isLegal({NewOpc, {DestTy}})) {
7714 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7726 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7729 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7739bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7741 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7742 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7746 unsigned Flags = Logic->
getFlags();
7765 std::optional<ValueAndVReg> MaybeC1 =
7769 C1 = MaybeC1->Value;
7771 std::optional<ValueAndVReg> MaybeC2 =
7775 C2 = MaybeC2->Value;
7796 std::optional<APInt> Offset1;
7797 std::optional<APInt> Offset2;
7800 std::optional<ValueAndVReg> MaybeOffset1 =
7803 R1 =
Add->getLHSReg();
7804 Offset1 = MaybeOffset1->Value;
7808 std::optional<ValueAndVReg> MaybeOffset2 =
7811 R2 =
Add->getLHSReg();
7812 Offset2 = MaybeOffset2->Value;
7831 bool CreateMask =
false;
7844 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7857 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7866 MatchInfo = [=](MachineIRBuilder &
B) {
7867 if (CreateMask &&
Offset != 0) {
7868 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7869 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7870 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7871 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7872 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7873 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7874 B.buildZExtOrTrunc(DstReg, ICmp);
7875 }
else if (CreateMask &&
Offset == 0) {
7876 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7877 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7878 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7879 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7880 B.buildZExtOrTrunc(DstReg, ICmp);
7881 }
else if (!CreateMask &&
Offset != 0) {
7882 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7883 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7884 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7885 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7886 B.buildZExtOrTrunc(DstReg, ICmp);
7887 }
else if (!CreateMask &&
Offset == 0) {
7888 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7889 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7890 B.buildZExtOrTrunc(DstReg, ICmp);
7898bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7904 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7916 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7922 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7923 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7924 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7925 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7936 if (LHS0 == RHS1 && LHS1 == RHS0) {
7942 if (LHS0 == RHS0 && LHS1 == RHS1) {
7946 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7948 MatchInfo = [=](MachineIRBuilder &
B) {
7953 auto False =
B.buildConstant(CmpTy, 0);
7954 B.buildZExtOrTrunc(DestReg, False);
7961 B.buildZExtOrTrunc(DestReg, True);
7963 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7964 B.buildZExtOrTrunc(DestReg, Cmp);
7976 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7979 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7988 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7991 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8006 bool IsSigned =
Add->isSigned();
8007 LLT DstTy =
MRI.getType(Dst);
8008 LLT CarryTy =
MRI.getType(Carry);
8011 if (
MRI.use_nodbg_empty(Carry) &&
8014 B.buildAdd(Dst, LHS, RHS);
8015 B.buildUndef(Carry);
8021 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8024 B.buildSAddo(Dst, Carry, RHS, LHS);
8030 B.buildUAddo(Dst, Carry, RHS, LHS);
8035 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8036 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8042 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8043 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8045 B.buildConstant(Dst, Result);
8046 B.buildConstant(Carry, Overflow);
8054 B.buildCopy(Dst, LHS);
8055 B.buildConstant(Carry, 0);
8064 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8067 std::optional<APInt> MaybeAddRHS =
8068 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8071 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8072 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8076 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8077 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8083 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8084 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8109 B.buildConstant(Carry, 0);
8116 B.buildAdd(Dst, LHS, RHS);
8117 B.buildConstant(Carry, 1);
8129 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8132 B.buildConstant(Carry, 0);
8148 B.buildConstant(Carry, 0);
8155 B.buildAdd(Dst, LHS, RHS);
8156 B.buildConstant(Carry, 1);
8174 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8180 auto [Dst,
Base] =
MI.getFirst2Regs();
8181 LLT Ty =
MRI.getType(Dst);
8185 Builder.buildFConstant(Dst, 1.0);
8186 MI.removeFromParent();
8198 std::optional<SrcOp> Res;
8200 while (ExpVal > 0) {
8205 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8208 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8215 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8219 MI.eraseFromParent();
8230 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8237 LLT DstTy =
MRI.getType(Dst);
8240 auto Const =
B.buildConstant(DstTy, C1 - C2);
8241 B.buildAdd(Dst,
A, Const);
8255 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8262 LLT DstTy =
MRI.getType(Dst);
8265 auto Const =
B.buildConstant(DstTy, C2 - C1);
8266 B.buildSub(Dst, Const,
A);
8287 LLT DstTy =
MRI.getType(Dst);
8290 auto Const =
B.buildConstant(DstTy, C1 + C2);
8291 B.buildSub(Dst,
A, Const);
8312 LLT DstTy =
MRI.getType(Dst);
8315 auto Const =
B.buildConstant(DstTy, C1 - C2);
8316 B.buildSub(Dst, Const,
A);
8330 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8337 LLT DstTy =
MRI.getType(Dst);
8340 auto Const =
B.buildConstant(DstTy, C2 - C1);
8341 B.buildAdd(Dst,
A, Const);
8385 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8393 LLT SmallBvTy = DstTy;
8397 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8402 {TargetOpcode::G_ANYEXT,
8414 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8415 Ops.push_back(AnyExt.getReg(0));
8433 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8434 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8435 const unsigned NumDstElts = OrigMask.
size();
8436 for (
unsigned i = 0; i != NumDstElts; ++i) {
8437 int Idx = OrigMask[i];
8438 if (Idx >= (
int)NumSrcElems) {
8449 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8450 std::move(NewMask));
8457 const unsigned MaskSize = Mask.size();
8458 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8463 if (Idx < (
int)NumElems)
8464 Mask[
I] = Idx + NumElems;
8466 Mask[
I] = Idx - NumElems;
8476 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8479 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8482 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8483 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8485 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8489 const unsigned NumSrcElems = Src1Ty.getNumElements();
8491 bool TouchesSrc1 =
false;
8492 bool TouchesSrc2 =
false;
8493 const unsigned NumElems = Mask.size();
8494 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8498 if (Mask[Idx] < (
int)NumSrcElems)
8504 if (TouchesSrc1 == TouchesSrc2)
8507 Register NewSrc1 = Shuffle.getSrc1Reg();
8510 NewSrc1 = Shuffle.getSrc2Reg();
8515 auto Undef =
B.buildUndef(Src1Ty);
8516 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8530 LLT DstTy =
MRI.getType(Dst);
8531 LLT CarryTy =
MRI.getType(Carry);
8553 B.buildConstant(Carry, 0);
8560 B.buildSub(Dst, LHS, RHS);
8578 B.buildConstant(Carry, 0);
8585 B.buildSub(Dst, LHS, RHS);
8602 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8603 "Expected G_CTLZ variant");
8608 LLT Ty =
MRI.getType(Dst);
8609 LLT SrcTy =
MRI.getType(Src);
8611 if (!(Ty.isValid() && Ty.isScalar()))
8620 switch (
LI->getAction(Query).Action) {
8631 bool NeedAdd =
true;
8639 unsigned BitWidth = Ty.getScalarSizeInBits();
8650 B.buildCTLS(Dst,
X);
8654 auto Ctls =
B.buildCTLS(Ty,
X);
8655 auto One =
B.buildConstant(Ty, 1);
8657 B.buildAdd(Dst, Ctls, One);
8667 unsigned TargetOpc)
const {
8668 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8669 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8670 "Expected G_LSHR/G_ASHR");
8673 return XTy ==
MRI.getType(
Y) &&
isLegal({TargetOpc, {XTy}});
8677 assert((
MI.getOpcode() == TargetOpcode::G_CTLZ ||
8678 MI.getOpcode() == TargetOpcode::G_CTTZ) &&
8679 "Expected count-zero opcode");
8680 switch (
MI.getOpcode()) {
8681 case TargetOpcode::G_CTLZ:
8682 return TargetOpcode::G_CTLZ_ZERO_POISON;
8683 case TargetOpcode::G_CTTZ:
8684 return TargetOpcode::G_CTTZ_ZERO_POISON;
8696 if (!
VT->isKnownNeverZero(Src))
8699 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8700 LLT SrcTy =
MRI.getType(Src);
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 const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
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 unsigned getCountZeroPoisonOpcode(const MachineInstr &MI)
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...
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...
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Interface for Targets to specify which operations they can successfully select and how the others sho...
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t IntrinsicInst * II
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.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static 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 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.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
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 getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
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)
static LLVM_ABI bool isEquality(Predicate pred)
Determine if this is an equals/not equals predicate.
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.
LLVM_ABI void applyCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
LLVM_ABI void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
LLVM_ABI bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
LLVM_ABI bool matchCountZeroToZeroPoison(MachineInstr &MI) const
LLVM_ABI bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
LLVM_ABI const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
LLVM_ABI bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
LLVM_ABI void applyUDivOrURemByConst(MachineInstr &MI) const
LLVM_ABI bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
LLVM_ABI void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
LLVM_ABI bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
LLVM_ABI 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)
LLVM_ABI bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchAVG(MachineInstr &MI, MachineRegisterInfo &MRI, Register X, Register Y, unsigned TargetOpc) const
LLVM_ABI bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
LLVM_ABI bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
LLVM_ABI bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
LLVM_ABI bool matchPtrAddZero(MachineInstr &MI) const
}
const TargetInstrInfo * TII
LLVM_ABI 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.
LLVM_ABI void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
LLVM_ABI bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
LLVM_ABI bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
LLVM_ABI 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...
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
LLVM_ABI bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI 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.
LLVM_ABI void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
LLVM_ABI void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
LLVM_ABI bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
LLVM_ABI void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
LLVM_ABI 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.
LLVM_ABI void applyCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo) const
LLVM_ABI bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
LLVM_ABI void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
LLVM_ABI bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
LLVM_ABI 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...
LLVM_ABI void applyUMulHToLShr(MachineInstr &MI) const
LLVM_ABI void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
LLVM_ABI bool isLegalOrHasFewerElements(const LegalityQuery &Query) const
LLVM_ABI bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
LLVM_ABI bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
LLVM_ABI bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
LLVM_ABI bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
LLVM_ABI bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI const TargetLowering & getTargetLowering() const
LLVM_ABI bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
LLVM_ABI void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
LLVM_ABI void applySDivByPow2(MachineInstr &MI) const
LLVM_ABI void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
LLVM_ABI bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
LLVM_ABI bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
LLVM_ABI void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
LLVM_ABI 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,...
LLVM_ABI void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
LLVM_ABI void applyCombineCopy(MachineInstr &MI) const
LLVM_ABI bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
LLVM_ABI bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
LLVM_ABI 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,...
LLVM_ABI bool matchSextTruncSextLoad(MachineInstr &MI) const
LLVM_ABI bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
LLVM_ABI bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
LLVM_ABI bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
LLVM_ABI bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
LLVM_ABI bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
LLVM_ABI bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
LLVM_ABI bool matchCombineCopy(MachineInstr &MI) const
LLVM_ABI bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
LLVM_ABI void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
LLVM_ABI bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
LLVM_ABI bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
LLVM_ABI void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
LLVM_ABI bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
LLVM_ABI bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchRedundantSExtInReg(MachineInstr &MI) const
LLVM_ABI void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
LLVM_ABI void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
LLVM_ABI bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
LLVM_ABI void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
LLVM_ABI bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
LLVM_ABI bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
LLVM_ABI void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
LLVM_ABI bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
LLVM_ABI void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
LLVM_ABI bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
LLVM_ABI bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
LLVM_ABI void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
LLVM_ABI bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
LLVM_ABI bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
LLVM_ABI bool isPreLegalize() const
LLVM_ABI bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
LLVM_ABI bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI 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...
LLVM_ABI bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
LLVM_ABI bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
LLVM_ABI bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVM_ABI LLVMContext & getContext() const
LLVM_ABI void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
LLVM_ABI bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
LLVM_ABI bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
LLVM_ABI bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
LLVM_ABI bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
LLVM_ABI bool matchConstantFoldUnaryIntOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold a unary integer op (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON variants,...
LLVM_ABI void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
LLVM_ABI bool isLegal(const LegalityQuery &Query) const
LLVM_ABI bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
LLVM_ABI bool matchOperandIsKnownToBeAPowerOfTwo(const MachineOperand &MO, bool OrNegative=false) const
Check if operand MO is known to be a power of 2.
LLVM_ABI bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
LLVM_ABI void eraseInst(MachineInstr &MI) const
Erase MI.
LLVM_ABI bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
LLVM_ABI void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
LLVM_ABI void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
LLVM_ABI void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
LLVM_ABI 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.
LLVM_ABI MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
LLVM_ABI void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
LLVM_ABI bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
LLVM_ABI bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
LLVM_ABI bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
LLVM_ABI bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
LLVM_ABI void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
LLVM_ABI void applyRotateOutOfRange(MachineInstr &MI) const
LLVM_ABI bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
LLVM_ABI bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
LLVM_ABI bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
LLVM_ABI bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
LLVM_ABI bool isDesirableToCommuteWithShift(const MachineInstr &MI) const
LLVM_ABI 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) !...
LLVM_ABI 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...
LLVM_ABI bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
LLVM_ABI void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
LLVM_ABI bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
LLVM_ABI bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
LLVM_ABI bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
LLVM_ABI bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchRotateOutOfRange(MachineInstr &MI) const
LLVM_ABI void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
LLVM_ABI void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
LLVM_ABI bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
LLVM_ABI bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
LLVM_ABI void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
LLVM_ABI bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
LLVM_ABI bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
LLVM_ABI void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applySimplifySRemByPow2(MachineInstr &MI) const
Combine G_SREM x, (+/-2^k) to a bias-and-mask sequence.
LLVM_ABI bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
LLVM_ABI bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
LLVM_ABI void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
LLVM_ABI void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
LLVM_ABI bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
LLVM_ABI void applyFunnelShiftToRotate(MachineInstr &MI) const
LLVM_ABI bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
LLVM_ABI bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
LLVM_ABI bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
LLVM_ABI bool matchBinopWithNeg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold a bitwiseop (~b +/- c) -> a bitwiseop ~(b -/+ c)
LLVM_ABI bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
LLVM_ABI void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
LLVM_ABI bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
LLVM_ABI bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
LLVM_ABI void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
LLVM_ABI 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.
LLVM_ABI bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
LLVM_ABI bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
LLVM_ABI bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
LLVM_ABI bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
LLVM_ABI bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
LLVM_ABI void applyCountZeroToZeroPoison(MachineInstr &MI) const
LLVM_ABI void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
LLVM_ABI bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
LLVM_ABI bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applySDivOrSRemByConst(MachineInstr &MI) const
LLVM_ABI bool matchCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo, unsigned MaxLen=0) const
LLVM_ABI 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...
LLVM_ABI bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
LLVM_ABI 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.
LLVM_ABI bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
LLVM_ABI bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
LLVM_ABI void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
LLVM_ABI void applyCommuteBinOpOperands(MachineInstr &MI) const
LLVM_ABI void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
LLVM_ABI const MachineFunction & getMachineFunction() const
LLVM_ABI bool matchCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
Combine G_BUILD_VECTOR(G_UNMERGE(G_BITCAST), Undef) to G_BITCAST(G_BUILD_VECTOR(.....
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
LLVM_ABI void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
LLVM_ABI void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
LLVM_ABI bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
LLVM_ABI void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
LLVM_ABI bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
LLVM_ABI void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
LLVM_ABI bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
LLVM_ABI void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
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.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
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.
Register getSrcReg() const
Represents a G_CONCAT_VECTORS.
Abstract class that contains various methods for clients to notify about changes.
Simple wrapper observer that takes several observers, and calls each one for each event.
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.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
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.
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
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 ElementCount getElementCount() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
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.
This is an important class for using LLVM in a threaded context.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
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...
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.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Helper class to build MachineInstr.
const TargetInstrInfo & getTII()
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 buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
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.
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...
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.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
bool isAtomic() const
Returns true if this operation has an atomic ordering requirement of unordered or higher,...
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
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.
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.
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
static use_instr_nodbg_iterator use_instr_nodbg_end()
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
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_arg_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.
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 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 isDesirableToCommuteWithShift(const SDNode *N, CombineLevel Level) const
Return true if it is profitable to move this shift by a constant amount through its operand,...
virtual unsigned combineRepeatedFPDivisors() const
Indicate whether this target prefers to combine FDIVs with the same divisor.
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.
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...
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ 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.
@ Custom
The target wants to do something special with this combination of operand and type.
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
GInstrBind< GBuildVector > m_GBuildVector(GBuildVector *&Inst)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
LoadOp_match< GLoad, PtrP > m_GLoad(const PtrP &Ptr)
MIFlagsRef m_MIFlags(uint32_t &Flags)
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)
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)
GInstrBind< GConcatVectors > m_GConcatVectors(GConcatVectors *&Inst)
GConstantBitsMatch m_GConstantOrFConstantBits(APInt &Bits)
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< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP > m_GICmp(const Pred &P, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
GInstrBind< GUnmerge > m_GUnmerge(GUnmerge *&Inst)
Instruction binders for ops with no operand-form matcher (constant-immediate or variadic-source ops).
MMORef m_MMO(const MachineMemOperand *&MMO)
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)
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT > m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
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)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(const APInt &RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
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.
LoadOp_match< GAnyLoad, PtrP > m_GAnyLoad(const PtrP &Ptr)
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)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FMUL, true > m_GFMul(const LHS &L, const RHS &R)
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)
auto 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 std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
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 std::optional< APFloat > isConstantOrConstantSplatVectorFP(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a float constant integer or a splat vector of float constant integers.
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...
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
std::function< void(MachineIRBuilder &)> BuildFnTy
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)
@ Load
The value being inserted comes from a load (InsertElement only).
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
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...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
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.
SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > OperandBuildSteps
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.
std::tuple< Register, Register, uint64_t, Align, bool, std::vector< LLT > > MemCpyFamilyLoweringInfo
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...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_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 bool canLowerMemCpyFamily(const MachineInstr &MI, const MachineRegisterInfo &MRI, unsigned MaxLen, Register &Dst, Register &Src, uint64_t &KnownLen, Align &Alignment, bool &DstAlignCanChange, std::vector< LLT > &MemOps)
Matcher for memcpy-like instructions.
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.
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
@ Fast
Assign the register banks as fast as possible (default).
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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
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 SmallVector< APInt > ConstantFoldUnaryIntOp(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Tries to constant fold a unary integer operation (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON vari...
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.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
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.
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...
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
unsigned PostShift
post-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true, bool AllowWidenOptimization=false)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...