46#define DEBUG_TYPE "gi-combiner"
55 cl::desc(
"Force all indexed operations to be "
56 "legal for the GlobalISel combiner"));
65 TII(
Builder.getMF().getSubtarget().getInstrInfo()),
66 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
67 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
72 return *
Builder.getMF().getSubtarget().getTargetLowering();
90 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
98 LLT Ty = MRI.getType(V);
109 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
110 return ByteWidth -
I - 1;
130static std::optional<bool>
134 unsigned Width = MemOffset2Idx.
size();
137 bool BigEndian =
true, LittleEndian =
true;
138 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
139 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
140 if (MemOffsetAndIdx == MemOffset2Idx.
end())
142 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
143 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
146 if (!BigEndian && !LittleEndian)
150 assert((BigEndian != LittleEndian) &&
151 "Pattern cannot be both big and little endian!");
158 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
186 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
187 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
194 if (
MRI.constrainRegAttrs(ToReg, FromReg))
195 MRI.replaceRegWith(FromReg, ToReg);
197 Builder.buildCopy(FromReg, ToReg);
199 Observer.finishedChangingAllUsesOfReg();
214 unsigned ToOpcode)
const {
229 MRI.setRegBank(Reg, *RegBank);
240 if (
MI.getOpcode() != TargetOpcode::COPY)
250 MI.eraseFromParent();
255 assert(
MI.getOpcode() == TargetOpcode::G_FREEZE &&
"Invalid instruction");
261 if (!
MRI.hasOneNonDBGUse(OrigOp))
282 std::optional<MachineOperand> MaybePoisonOperand;
284 if (!Operand.isReg())
290 if (!MaybePoisonOperand)
291 MaybePoisonOperand = Operand;
300 if (!MaybePoisonOperand) {
305 B.buildCopy(
DstOp, OrigOp);
310 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
311 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
314 {TargetOpcode::G_FREEZE, {MaybePoisonOperandRegTy}}))
322 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
333 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
334 "Invalid instruction");
346 if (!
MRI.hasOneNonDBGUse(Reg))
348 switch (Def->getOpcode()) {
349 case TargetOpcode::G_BUILD_VECTOR:
354 Ops.push_back(BuildVecMO.getReg());
356 case TargetOpcode::G_IMPLICIT_DEF: {
357 LLT OpType =
MRI.getType(Reg);
364 OpType.getScalarType() &&
365 "All undefs should have the same type");
368 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
369 EltIdx != EltEnd; ++EltIdx)
370 Ops.push_back(
Undef->getOperand(0).getReg());
379 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
381 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
396 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
409 MI.eraseFromParent();
418 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
423 LLT InputTy =
MRI.getType(BCSrc);
425 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
430 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
434 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
450 Ops.push_back(BCSrc);
471 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
472 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
473 MI.eraseFromParent();
479 Register SrcVec1 = Shuffle.getSrc1Reg();
480 Register SrcVec2 = Shuffle.getSrc2Reg();
481 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
482 int Width =
MRI.getType(SrcVec1).getNumElements();
484 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
485 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
489 for (
int Val : Shuffle.getMask()) {
492 else if (Val < Width)
493 Extracts.
push_back(Unmerge1.getReg(Val));
495 Extracts.
push_back(Unmerge2.getReg(Val - Width));
497 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
498 if (Extracts.
size() == 1)
499 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
501 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
502 MI.eraseFromParent();
519 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
521 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
525 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
526 if (i + j >= Mask.size())
528 if (Mask[i + j] != -1)
532 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
535 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
536 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
537 if (i + j >= Mask.size())
539 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
556 {TargetOpcode::G_CONCAT_VECTORS,
557 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
568 SrcTy =
MRI.getType(Reg);
570 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
577 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
583 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
586 MI.eraseFromParent();
591 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
592 "Invalid instruction kind");
593 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
595 LLT SrcType =
MRI.getType(Src1);
597 unsigned DstNumElts = DstType.getNumElements();
598 unsigned SrcNumElts = SrcType.getNumElements();
615 if (DstNumElts < 2 * SrcNumElts)
620 if (DstNumElts % SrcNumElts != 0)
626 unsigned NumConcat = DstNumElts / SrcNumElts;
629 for (
unsigned i = 0; i != DstNumElts; ++i) {
636 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
637 (ConcatSrcs[i / SrcNumElts] >= 0 &&
638 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
641 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
648 for (
auto Src : ConcatSrcs) {
652 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
654 Ops.push_back(UndefReg);
667 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
675 MI.eraseFromParent();
684 const LLT TyForCandidate,
685 unsigned OpcodeForCandidate,
690 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
701 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
704 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
705 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
706 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
714 OpcodeForCandidate == TargetOpcode::G_ZEXT)
716 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
717 OpcodeForCandidate == TargetOpcode::G_SEXT)
718 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
727 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
738static void InsertInsnsWithoutSideEffectsBeforeUse(
750 InsertBB = PredBB->
getMBB();
755 if (InsertBB ==
DefMI.getParent()) {
757 Inserter(InsertBB, std::next(InsertPt), UseMO);
776 unsigned CandidateLoadOpc;
778 case TargetOpcode::G_ANYEXT:
779 CandidateLoadOpc = TargetOpcode::G_LOAD;
781 case TargetOpcode::G_SEXT:
782 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
784 case TargetOpcode::G_ZEXT:
785 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
790 return CandidateLoadOpc;
807 LLT LoadValueTy =
MRI.getType(LoadReg);
829 unsigned PreferredOpcode =
831 ? TargetOpcode::G_ANYEXT
833 Preferred = {
LLT(), PreferredOpcode,
nullptr};
834 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
835 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
836 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
837 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
838 const auto &MMO = LoadMI->
getMMO();
846 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
848 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
852 Preferred = ChoosePreferredUse(
MI, Preferred,
853 MRI.getType(
UseMI.getOperand(0).getReg()),
863 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
881 if (PreviouslyEmitted) {
888 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
889 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
891 EmittedInsns[InsertIntoBB] = NewMI;
897 MI.setDesc(
Builder.getTII().get(LoadOpc));
904 for (
auto *UseMO :
Uses) {
910 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
913 const LLT UseDstTy =
MRI.getType(UseDstReg);
914 if (UseDstReg != ChosenDstReg) {
915 if (Preferred.
Ty == UseDstTy) {
952 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
967 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
970 MI.getOperand(0).setReg(ChosenDstReg);
976 assert(
MI.getOpcode() == TargetOpcode::G_AND);
987 if (
MRI.getType(Dst).isVector())
995 APInt MaskVal = MaybeMask->Value;
1010 LLT RegTy =
MRI.getType(LoadReg);
1013 unsigned MaskSizeBits = MaskVal.
countr_one();
1016 !
MRI.hasOneNonDBGUse(LoadReg))
1021 if (MaskSizeBits > LoadSizeBits)
1040 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1045 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1049 B.setInstrAndDebugLoc(*LoadMI);
1050 auto &MF =
B.getMF();
1052 auto *NewMMO = MF.getMachineMemOperand(MMO, PtrInfo, MemDesc.
MemoryTy);
1053 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1063 "shouldn't consider debug uses");
1071 if (DefOrUse ==
MBB.end())
1073 return &*DefOrUse == &
DefMI;
1079 "shouldn't consider debug uses");
1082 else if (
DefMI.getParent() !=
UseMI.getParent())
1089 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1093 if (
MRI.getType(SrcReg).isVector())
1098 LoadUser = TruncSrc;
1100 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1105 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1107 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1109 if (LoadSizeBits == SizeInBits)
1116 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1117 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1118 MI.eraseFromParent();
1122 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1123 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1126 LLT RegTy =
MRI.getType(DstReg);
1139 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1141 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1147 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1150 if (NewSizeBits < 8)
1163 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1168 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1171 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1176 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1177 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1179 unsigned ScalarSizeBits;
1180 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1189 auto &MMO = LoadDef->
getMMO();
1190 Builder.setInstrAndDebugLoc(*LoadDef);
1192 auto PtrInfo = MMO.getPointerInfo();
1193 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1194 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1197 MI.eraseFromParent();
1208 auto *MF =
MI->getMF();
1215 AM.
BaseOffs = CstOff->getSExtValue();
1220 MF->getDataLayout(), AM,
1222 MF->getFunction().getContext()),
1223 MI->getMMO().getAddrSpace());
1228 case TargetOpcode::G_LOAD:
1229 return TargetOpcode::G_INDEXED_LOAD;
1230 case TargetOpcode::G_STORE:
1231 return TargetOpcode::G_INDEXED_STORE;
1232 case TargetOpcode::G_ZEXTLOAD:
1233 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1234 case TargetOpcode::G_SEXTLOAD:
1235 return TargetOpcode::G_INDEXED_SEXTLOAD;
1241bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1251 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1252 OpTys = {PtrTy, Ty, Ty};
1254 OpTys = {Ty, PtrTy};
1256 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1262 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1263 "considered for post-indexing."));
1267 bool &RematOffset)
const {
1280 if (!isIndexedLoadStoreLegal(LdSt))
1291 unsigned NumUsesChecked = 0;
1304 if (StoredValDef == &
Use)
1307 Offset = PtrAdd->getOffsetReg();
1309 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1317 RematOffset =
false;
1321 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1326 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1327 if (&BasePtrUse == PtrDef)
1333 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1335 isIndexedLoadStoreLegal(*BasePtrLdSt))
1341 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1342 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1345 if (BaseUseUse.getParent() != LdSt.
getParent())
1357 Addr = PtrAdd->getReg(0);
1358 Base = PtrAdd->getBaseReg();
1373 MRI.hasOneNonDBGUse(Addr))
1380 if (!isIndexedLoadStoreLegal(LdSt))
1384 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1389 if (
Base == St->getValueReg())
1394 if (St->getValueReg() == Addr)
1399 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1400 if (AddrUse.getParent() != LdSt.
getParent())
1405 bool RealUse =
false;
1406 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1424 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1434 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1441 if (!LoadMI->isSimple())
1453 const unsigned MaxIter = 20;
1456 if (
II->isLoadFoldBarrier())
1458 if (Iter++ == MaxIter)
1474 int Elt = CVal->getZExtValue();
1487 Register VecPtr = LoadMI->getPointerReg();
1488 LLT PtrTy =
MRI.getType(VecPtr);
1496 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1519 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1534 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1536 if (!MatchInfo.
IsPre &&
1537 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1547 unsigned Opcode =
MI.getOpcode();
1548 bool IsStore = Opcode == TargetOpcode::G_STORE;
1554 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1556 *OldCst->getOperand(1).getCImm());
1557 MatchInfo.
Offset = NewCst.getReg(0);
1560 auto MIB =
Builder.buildInstr(NewOpcode);
1562 MIB.addDef(MatchInfo.
Addr);
1563 MIB.addUse(
MI.getOperand(0).getReg());
1565 MIB.addDef(
MI.getOperand(0).getReg());
1566 MIB.addDef(MatchInfo.
Addr);
1569 MIB.addUse(MatchInfo.
Base);
1570 MIB.addUse(MatchInfo.
Offset);
1571 MIB.addImm(MatchInfo.
IsPre);
1572 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1573 MI.eraseFromParent();
1581 unsigned Opcode =
MI.getOpcode();
1582 bool IsDiv, IsSigned;
1587 case TargetOpcode::G_SDIV:
1588 case TargetOpcode::G_UDIV: {
1590 IsSigned = Opcode == TargetOpcode::G_SDIV;
1593 case TargetOpcode::G_SREM:
1594 case TargetOpcode::G_UREM: {
1596 IsSigned = Opcode == TargetOpcode::G_SREM;
1602 unsigned DivOpcode, RemOpcode, DivremOpcode;
1604 DivOpcode = TargetOpcode::G_SDIV;
1605 RemOpcode = TargetOpcode::G_SREM;
1606 DivremOpcode = TargetOpcode::G_SDIVREM;
1608 DivOpcode = TargetOpcode::G_UDIV;
1609 RemOpcode = TargetOpcode::G_UREM;
1610 DivremOpcode = TargetOpcode::G_UDIVREM;
1628 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1629 if (
MI.getParent() ==
UseMI.getParent() &&
1630 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1631 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1644 unsigned Opcode =
MI.getOpcode();
1645 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1648 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1649 DestDivReg =
MI.getOperand(0).getReg();
1653 DestRemReg =
MI.getOperand(0).getReg();
1657 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1664 Builder.setInstrAndDebugLoc(*FirstInst);
1666 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1667 : TargetOpcode::G_UDIVREM,
1668 {DestDivReg, DestRemReg},
1670 MI.eraseFromParent();
1676 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1693 if (BrIt ==
MBB->begin())
1695 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1697 BrCond = &*std::prev(BrIt);
1698 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1704 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1705 MBB->isLayoutSuccessor(BrCondTarget);
1711 Builder.setInstrAndDebugLoc(*BrCond);
1716 auto True =
Builder.buildConstant(
1722 MI.getOperand(0).setMBB(FallthroughBB);
1735 unsigned MaxLen)
const {
1736 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1738 DstAlignCanChange, MemOps);
1743 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1748 DstAlignCanChange, MemOps) ==
1750 assert(
Changed &&
"expected memcpy-family instruction to lower");
1755 unsigned MaxLen)
const {
1767 switch (
MI.getOpcode()) {
1770 case TargetOpcode::G_FNEG: {
1771 Result.changeSign();
1774 case TargetOpcode::G_FABS: {
1778 case TargetOpcode::G_FCEIL:
1781 case TargetOpcode::G_FFLOOR:
1784 case TargetOpcode::G_INTRINSIC_TRUNC:
1787 case TargetOpcode::G_INTRINSIC_ROUND:
1790 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1793 case TargetOpcode::G_FRINT:
1794 case TargetOpcode::G_FNEARBYINT:
1798 case TargetOpcode::G_FPEXT:
1799 case TargetOpcode::G_FPTRUNC: {
1806 case TargetOpcode::G_FSQRT: {
1810 Result =
APFloat(sqrt(Result.convertToDouble()));
1813 case TargetOpcode::G_FLOG2: {
1833 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1834 MI.eraseFromParent();
1845 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1868 Type *AccessTy =
nullptr;
1869 auto &MF = *
MI.getMF();
1870 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1873 MF.getFunction().getContext());
1878 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1883 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1885 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1886 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1887 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1888 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1897 unsigned PtrAddFlags =
MI.getFlags();
1913 MatchInfo.
Flags = Flags;
1919 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1921 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1925 MI.getOperand(1).setReg(MatchInfo.
Base);
1926 MI.getOperand(2).setReg(NewOffset.getReg(0));
1940 unsigned Opcode =
MI.getOpcode();
1941 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1942 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1943 Opcode == TargetOpcode::G_USHLSAT) &&
1944 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1964 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1969 if (Opcode == TargetOpcode::G_USHLSAT &&
1970 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1978 unsigned Opcode =
MI.getOpcode();
1979 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1980 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1981 Opcode == TargetOpcode::G_USHLSAT) &&
1982 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1984 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1985 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1986 auto Imm = MatchInfo.
Imm;
1988 if (
Imm >= ScalarSizeInBits) {
1990 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1991 Builder.buildConstant(
MI.getOperand(0), 0);
1992 MI.eraseFromParent();
1997 Imm = ScalarSizeInBits - 1;
2000 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
2003 MI.getOperand(1).setReg(MatchInfo.
Reg);
2004 MI.getOperand(2).setReg(NewImm);
2020 unsigned ShiftOpcode =
MI.getOpcode();
2021 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2022 ShiftOpcode == TargetOpcode::G_ASHR ||
2023 ShiftOpcode == TargetOpcode::G_LSHR ||
2024 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2025 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2026 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2029 Register LogicDest =
MI.getOperand(1).getReg();
2030 if (!
MRI.hasOneNonDBGUse(LogicDest))
2036 unsigned LogicOpcode = LogicMI->
getOpcode();
2037 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2038 LogicOpcode != TargetOpcode::G_XOR)
2042 const Register C1 =
MI.getOperand(2).getReg();
2044 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2047 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2049 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2051 if (
MI->getOpcode() != ShiftOpcode ||
2052 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2061 ShiftVal = MaybeImmVal->Value.getSExtValue();
2075 if (matchFirstShift(LogicMIOp1, C0Val)) {
2077 MatchInfo.
Shift2 = LogicMIOp1;
2078 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2080 MatchInfo.
Shift2 = LogicMIOp2;
2084 MatchInfo.
ValSum = C0Val + C1Val;
2087 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2090 MatchInfo.
Logic = LogicMI;
2096 unsigned Opcode =
MI.getOpcode();
2097 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2098 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2099 Opcode == TargetOpcode::G_SSHLSAT) &&
2100 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2102 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2103 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2109 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2118 Register Shift2Const =
MI.getOperand(2).getReg();
2120 .buildInstr(Opcode, {DestType},
2130 MI.eraseFromParent();
2135 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2160 LLT SrcTy =
MRI.getType(SrcReg);
2162 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2163 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2164 B.buildInstr(SrcOpc, {DstReg}, {
S1, S2});
2172 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2176 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2191 LLT InnerShiftTy =
MRI.getType(InnerShift);
2193 if ((N1C + N001C).ult(InnerShiftSize)) {
2199 if ((N001C + OpSizeInBits) == InnerShiftSize)
2201 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2202 MatchInfo.
Mask =
true;
2212 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2219 if (MatchInfo.
Mask ==
true) {
2227 Builder.buildTrunc(Dst, Shift);
2228 MI.eraseFromParent();
2232 unsigned &ShiftVal)
const {
2233 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2239 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2240 return (
static_cast<int32_t
>(ShiftVal) != -1);
2244 unsigned &ShiftVal)
const {
2245 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2247 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2250 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2251 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2272 auto NegCst =
B.buildConstant(Ty, -
Imm);
2274 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2275 MI.getOperand(2).setReg(NegCst.getReg(0));
2277 if (
Imm.isMinSignedValue())
2287 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2301 if (!MaybeShiftAmtVal)
2305 LLT SrcTy =
MRI.getType(ExtSrc);
2315 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2316 MatchData.
Reg = ExtSrc;
2317 MatchData.
Imm = ShiftAmt;
2319 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2320 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2321 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2327 int64_t ShiftAmtVal = MatchData.
Imm;
2329 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2330 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2332 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2333 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2334 MI.eraseFromParent();
2341 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2345 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2348 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2349 if (MergedValues[
I] != Unmerge->getReg(
I))
2352 MatchInfo = Unmerge->getSourceReg();
2366 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2367 "Expected an unmerge");
2376 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2377 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2379 if (SrcMergeTy != Dst0Ty && !SameSize)
2383 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2384 Operands.push_back(SrcInstr->getSourceReg(Idx));
2390 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2391 "Expected an unmerge");
2393 "Not enough operands to replace all defs");
2394 unsigned NumElems =
MI.getNumOperands() - 1;
2397 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2398 bool CanReuseInputDirectly = DstTy == SrcTy;
2399 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2400 Register DstReg =
MI.getOperand(Idx).getReg();
2405 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2406 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2407 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2408 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2411 if (CanReuseInputDirectly)
2414 Builder.buildCast(DstReg, SrcReg);
2416 MI.eraseFromParent();
2421 unsigned SrcIdx =
MI.getNumOperands() - 1;
2422 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2428 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2431 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2433 Val = Val.
lshr(ShiftAmt);
2441 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2442 "Expected an unmerge");
2444 "Not enough operands to replace all defs");
2445 unsigned NumElems =
MI.getNumOperands() - 1;
2446 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2447 Register DstReg =
MI.getOperand(Idx).getReg();
2448 Builder.buildConstant(DstReg, Csts[Idx]);
2451 MI.eraseFromParent();
2457 unsigned SrcIdx =
MI.getNumOperands() - 1;
2458 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2460 unsigned NumElems =
MI.getNumOperands() - 1;
2461 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2462 Register DstReg =
MI.getOperand(Idx).getReg();
2463 B.buildUndef(DstReg);
2471 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2472 "Expected an unmerge");
2473 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2474 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2477 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2478 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2486 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2487 Register Dst0Reg =
MI.getOperand(0).getReg();
2488 Builder.buildTrunc(Dst0Reg, SrcReg);
2489 MI.eraseFromParent();
2493 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2494 "Expected an unmerge");
2495 Register Dst0Reg =
MI.getOperand(0).getReg();
2496 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2502 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2503 LLT SrcTy =
MRI.getType(SrcReg);
2504 if (SrcTy.isVector())
2514 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2519 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2520 "Expected an unmerge");
2522 Register Dst0Reg =
MI.getOperand(0).getReg();
2527 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2528 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2531 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2534 "ZExt src doesn't fit in destination");
2539 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2541 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2544 MI.eraseFromParent();
2548 unsigned TargetShiftSize,
2549 unsigned &ShiftVal)
const {
2550 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2551 MI.getOpcode() == TargetOpcode::G_LSHR ||
2552 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2554 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2559 unsigned Size = Ty.getSizeInBits();
2560 if (
Size <= TargetShiftSize)
2568 ShiftVal = MaybeImmVal->Value.getSExtValue();
2569 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2576 LLT Ty =
MRI.getType(SrcReg);
2577 unsigned Size = Ty.getSizeInBits();
2578 unsigned HalfSize =
Size / 2;
2579 assert(ShiftVal >= HalfSize);
2583 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2584 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2586 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2587 Register Narrowed = Unmerge.getReg(1);
2594 if (NarrowShiftAmt != 0) {
2595 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2596 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2599 auto Zero =
Builder.buildConstant(HalfTy, 0);
2600 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2601 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2602 Register Narrowed = Unmerge.getReg(0);
2607 if (NarrowShiftAmt != 0) {
2608 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2609 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2612 auto Zero =
Builder.buildConstant(HalfTy, 0);
2613 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2615 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2617 HalfTy, Unmerge.getReg(1),
2618 Builder.buildConstant(HalfTy, HalfSize - 1));
2620 if (ShiftVal == HalfSize) {
2623 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2624 }
else if (ShiftVal ==
Size - 1) {
2632 HalfTy, Unmerge.getReg(1),
2633 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2641 MI.eraseFromParent();
2657 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2659 LLT DstTy =
MRI.getType(DstReg);
2667 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2669 Builder.buildCopy(DstReg, Reg);
2670 MI.eraseFromParent();
2675 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2677 Builder.buildZExtOrTrunc(DstReg, Reg);
2678 MI.eraseFromParent();
2683 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2686 LLT IntTy =
MRI.getType(LHS);
2690 PtrReg.second =
false;
2691 for (
Register SrcReg : {LHS, RHS}) {
2695 LLT PtrTy =
MRI.getType(PtrReg.first);
2700 PtrReg.second =
true;
2712 const bool DoCommute = PtrReg.second;
2717 LLT PtrTy =
MRI.getType(LHS);
2719 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2720 Builder.buildPtrToInt(Dst, PtrAdd);
2721 MI.eraseFromParent();
2725 APInt &NewCst)
const {
2727 Register LHS = PtrAdd.getBaseReg();
2728 Register RHS = PtrAdd.getOffsetReg();
2734 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2737 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2746 APInt &NewCst)
const {
2750 Builder.buildConstant(Dst, NewCst);
2751 PtrAdd.eraseFromParent();
2756 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2761 SrcReg = OriginalSrcReg;
2762 LLT DstTy =
MRI.getType(DstReg);
2770 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2773 LLT DstTy =
MRI.getType(DstReg);
2778 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2779 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2789 if (ShiftSize > 32 && TruncSize < 32)
2802 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2803 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2807 if (!
MRI.hasOneNonDBGUse(SrcReg))
2810 LLT SrcTy =
MRI.getType(SrcReg);
2811 LLT DstTy =
MRI.getType(DstReg);
2820 case TargetOpcode::G_SHL: {
2829 case TargetOpcode::G_LSHR:
2830 case TargetOpcode::G_ASHR: {
2836 for (
auto &
User :
MRI.use_instructions(DstReg))
2837 if (
User.getOpcode() == TargetOpcode::G_STORE)
2841 if (NewShiftTy == SrcTy)
2855 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2858 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2863 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2865 LLT NewShiftTy = MatchInfo.second;
2868 LLT DstTy =
MRI.getType(Dst);
2872 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2875 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2876 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2877 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2881 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2884 if (NewShiftTy == DstTy)
2887 Builder.buildTrunc(Dst, NewShift);
2894 return MO.isReg() &&
2895 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2901 return !MO.isReg() ||
2902 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2907 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2909 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2913 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2914 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2919 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2920 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2926 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2927 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2928 "Expected an insert/extract element op");
2929 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2934 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2942 unsigned &OpIdx)
const {
2947 OpIdx = Cst->isZero() ? 3 : 2;
2992 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
3019 return MO.isReg() && MO.getReg().isPhysical();
3029 return I1->isIdenticalTo(*I2);
3037 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
3044 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
3055 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
3056 MaybeCst->getSExtValue() ==
C;
3063 std::optional<FPValueAndVReg> MaybeCst;
3067 return MaybeCst->Value.isExactlyValue(
C);
3071 unsigned OpIdx)
const {
3072 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3074 Register Replacement =
MI.getOperand(OpIdx).getReg();
3077 MI.eraseFromParent();
3082 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3086 MI.eraseFromParent();
3090 unsigned ConstIdx)
const {
3091 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3092 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3104 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3105 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3106 "This is not a funnel shift operation");
3108 Register ConstReg =
MI.getOperand(3).getReg();
3109 LLT ConstTy =
MRI.getType(ConstReg);
3110 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3113 assert((VRegAndVal) &&
"Value is not a constant");
3116 APInt NewConst = VRegAndVal->Value.
urem(
3121 MI.getOpcode(), {MI.getOperand(0)},
3122 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3124 MI.eraseFromParent();
3128 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3142 unsigned OpIdx)
const {
3144 return MO.
isReg() &&
3155 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3157 MI.eraseFromParent();
3162 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3164 MI.eraseFromParent();
3168 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3170 MI.eraseFromParent();
3175 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3177 MI.eraseFromParent();
3181 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3183 MI.eraseFromParent();
3187 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3190 Register &NewLHS = std::get<0>(MatchInfo);
3191 Register &NewRHS = std::get<1>(MatchInfo);
3199 NewLHS = MaybeNewLHS;
3203 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3208 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3211 LLT DstTy =
MRI.getType(DstReg);
3220 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3221 TargetOpcode::G_INSERT_VECTOR_ELT)
3227 MatchInfo.
resize(NumElts);
3231 if (IntImm >= NumElts || IntImm < 0)
3233 if (!MatchInfo[IntImm])
3234 MatchInfo[IntImm] = TmpReg;
3238 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3240 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3249 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3256 auto GetUndef = [&]() {
3259 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3267 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3268 MI.eraseFromParent();
3272 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3274 std::tie(SubLHS, SubRHS) = MatchInfo;
3275 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3276 MI.eraseFromParent();
3289 unsigned InnerOpc = InnerDef->
getOpcode();
3290 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3314 if (!TryMatch(InnerLHS, InnerRHS) &&
3315 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3319 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3320 : TargetOpcode::G_ADD;
3323 MatchInfo = [=](MachineIRBuilder &
Builder) {
3324 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3325 auto NewNot =
Builder.buildNot(Ty, NewInner);
3326 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3338 unsigned RootOpc =
MI.getOpcode();
3340 LLT Ty =
MRI.getType(Dst);
3345 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3346 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3357 unsigned LogicOpcode =
MI.getOpcode();
3358 assert(LogicOpcode == TargetOpcode::G_AND ||
3359 LogicOpcode == TargetOpcode::G_OR ||
3360 LogicOpcode == TargetOpcode::G_XOR);
3367 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3373 if (!LeftHandInst || !RightHandInst)
3375 unsigned HandOpcode = LeftHandInst->
getOpcode();
3376 if (HandOpcode != RightHandInst->
getOpcode())
3390 if (!XTy.
isValid() || XTy != YTy)
3395 switch (HandOpcode) {
3398 case TargetOpcode::G_ANYEXT:
3399 case TargetOpcode::G_SEXT:
3400 case TargetOpcode::G_ZEXT: {
3404 case TargetOpcode::G_TRUNC: {
3409 LLT DstTy =
MRI.getType(Dst);
3418 case TargetOpcode::G_AND:
3419 case TargetOpcode::G_ASHR:
3420 case TargetOpcode::G_LSHR:
3421 case TargetOpcode::G_SHL: {
3426 ExtraHandOpSrcReg = ZOp.
getReg();
3437 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3448 if (ExtraHandOpSrcReg.
isValid())
3460 "Expected at least one instr to build?");
3462 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3463 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3465 for (
auto &OperandFn : InstrToBuild.OperandFns)
3468 MI.eraseFromParent();
3472 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3473 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3474 int64_t ShlCst, AshrCst;
3480 if (ShlCst != AshrCst)
3483 {TargetOpcode::G_SEXT_INREG,
3486 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3488 MatchInfo = std::make_tuple(Src, ShlCst);
3493 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3494 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3497 std::tie(Src, ShiftAmt) = MatchInfo;
3498 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3499 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3500 MI.eraseFromParent();
3507 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3510 LLT Ty =
MRI.getType(Dst);
3522 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3525 auto Zero =
B.buildConstant(Ty, 0);
3548 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3572 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3579 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3596 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3614 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3621 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3632 unsigned ExtBits =
MI.getOperand(2).getImm();
3633 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3634 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3638 int64_t Cst,
bool IsVector,
bool IsFP) {
3640 return (ScalarSizeBits == 1 && Cst == -1) ||
3662 unsigned BuildUseCount = BV.getNumSources();
3663 if (BuildUseCount % 2 != 0)
3666 unsigned NumUnmerge = BuildUseCount / 2;
3672 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3675 UnmergeSrc = Unmerge->getSourceReg();
3677 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3678 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3685 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3690 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3691 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3694 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3697 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3702 if (Unmerge->getNumDefs() != NumUnmerge)
3706 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3709 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3720 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3721 B.setInstrAndDebugLoc(
MI);
3723 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3724 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3726 MI.eraseFromParent();
3748 unsigned NumOperands =
BuildMI->getNumSources();
3758 for (
I = 0;
I < NumOperands; ++
I) {
3770 UnmergeMI != UnmergeSrcMI)
3781 for (;
I < NumOperands; ++
I) {
3788 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3795 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3796 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3804 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3807 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3819 LLT DstTy =
MRI.getType(DstReg);
3820 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3825 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3830 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3834 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3837 Builder.buildTrunc(DstReg, MidReg);
3838 MI.eraseFromParent();
3843 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3844 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3845 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3853 if (!
MRI.hasOneNonDBGUse(XorSrc))
3863 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3865 if (!
MRI.hasOneNonDBGUse(Reg))
3870 switch (Def->getOpcode()) {
3875 case TargetOpcode::G_ICMP:
3881 case TargetOpcode::G_FCMP:
3887 case TargetOpcode::G_AND:
3888 case TargetOpcode::G_OR:
3894 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3895 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3903 if (Ty.isVector()) {
3907 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), SplatCst,
true, IsFP))
3921 for (
Register Reg : RegsToNegate) {
3926 switch (Def->getOpcode()) {
3929 case TargetOpcode::G_ICMP:
3930 case TargetOpcode::G_FCMP: {
3937 case TargetOpcode::G_AND:
3938 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3940 case TargetOpcode::G_OR:
3941 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3948 MI.eraseFromParent();
3952 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3954 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3958 Register SharedReg =
MI.getOperand(2).getReg();
3972 if (!
MRI.hasOneNonDBGUse(AndReg))
3979 return Y == SharedReg;
3983 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3986 std::tie(
X,
Y) = MatchInfo;
3989 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3990 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3991 MI.getOperand(2).setReg(
Y);
3997 Register DstReg = PtrAdd.getReg(0);
3998 LLT Ty =
MRI.getType(DstReg);
4001 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
4004 if (Ty.isPointer()) {
4006 return ConstVal && *ConstVal == 0;
4009 assert(Ty.isVector() &&
"Expecting a vector type");
4018 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
4019 PtrAdd.eraseFromParent();
4026 Register Pow2Src1 =
MI.getOperand(2).getReg();
4027 LLT Ty =
MRI.getType(DstReg);
4030 auto NegOne =
Builder.buildConstant(Ty, -1);
4031 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
4033 MI.eraseFromParent();
4037 unsigned &SelectOpNo)
const {
4049 !
MRI.hasOneNonDBGUse(LHS)) {
4050 OtherOperandReg = LHS;
4054 !
MRI.hasOneNonDBGUse(RHS))
4072 unsigned BinOpcode =
MI.getOpcode();
4077 bool CanFoldNonConst =
4078 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4083 if (CanFoldNonConst)
4108 LLT Ty =
MRI.getType(Dst);
4109 unsigned BinOpcode =
MI.getOpcode();
4116 if (SelectOperand == 1) {
4120 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4122 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4124 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4126 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4129 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4130 MI.eraseFromParent();
4133std::optional<SmallVector<Register, 8>>
4134CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4135 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4164 const unsigned MaxIter =
4166 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4175 return std::nullopt;
4191 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4192 return std::nullopt;
4204static std::optional<std::pair<GZExtLoad *, int64_t>>
4208 "Expected Reg to only have one non-debug use?");
4217 if (Shift % MemSizeInBits != 0)
4218 return std::nullopt;
4223 return std::nullopt;
4225 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
4226 return std::nullopt;
4228 return std::make_pair(
Load, Shift / MemSizeInBits);
4231std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4232CombinerHelper::findLoadOffsetsForLoadOrCombine(
4235 const unsigned MemSizeInBits)
const {
4238 SmallSetVector<const MachineInstr *, 8> Loads;
4244 GZExtLoad *LowestIdxLoad =
nullptr;
4247 SmallSet<int64_t, 8> SeenIdx;
4251 MachineBasicBlock *
MBB =
nullptr;
4252 const MachineMemOperand *MMO =
nullptr;
4255 GZExtLoad *EarliestLoad =
nullptr;
4258 GZExtLoad *LatestLoad =
nullptr;
4267 for (
auto Reg : RegsToVisit) {
4272 return std::nullopt;
4275 std::tie(
Load, DstPos) = *LoadAndPos;
4279 MachineBasicBlock *LoadMBB =
Load->getParent();
4283 return std::nullopt;
4286 auto &LoadMMO =
Load->getMMO();
4290 return std::nullopt;
4297 LoadPtr =
Load->getOperand(1).getReg();
4302 if (!SeenIdx.
insert(Idx).second)
4303 return std::nullopt;
4310 if (BasePtr != LoadPtr)
4311 return std::nullopt;
4313 if (Idx < LowestIdx) {
4315 LowestIdxLoad =
Load;
4322 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4323 return std::nullopt;
4332 EarliestLoad =
Load;
4340 "Expected to find a load for each register?");
4341 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4342 LatestLoad &&
"Expected at least two loads?");
4351 const unsigned MaxIter = 20;
4357 if (
MI.isLoadFoldBarrier())
4358 return std::nullopt;
4359 if (Iter++ == MaxIter)
4360 return std::nullopt;
4363 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4369 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4382 LLT Ty =
MRI.getType(Dst);
4388 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4389 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4393 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4400 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4401 if (NarrowMemSizeInBits % 8 != 0)
4414 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4415 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4418 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4425 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4428 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4440 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4441 const unsigned ZeroByteOffset =
4445 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4446 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4447 ZeroOffsetIdx->second != LowestIdx)
4457 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4471 MIB.setInstrAndDebugLoc(*LatestLoad);
4472 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4473 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4475 MIB.buildBSwap(Dst, LoadDst);
4487 if (
MRI.getType(DstReg).isVector())
4491 if (!
MRI.hasOneNonDBGUse(DstReg))
4493 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4495 case TargetOpcode::G_ANYEXT:
4497 case TargetOpcode::G_ZEXT:
4498 case TargetOpcode::G_SEXT:
4505 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4512 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4514 switch (
DefMI->getOpcode()) {
4515 case TargetOpcode::G_LOAD:
4516 case TargetOpcode::G_TRUNC:
4517 case TargetOpcode::G_SEXT:
4518 case TargetOpcode::G_ZEXT:
4519 case TargetOpcode::G_ANYEXT:
4520 case TargetOpcode::G_CONSTANT:
4524 if (InSrcs.
size() > 2)
4538 LLT ExtTy =
MRI.getType(DstReg);
4545 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4546 auto SrcReg =
PHI.getIncomingValue(
I);
4550 if (!SrcMIs.
insert(SrcMI))
4556 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4557 InsertPt =
MBB->getFirstNonPHI();
4562 OldToNewSrcMap[SrcMI] = NewExt;
4567 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4568 NewPhi.addDef(DstReg);
4571 NewPhi.addMBB(MO.getMBB());
4574 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4575 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4583 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4587 LLT SrcTy =
MRI.getType(SrcVec);
4588 if (SrcTy.isScalableVector())
4592 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4595 unsigned VecIdx = Cst->Value.getZExtValue();
4607 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4608 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4612 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4624 LLT ScalarTy =
MRI.getType(Reg);
4626 LLT DstTy =
MRI.getType(DstReg);
4628 if (ScalarTy != DstTy) {
4630 Builder.buildTrunc(DstReg, Reg);
4631 MI.eraseFromParent();
4639 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4640 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4658 LLT DstTy =
MRI.getType(DstReg);
4663 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4668 unsigned Idx = Cst->getZExtValue();
4671 ExtractedElts.
set(Idx);
4672 SrcDstPairs.emplace_back(
4673 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4676 return ExtractedElts.
all();
4681 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4682 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4683 for (
auto &Pair : SrcDstPairs) {
4684 auto *ExtMI = Pair.second;
4686 ExtMI->eraseFromParent();
4688 MI.eraseFromParent();
4695 MI.eraseFromParent();
4705 bool AllowScalarConstants,
4707 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4710 LLT Ty =
MRI.getType(Dst);
4711 unsigned BitWidth = Ty.getScalarSizeInBits();
4713 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4714 unsigned FshOpc = 0;
4725 int64_t CstShlAmt = 0, CstLShrAmt;
4728 CstShlAmt + CstLShrAmt ==
BitWidth) {
4729 FshOpc = TargetOpcode::G_FSHR;
4735 FshOpc = TargetOpcode::G_FSHL;
4740 FshOpc = TargetOpcode::G_FSHR;
4745 LLT AmtTy =
MRI.getType(Amt);
4747 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4751 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4758 unsigned Opc =
MI.getOpcode();
4759 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4764 unsigned RotateOpc =
4765 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4770 unsigned Opc =
MI.getOpcode();
4771 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4772 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4774 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4775 : TargetOpcode::G_ROTR));
4776 MI.removeOperand(2);
4782 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4783 MI.getOpcode() == TargetOpcode::G_ROTR);
4785 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4787 bool OutOfRange =
false;
4788 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4790 OutOfRange |= CI->getValue().uge(Bitsize);
4797 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4798 MI.getOpcode() == TargetOpcode::G_ROTR);
4800 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4802 LLT AmtTy =
MRI.getType(Amt);
4803 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4804 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4806 MI.getOperand(2).setReg(Amt);
4811 int64_t &MatchInfo)
const {
4812 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4823 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4824 if (KnownRHS.isUnknown())
4827 std::optional<bool> KnownVal;
4828 if (KnownRHS.isZero()) {
4838 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4848 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4857 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4873 LLT DstTy =
MRI.getType(Dst);
4881 auto KnownLHS =
VT->getKnownBits(LHS);
4882 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4885 LLT LHSTy =
MRI.getType(LHS);
4888 unsigned Op = TargetOpcode::COPY;
4889 if (DstSize != LHSSize)
4890 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4901 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4905 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4911 int64_t AndMaskBits;
4919 if (AndMaskBits & OrMaskBits)
4925 if (
MI.getOperand(1).getReg() == AndMaskReg)
4926 MI.getOperand(2).setReg(AndMaskReg);
4927 MI.getOperand(1).setReg(Src);
4937 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4940 LLT Ty =
MRI.getType(Src);
4942 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4944 int64_t Width =
MI.getOperand(2).getImm();
4952 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4956 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4957 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4958 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4968 LLT Ty =
MRI.getType(Dst);
4972 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4975 int64_t AndImm, LSBImm;
4977 const unsigned Size = Ty.getScalarSizeInBits();
4984 auto MaybeMask =
static_cast<uint64_t
>(AndImm);
4985 if (MaybeMask & (MaybeMask + 1))
4989 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4994 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4995 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4996 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
5004 const unsigned Opcode =
MI.getOpcode();
5005 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
5007 const Register Dst =
MI.getOperand(0).getReg();
5009 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
5010 ? TargetOpcode::G_SBFX
5011 : TargetOpcode::G_UBFX;
5014 LLT Ty =
MRI.getType(Dst);
5016 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
5022 const unsigned Size = Ty.getScalarSizeInBits();
5032 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
5036 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
5040 const int64_t Pos = ShrAmt - ShlAmt;
5041 const int64_t Width =
Size - ShrAmt;
5044 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5045 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5046 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
5054 const unsigned Opcode =
MI.getOpcode();
5055 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
5057 const Register Dst =
MI.getOperand(0).getReg();
5058 LLT Ty =
MRI.getType(Dst);
5060 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
5073 const unsigned Size = Ty.getScalarSizeInBits();
5074 if (ShrAmt < 0 || ShrAmt >=
Size)
5078 if (0 == (SMask >> ShrAmt)) {
5080 B.buildConstant(Dst, 0);
5093 const int64_t Pos = ShrAmt;
5098 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5102 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5103 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5104 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5109bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5113 Register Src1Reg = PtrAdd.getBaseReg();
5118 Register Src2Reg = PtrAdd.getOffsetReg();
5120 if (
MRI.hasOneNonDBGUse(Src1Reg))
5130 const APInt &C1APIntVal = *C1;
5131 const APInt &C2APIntVal = *C2;
5132 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5134 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5137 MachineInstr *ConvUseMI = &
UseMI;
5138 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5139 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5140 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5142 if (!
MRI.hasOneNonDBGUse(DefReg))
5144 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5153 TargetLoweringBase::AddrMode AM;
5156 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5158 PtrAdd.getMF()->getFunction().getContext());
5159 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5160 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5166 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5178 Register Src1Reg =
MI.getOperand(1).getReg();
5179 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5191 unsigned PtrAddFlags =
MI.getFlags();
5192 unsigned AddFlags = RHS->getFlags();
5205 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5208 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5210 MI.getOperand(1).setReg(NewBase.getReg(0));
5211 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5215 return !reassociationCanBreakAddressingModePattern(
MI);
5225 std::optional<ValueAndVReg> LHSCstOff;
5235 unsigned PtrAddFlags =
MI.getFlags();
5236 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5238 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5240 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5254 LHSPtrAdd->moveBefore(&
MI);
5257 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5259 MI.getOperand(2).setReg(NewCst.getReg(0));
5262 Observer.changingInstr(*LHSPtrAdd);
5263 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5264 LHSPtrAdd->setFlags(Flags);
5267 return !reassociationCanBreakAddressingModePattern(
MI);
5278 Register Src2Reg =
MI.getOperand(2).getReg();
5279 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5280 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5293 unsigned PtrAddFlags =
MI.getFlags();
5294 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5307 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5309 MI.getOperand(1).setReg(LHSSrc1);
5310 MI.getOperand(2).setReg(NewCst.getReg(0));
5314 return !reassociationCanBreakAddressingModePattern(
MI);
5354 LLT OpRHSTy =
MRI.getType(OpRHS);
5371 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5372 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5380 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5381 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5394 unsigned Opc =
MI.getOpcode();
5407 APInt &MatchInfo)
const {
5408 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5412 MatchInfo = *MaybeCst;
5423 MI.getOperand(1).getReg(),
MRI);
5428 if (Csts.size() == 1)
5429 B.buildConstant(Dst, Csts[0]);
5431 B.buildBuildVectorConstant(Dst, Csts);
5437 APInt &MatchInfo)
const {
5443 MatchInfo = *MaybeCst;
5455 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5461 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5462 MI.getOpcode() == TargetOpcode::G_FMAD);
5463 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5480 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5503 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5507 LLT WideTy =
MRI.getType(Dst);
5511 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5527 case TargetOpcode::G_ADD:
5528 case TargetOpcode::G_SUB:
5529 case TargetOpcode::G_MUL:
5530 case TargetOpcode::G_AND:
5531 case TargetOpcode::G_OR:
5532 case TargetOpcode::G_XOR:
5540 auto Mask = Cst->Value;
5545 unsigned NarrowWidth = Mask.countr_one();
5551 auto &MF = *
MI.getMF();
5554 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5555 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5563 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5564 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5566 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5567 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5569 MI.getOperand(1).setReg(Ext.getReg(0));
5577 unsigned Opc =
MI.getOpcode();
5578 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5585 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5586 : TargetOpcode::G_SADDO;
5587 MI.setDesc(
Builder.getTII().get(NewOpc));
5588 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5597 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5598 MI.getOpcode() == TargetOpcode::G_SMULO);
5607 B.buildConstant(Dst, 0);
5608 B.buildConstant(Carry, 0);
5617 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5618 MI.getOpcode() == TargetOpcode::G_SADDE ||
5619 MI.getOpcode() == TargetOpcode::G_USUBE ||
5620 MI.getOpcode() == TargetOpcode::G_SSUBE);
5625 switch (
MI.getOpcode()) {
5626 case TargetOpcode::G_UADDE:
5627 NewOpcode = TargetOpcode::G_UADDO;
5629 case TargetOpcode::G_SADDE:
5630 NewOpcode = TargetOpcode::G_SADDO;
5632 case TargetOpcode::G_USUBE:
5633 NewOpcode = TargetOpcode::G_USUBO;
5635 case TargetOpcode::G_SSUBE:
5636 NewOpcode = TargetOpcode::G_SSUBO;
5640 MI.setDesc(
B.getTII().get(NewOpcode));
5641 MI.removeOperand(4);
5649 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5682 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5683 B.buildSub(Dst, Zero, ReplaceReg);
5692 unsigned Opcode =
MI.getOpcode();
5693 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5695 Register Dst = UDivorRem.getReg(0);
5696 Register LHS = UDivorRem.getReg(1);
5697 Register RHS = UDivorRem.getReg(2);
5698 LLT Ty =
MRI.getType(Dst);
5706 bool UseSRL =
false;
5711 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5713 if (IsSplat && !Factors.
empty()) {
5720 APInt Divisor = CI->getValue();
5729 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5730 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5740 if (Ty.isVector()) {
5741 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5742 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5745 Factor = Factors[0];
5753 return MIB.buildMul(Ty, Res, Factor);
5756 unsigned KnownLeadingZeros =
5757 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5759 bool UseNPQ =
false;
5761 auto BuildUDIVPattern = [&](
const Constant *
C) {
5763 const APInt &Divisor = CI->getValue();
5765 bool SelNPQ =
false;
5767 unsigned PreShift = 0, PostShift = 0;
5772 if (!Divisor.
isOne()) {
5778 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5780 Magic = std::move(magics.
Magic);
5783 "We shouldn't generate an undefined shift!");
5785 "We shouldn't generate an undefined shift!");
5789 SelNPQ = magics.
IsAdd;
5793 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5794 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5796 MIB.buildConstant(ScalarTy,
5801 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5809 assert(Matched &&
"Expected unary predicate match to succeed");
5811 Register PreShift, PostShift, MagicFactor, NPQFactor;
5814 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5815 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5816 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5817 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5820 "Non-build_vector operation should have been a scalar");
5821 PreShift = PreShifts[0];
5822 MagicFactor = MagicFactors[0];
5823 PostShift = PostShifts[0];
5827 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5830 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5833 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5838 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5840 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5842 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5845 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5846 auto One = MIB.buildConstant(Ty, 1);
5847 auto IsOne = MIB.buildICmp(
5851 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5853 if (Opcode == TargetOpcode::G_UREM) {
5854 auto Prod = MIB.buildMul(Ty, ret, RHS);
5855 return MIB.buildSub(Ty, LHS, Prod);
5861 unsigned Opcode =
MI.getOpcode();
5862 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5865 LLT DstTy =
MRI.getType(Dst);
5867 auto &MF = *
MI.getMF();
5868 AttributeList Attr = MF.getFunction().getAttributes();
5877 if (MF.getFunction().hasMinSize())
5880 if (Opcode == TargetOpcode::G_UDIV &&
5883 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5898 {TargetOpcode::G_ICMP,
5902 if (Opcode == TargetOpcode::G_UREM &&
5908 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5917 unsigned Opcode =
MI.getOpcode();
5918 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5921 LLT DstTy =
MRI.getType(Dst);
5925 auto &MF = *
MI.getMF();
5926 AttributeList Attr = MF.getFunction().getAttributes();
5935 if (MF.getFunction().hasMinSize())
5939 if (Opcode == TargetOpcode::G_SDIV &&
5942 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5954 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5957 if (Opcode == TargetOpcode::G_SREM &&
5963 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5972 unsigned Opcode =
MI.getOpcode();
5973 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5974 Opcode == TargetOpcode::G_SREM);
5976 Register Dst = SDivorRem.getReg(0);
5977 Register LHS = SDivorRem.getReg(1);
5978 Register RHS = SDivorRem.getReg(2);
5979 LLT Ty =
MRI.getType(Dst);
5986 bool UseSRA =
false;
5992 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5994 if (IsSplat && !ExactFactors.
empty()) {
5996 ExactFactors.
push_back(ExactFactors[0]);
6001 APInt Divisor = CI->getValue();
6011 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
6012 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
6020 assert(Matched &&
"Expected unary predicate match to succeed");
6023 if (Ty.isVector()) {
6024 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
6025 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
6027 Shift = ExactShifts[0];
6028 Factor = ExactFactors[0];
6036 return MIB.buildMul(Ty, Res, Factor);
6041 auto BuildSDIVPattern = [&](
const Constant *
C) {
6043 const APInt &Divisor = CI->getValue();
6047 int NumeratorFactor = 0;
6058 NumeratorFactor = 1;
6061 NumeratorFactor = -1;
6064 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
6065 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
6067 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
6068 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
6076 assert(Matched &&
"Expected unary predicate match to succeed");
6078 Register MagicFactor, Factor, Shift, ShiftMask;
6081 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
6082 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
6083 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
6084 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
6087 "Non-build_vector operation should have been a scalar");
6088 MagicFactor = MagicFactors[0];
6089 Factor = Factors[0];
6091 ShiftMask = ShiftMasks[0];
6095 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6098 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6099 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6102 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6105 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6106 auto T = MIB.buildLShr(Ty, Q, SignShift);
6107 T = MIB.buildAnd(Ty,
T, ShiftMask);
6108 auto ret = MIB.buildAdd(Ty, Q,
T);
6110 if (Opcode == TargetOpcode::G_SREM) {
6111 auto Prod = MIB.buildMul(Ty, ret, RHS);
6112 return MIB.buildSub(Ty, LHS, Prod);
6118 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6119 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6120 "Expected SDIV or UDIV");
6123 auto MatchPow2 = [&](
const Constant *
C) {
6125 return CI && (CI->getValue().isPowerOf2() ||
6126 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6132 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6137 LLT Ty =
MRI.getType(Dst);
6157 unsigned BitWidth = Ty.getScalarSizeInBits();
6158 auto Zero =
Builder.buildConstant(Ty, 0);
6161 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6162 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6164 auto Sign =
Builder.buildAShr(
6168 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6174 auto One =
Builder.buildConstant(Ty, 1);
6175 auto MinusOne =
Builder.buildConstant(Ty, -1);
6179 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6180 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6184 auto Neg =
Builder.buildNeg(Ty, AShr);
6186 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6187 MI.eraseFromParent();
6191 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6196 LLT Ty =
MRI.getType(Dst);
6199 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6200 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6201 MI.eraseFromParent();
6205 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6210 LLT Ty =
MRI.getType(Dst);
6229 unsigned BitWidth = Ty.getScalarSizeInBits();
6230 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6231 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6233 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6234 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6235 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6238 MI.eraseFromParent();
6242 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6245 LLT Ty =
MRI.getType(Dst);
6246 LLT RHSTy =
MRI.getType(RHS);
6248 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6250 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6265 LLT Ty =
MRI.getType(Dst);
6271 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6272 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6273 Builder.buildLShr(Dst, LHS, Trunc);
6274 MI.eraseFromParent();
6281 LLT DstTy =
MRI.getType(Dst);
6282 LLT SrcTy =
MRI.getType(Src);
6284 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6285 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6288 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6306 Builder.buildTruncSSatS(Dst, MatchInfo);
6307 MI.eraseFromParent();
6314 LLT DstTy =
MRI.getType(Dst);
6315 LLT SrcTy =
MRI.getType(Src);
6317 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6318 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6321 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6339 Builder.buildTruncSSatU(Dst, MatchInfo);
6340 MI.eraseFromParent();
6347 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6348 LLT SrcTy =
MRI.getType(Val);
6350 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6351 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6354 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6363 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6372 unsigned Opc =
MI.getOpcode();
6373 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6374 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6375 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6387 Opc = TargetOpcode::G_FSUB;
6392 Opc = TargetOpcode::G_FADD;
6398 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6399 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6408 MI.setDesc(
B.getTII().get(
Opc));
6409 MI.getOperand(1).setReg(
X);
6410 MI.getOperand(2).setReg(
Y);
6418 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6421 MatchInfo =
MI.getOperand(2).getReg();
6422 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6424 const auto LHSCst = Ty.isVector()
6431 if (LHSCst->Value.isNegZero())
6435 if (LHSCst->Value.isPosZero())
6445 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6452 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6466 bool &AllowFusionGlobally,
6468 bool CanReassociate)
const {
6470 auto *MF =
MI.getMF();
6471 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6473 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6481 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6484 if (!HasFMAD && !HasFMA)
6492 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6499 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6501 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6513 unsigned PreferredFusedOpcode =
6514 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6527 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6529 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6530 {LHS.MI->getOperand(1).getReg(),
6531 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6540 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6542 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6543 {RHS.MI->getOperand(1).getReg(),
6544 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6556 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6558 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6562 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6571 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6573 unsigned PreferredFusedOpcode =
6574 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6588 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6590 unsigned Flags =
MI.getFlags() & FpExtSrc->
getFlags();
6594 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6595 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6604 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6606 unsigned Flags =
MI.getFlags() & FpExtSrc->
getFlags();
6610 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6611 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg}, Flags);
6622 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6624 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6636 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6638 unsigned PreferredFusedOpcode =
6639 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6652 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6655 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6656 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6661 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6664 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6665 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6674 Register X = FMA->getOperand(1).getReg();
6675 Register Y = FMA->getOperand(2).getReg();
6678 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6679 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6682 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6683 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6684 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6685 {
X,
Y, InnerFMA}, OuterFlags);
6696 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6698 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6705 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6706 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6716 unsigned PreferredFusedOpcode =
6717 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6731 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6732 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6733 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6734 {FpExtU, FpExtV, Z}, InnerFlags)
6736 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6737 {
X,
Y, InnerFMA}, OuterFlags);
6743 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6747 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6749 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6750 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6754 LHS.MI->getOperand(1).getReg(),
6755 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6766 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6771 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6773 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6774 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6778 X =
B.buildFPExt(DstType,
X).getReg(0);
6779 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6782 InnerFlags, OuterFlags,
B);
6791 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6795 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6797 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6798 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6802 RHS.MI->getOperand(1).getReg(),
6803 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6814 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6819 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6821 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6822 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6826 X =
B.buildFPExt(DstType,
X).getReg(0);
6827 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6830 InnerFlags, OuterFlags,
B);
6842 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6844 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6856 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6860 int FirstMulHasFewerUses =
true;
6864 FirstMulHasFewerUses =
false;
6866 unsigned PreferredFusedOpcode =
6867 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6870 if (FirstMulHasFewerUses &&
6873 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6875 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6876 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6877 {LHS.MI->getOperand(1).getReg(),
6878 LHS.MI->getOperand(2).getReg(), NegZ},
6886 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6889 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6890 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6891 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6902 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6904 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6910 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6912 unsigned PreferredFusedOpcode =
6913 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6921 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6925 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6926 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6937 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6939 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6953 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6955 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6961 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6963 unsigned PreferredFusedOpcode =
6964 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6971 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6977 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6978 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6979 {FpExtX, FpExtY, NegZ}, Flags);
6988 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6992 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6995 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6996 {NegY, FpExtZ, LHSReg}, Flags);
7007 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
7009 bool AllowFusionGlobally, HasFMAD,
Aggressive;
7013 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
7014 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
7018 unsigned PreferredFusedOpcode =
7019 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
7023 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
7024 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
7025 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
7036 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
7038 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
7040 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
7043 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
7053 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
7055 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
7067 unsigned &IdxToPropagate)
const {
7069 switch (
MI.getOpcode()) {
7072 case TargetOpcode::G_FMINNUM:
7073 case TargetOpcode::G_FMAXNUM:
7074 PropagateNaN =
false;
7076 case TargetOpcode::G_FMINIMUM:
7077 case TargetOpcode::G_FMAXIMUM:
7078 PropagateNaN =
true;
7082 auto MatchNaN = [&](
unsigned Idx) {
7083 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
7087 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
7091 return MatchNaN(1) || MatchNaN(2);
7099 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
7109 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
7126 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
7127 if (&U == &
MI || U.getParent() !=
MI.getParent())
7129 if (U.getOpcode() == TargetOpcode::G_FDIV &&
7130 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
7131 !IsOne(U.getOperand(1).getReg())) {
7144 return MatchInfo.
size() >= MinUses;
7152 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7153 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7154 MatchInfo[0]->getOperand(2).getReg(),
7155 MatchInfo[0]->getFlags());
7160 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7161 Div->getOperand(0).getReg(),
MI->getFlags());
7162 MI->eraseFromParent();
7167 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7177 Reg == MaybeSameReg;
7179 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7200 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7209 return MRI.getType(MatchInfo) == DstVecTy;
7212 std::optional<ValueAndVReg> ShiftAmount;
7221 return MRI.getType(MatchInfo) == DstVecTy;
7236 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7243 std::optional<ValueAndVReg> ShiftAmt;
7249 LLT MatchTy =
MRI.getType(MatchInfo);
7250 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7251 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7254unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7256 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7257 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7258 "Expected a NaN behaviour?");
7268 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7269 return TargetOpcode::G_FMAXNUM;
7270 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7271 return TargetOpcode::G_FMAXIMUM;
7272 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7273 return TargetOpcode::G_FMAXNUM;
7274 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7275 return TargetOpcode::G_FMAXIMUM;
7281 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7282 return TargetOpcode::G_FMINNUM;
7283 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7284 return TargetOpcode::G_FMINIMUM;
7285 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7286 return TargetOpcode::G_FMINNUM;
7287 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7289 return TargetOpcode::G_FMINIMUM;
7293CombinerHelper::SelectPatternNaNBehaviour
7295 bool IsOrderedComparison)
const {
7296 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7297 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7299 if (!LHSSafe && !RHSSafe)
7300 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7301 if (LHSSafe && RHSSafe)
7302 return SelectPatternNaNBehaviour::RETURNS_ANY;
7305 if (IsOrderedComparison)
7306 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7307 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7310 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7311 : SelectPatternNaNBehaviour::RETURNS_NAN;
7320 LLT DstTy =
MRI.getType(Dst);
7333 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7335 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7337 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7340 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7341 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7342 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7343 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7345 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7348 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7353 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7358 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7360 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7364 MatchInfo = [=](MachineIRBuilder &
B) {
7365 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7373 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7380 Register TrueVal =
MI.getOperand(2).getReg();
7381 Register FalseVal =
MI.getOperand(3).getReg();
7382 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7387 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7400 if (MatchedSub &&
X != OpLHS)
7408 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7411 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7412 B.buildICmp(Pred, Dst,
Y, Zero);
7419static std::optional<unsigned>
7421 std::optional<int64_t> &Result) {
7422 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7423 Opcode == TargetOpcode::G_ASHR) &&
7424 "Expect G_SHL, G_LSHR or G_ASHR.");
7425 auto SignificantBits = 0;
7427 case TargetOpcode::G_SHL:
7431 case TargetOpcode::G_LSHR:
7435 case TargetOpcode::G_ASHR:
7444 Result = std::nullopt;
7455 Register ShiftVal =
MI.getOperand(1).getReg();
7456 Register ShiftReg =
MI.getOperand(2).getReg();
7457 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7458 auto IsShiftTooBig = [&](
const Constant *
C) {
7463 MatchInfo = std::nullopt;
7467 MI.getOpcode(), MatchInfo);
7468 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7474 unsigned LHSOpndIdx = 1;
7475 unsigned RHSOpndIdx = 2;
7476 switch (
MI.getOpcode()) {
7477 case TargetOpcode::G_UADDO:
7478 case TargetOpcode::G_SADDO:
7479 case TargetOpcode::G_UMULO:
7480 case TargetOpcode::G_SMULO:
7487 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7488 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7498 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7502 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7509 std::optional<FPValueAndVReg> ValAndVReg;
7517 unsigned LHSOpndIdx = 1;
7518 unsigned RHSOpndIdx = 2;
7519 switch (
MI.getOpcode()) {
7520 case TargetOpcode::G_UADDO:
7521 case TargetOpcode::G_SADDO:
7522 case TargetOpcode::G_UMULO:
7523 case TargetOpcode::G_SMULO:
7530 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7531 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7532 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7533 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7537bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7539 if (SrcTy.isFixedVector())
7541 if (SrcTy.isScalar()) {
7545 return IConstant && IConstant->Value == 1;
7550bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7551 LLT SrcTy =
MRI.getType(Src);
7553 return isConstantSplatVector(Src, 0, AllowUndefs);
7558 return IConstant && IConstant->Value == 0;
7565bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7566 bool AllowUndefs)
const {
7572 for (
unsigned I = 0;
I < NumSources; ++
I) {
7573 GImplicitDef *ImplicitDef =
7575 if (ImplicitDef && AllowUndefs)
7577 if (ImplicitDef && !AllowUndefs)
7579 std::optional<ValueAndVReg> IConstant =
7581 if (IConstant && IConstant->Value == SplatValue)
7591CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7594 return IConstant->Value;
7598 return std::nullopt;
7601 std::optional<APInt>
Value = std::nullopt;
7602 for (
unsigned I = 0;
I < NumSources; ++
I) {
7603 std::optional<ValueAndVReg> IConstant =
7606 return std::nullopt;
7608 Value = IConstant->Value;
7609 else if (*
Value != IConstant->Value)
7610 return std::nullopt;
7616bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7626 for (
unsigned I = 0;
I < NumSources; ++
I) {
7627 std::optional<ValueAndVReg> IConstant =
7636bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7643 LLT CondTy =
MRI.getType(
Select->getCondReg());
7644 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7654 std::optional<ValueAndVReg> TrueOpt =
7656 std::optional<ValueAndVReg> FalseOpt =
7659 if (!TrueOpt || !FalseOpt)
7662 APInt TrueValue = TrueOpt->Value;
7663 APInt FalseValue = FalseOpt->Value;
7667 MatchInfo = [=](MachineIRBuilder &
B) {
7668 B.setInstrAndDebugLoc(*
Select);
7669 B.buildZExtOrTrunc(Dest,
Cond);
7676 MatchInfo = [=](MachineIRBuilder &
B) {
7677 B.setInstrAndDebugLoc(*
Select);
7678 B.buildSExtOrTrunc(Dest,
Cond);
7685 MatchInfo = [=](MachineIRBuilder &
B) {
7686 B.setInstrAndDebugLoc(*
Select);
7687 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7688 B.buildNot(Inner,
Cond);
7689 B.buildZExtOrTrunc(Dest, Inner);
7696 MatchInfo = [=](MachineIRBuilder &
B) {
7697 B.setInstrAndDebugLoc(*
Select);
7698 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7699 B.buildNot(Inner,
Cond);
7700 B.buildSExtOrTrunc(Dest, Inner);
7706 if (TrueValue - 1 == FalseValue) {
7707 MatchInfo = [=](MachineIRBuilder &
B) {
7708 B.setInstrAndDebugLoc(*
Select);
7709 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7710 B.buildZExtOrTrunc(Inner,
Cond);
7711 B.buildAdd(Dest, Inner, False);
7717 if (TrueValue + 1 == FalseValue) {
7718 MatchInfo = [=](MachineIRBuilder &
B) {
7719 B.setInstrAndDebugLoc(*
Select);
7720 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7721 B.buildSExtOrTrunc(Inner,
Cond);
7722 B.buildAdd(Dest, Inner, False);
7729 MatchInfo = [=](MachineIRBuilder &
B) {
7730 B.setInstrAndDebugLoc(*
Select);
7731 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7732 B.buildZExtOrTrunc(Inner,
Cond);
7735 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7736 B.buildShl(Dest, Inner, ShAmtC, Flags);
7743 MatchInfo = [=](MachineIRBuilder &
B) {
7744 B.setInstrAndDebugLoc(*
Select);
7746 B.buildNot(Not,
Cond);
7747 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7748 B.buildZExtOrTrunc(Inner, Not);
7751 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7752 B.buildShl(Dest, Inner, ShAmtC, Flags);
7759 MatchInfo = [=](MachineIRBuilder &
B) {
7760 B.setInstrAndDebugLoc(*
Select);
7761 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7762 B.buildSExtOrTrunc(Inner,
Cond);
7763 B.buildOr(Dest, Inner, False, Flags);
7770 MatchInfo = [=](MachineIRBuilder &
B) {
7771 B.setInstrAndDebugLoc(*
Select);
7773 B.buildNot(Not,
Cond);
7774 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7775 B.buildSExtOrTrunc(Inner, Not);
7776 B.buildOr(Dest, Inner, True, Flags);
7785bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7792 LLT CondTy =
MRI.getType(
Select->getCondReg());
7793 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7802 if (CondTy != TrueTy)
7807 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7808 MatchInfo = [=](MachineIRBuilder &
B) {
7809 B.setInstrAndDebugLoc(*
Select);
7810 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7811 B.buildZExtOrTrunc(Ext,
Cond);
7812 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7813 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7820 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7821 MatchInfo = [=](MachineIRBuilder &
B) {
7822 B.setInstrAndDebugLoc(*
Select);
7823 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7824 B.buildZExtOrTrunc(Ext,
Cond);
7825 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7826 B.buildAnd(DstReg, Ext, FreezeTrue);
7832 if (isOneOrOneSplat(False,
true)) {
7833 MatchInfo = [=](MachineIRBuilder &
B) {
7834 B.setInstrAndDebugLoc(*
Select);
7836 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7837 B.buildNot(Inner,
Cond);
7839 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7840 B.buildZExtOrTrunc(Ext, Inner);
7841 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7842 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7848 if (isZeroOrZeroSplat(True,
true)) {
7849 MatchInfo = [=](MachineIRBuilder &
B) {
7850 B.setInstrAndDebugLoc(*
Select);
7852 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7853 B.buildNot(Inner,
Cond);
7855 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7856 B.buildZExtOrTrunc(Ext, Inner);
7857 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7858 B.buildAnd(DstReg, Ext, FreezeFalse);
7880 LLT DstTy =
MRI.getType(DstReg);
7885 if (!
MRI.hasOneNonDBGUse(CondReg))
7894 if (True == CmpRHS && False == CmpLHS) {
7902 if (True != CmpLHS || False != CmpRHS)
7942 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7943 Register DestReg =
MI.getOperand(0).getReg();
7944 LLT DestTy =
MRI.getType(DestReg);
7958 if (
isLegal({NewOpc, {DestTy}})) {
7960 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7972 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7975 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7985bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7987 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7988 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7992 unsigned Flags = Logic->
getFlags();
8011 std::optional<ValueAndVReg> MaybeC1 =
8015 C1 = MaybeC1->Value;
8017 std::optional<ValueAndVReg> MaybeC2 =
8021 C2 = MaybeC2->Value;
8042 std::optional<APInt> Offset1;
8043 std::optional<APInt> Offset2;
8046 std::optional<ValueAndVReg> MaybeOffset1 =
8049 R1 =
Add->getLHSReg();
8050 Offset1 = MaybeOffset1->Value;
8054 std::optional<ValueAndVReg> MaybeOffset2 =
8057 R2 =
Add->getLHSReg();
8058 Offset2 = MaybeOffset2->Value;
8077 bool CreateMask =
false;
8090 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
8103 CR->getEquivalentICmp(NewPred, NewC,
Offset);
8112 MatchInfo = [=](MachineIRBuilder &
B) {
8113 if (CreateMask &&
Offset != 0) {
8114 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8115 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8116 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8117 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
8118 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8119 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8120 B.buildZExtOrTrunc(DstReg, ICmp);
8121 }
else if (CreateMask &&
Offset == 0) {
8122 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8123 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8124 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8125 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
8126 B.buildZExtOrTrunc(DstReg, ICmp);
8127 }
else if (!CreateMask &&
Offset != 0) {
8128 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8129 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
8130 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8131 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8132 B.buildZExtOrTrunc(DstReg, ICmp);
8133 }
else if (!CreateMask &&
Offset == 0) {
8134 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8135 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
8136 B.buildZExtOrTrunc(DstReg, ICmp);
8144bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
8150 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8162 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8168 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8169 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8170 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8171 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8182 if (LHS0 == RHS1 && LHS1 == RHS0) {
8188 if (LHS0 == RHS0 && LHS1 == RHS1) {
8192 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8194 MatchInfo = [=](MachineIRBuilder &
B) {
8199 auto False =
B.buildConstant(CmpTy, 0);
8200 B.buildZExtOrTrunc(DestReg, False);
8207 B.buildZExtOrTrunc(DestReg, True);
8209 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8210 B.buildZExtOrTrunc(DestReg, Cmp);
8222 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8225 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8234 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8237 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8252 bool IsSigned =
Add->isSigned();
8253 LLT DstTy =
MRI.getType(Dst);
8254 LLT CarryTy =
MRI.getType(Carry);
8257 if (
MRI.use_nodbg_empty(Carry) &&
8260 B.buildAdd(Dst, LHS, RHS);
8261 B.buildUndef(Carry);
8267 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8270 B.buildSAddo(Dst, Carry, RHS, LHS);
8276 B.buildUAddo(Dst, Carry, RHS, LHS);
8281 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8282 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8288 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8289 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8291 B.buildConstant(Dst, Result);
8292 B.buildConstant(Carry, Overflow);
8300 B.buildCopy(Dst, LHS);
8301 B.buildConstant(Carry, 0);
8310 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8313 std::optional<APInt> MaybeAddRHS =
8314 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8317 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8318 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8322 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8323 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8329 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8330 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8355 B.buildConstant(Carry, 0);
8362 B.buildAdd(Dst, LHS, RHS);
8363 B.buildConstant(Carry, 1);
8375 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8378 B.buildConstant(Carry, 0);
8394 B.buildConstant(Carry, 0);
8401 B.buildAdd(Dst, LHS, RHS);
8402 B.buildConstant(Carry, 1);
8420 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8426 auto [Dst,
Base] =
MI.getFirst2Regs();
8427 LLT Ty =
MRI.getType(Dst);
8431 Builder.buildFConstant(Dst, 1.0);
8432 MI.removeFromParent();
8444 std::optional<SrcOp> Res;
8446 while (ExpVal > 0) {
8451 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8454 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8461 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8465 MI.eraseFromParent();
8476 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8483 LLT DstTy =
MRI.getType(Dst);
8486 auto Const =
B.buildConstant(DstTy, C1 - C2);
8487 B.buildAdd(Dst,
A, Const);
8501 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8508 LLT DstTy =
MRI.getType(Dst);
8511 auto Const =
B.buildConstant(DstTy, C2 - C1);
8512 B.buildSub(Dst, Const,
A);
8533 LLT DstTy =
MRI.getType(Dst);
8536 auto Const =
B.buildConstant(DstTy, C1 + C2);
8537 B.buildSub(Dst,
A, Const);
8558 LLT DstTy =
MRI.getType(Dst);
8561 auto Const =
B.buildConstant(DstTy, C1 - C2);
8562 B.buildSub(Dst, Const,
A);
8576 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8583 LLT DstTy =
MRI.getType(Dst);
8586 auto Const =
B.buildConstant(DstTy, C2 - C1);
8587 B.buildAdd(Dst,
A, Const);
8631 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8639 LLT SmallBvTy = DstTy;
8643 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8648 {TargetOpcode::G_ANYEXT,
8660 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8661 Ops.push_back(AnyExt.getReg(0));
8679 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8680 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8681 const unsigned NumDstElts = OrigMask.
size();
8682 for (
unsigned i = 0; i != NumDstElts; ++i) {
8683 int Idx = OrigMask[i];
8684 if (Idx >= (
int)NumSrcElems) {
8695 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8696 std::move(NewMask));
8703 const unsigned MaskSize = Mask.size();
8704 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8709 if (Idx < (
int)NumElems)
8710 Mask[
I] = Idx + NumElems;
8712 Mask[
I] = Idx - NumElems;
8722 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8725 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8728 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8729 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8731 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8735 const unsigned NumSrcElems = Src1Ty.getNumElements();
8737 bool TouchesSrc1 =
false;
8738 bool TouchesSrc2 =
false;
8739 const unsigned NumElems = Mask.size();
8740 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8744 if (Mask[Idx] < (
int)NumSrcElems)
8750 if (TouchesSrc1 == TouchesSrc2)
8753 Register NewSrc1 = Shuffle.getSrc1Reg();
8756 NewSrc1 = Shuffle.getSrc2Reg();
8761 auto Undef =
B.buildUndef(Src1Ty);
8762 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8776 LLT DstTy =
MRI.getType(Dst);
8777 LLT CarryTy =
MRI.getType(Carry);
8799 B.buildConstant(Carry, 0);
8806 B.buildSub(Dst, LHS, RHS);
8824 B.buildConstant(Carry, 0);
8831 B.buildSub(Dst, LHS, RHS);
8848 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8849 "Expected G_CTLZ variant");
8854 LLT Ty =
MRI.getType(Dst);
8855 LLT SrcTy =
MRI.getType(Src);
8857 if (!(Ty.isValid() && Ty.isScalar()))
8866 switch (
LI->getAction(Query).Action) {
8877 bool NeedAdd =
true;
8885 unsigned BitWidth = Ty.getScalarSizeInBits();
8896 B.buildCTLS(Dst,
X);
8900 auto Ctls =
B.buildCTLS(Ty,
X);
8901 auto One =
B.buildConstant(Ty, 1);
8903 B.buildAdd(Dst, Ctls, One);
8913 unsigned TargetOpc)
const {
8914 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8915 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8916 "Expected G_LSHR/G_ASHR");
8919 return XTy ==
MRI.getType(
Y) &&
isLegal({TargetOpc, {XTy}});
8923 assert((
MI.getOpcode() == TargetOpcode::G_CTLZ ||
8924 MI.getOpcode() == TargetOpcode::G_CTTZ) &&
8925 "Expected count-zero opcode");
8926 switch (
MI.getOpcode()) {
8927 case TargetOpcode::G_CTLZ:
8928 return TargetOpcode::G_CTLZ_ZERO_POISON;
8929 case TargetOpcode::G_CTTZ:
8930 return TargetOpcode::G_CTTZ_ZERO_POISON;
8942 if (!
VT->isKnownNeverZero(Src))
8945 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8946 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 zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
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 matchCommuteShift(MachineInstr &MI, BuildFnTy &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 void applyPtrAddZero(MachineInstr &MI) const
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 const DataLayout & getDataLayout() const
LLVM_ABI bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
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 void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
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 applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) 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 bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
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 matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
LLVM_ABI bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
LLVM_ABI void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) 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 matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
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 applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
LLVM_ABI bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
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 matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
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 tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
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 matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
LLVM_ABI bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
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 matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
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 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 bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
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 bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
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 void applySextTruncSextLoad(MachineInstr &MI) const
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.
Represents a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
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 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)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
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)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
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...