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))
280 std::optional<MachineOperand> MaybePoisonOperand;
282 if (!Operand.isReg())
288 if (!MaybePoisonOperand)
289 MaybePoisonOperand = Operand;
298 if (!MaybePoisonOperand) {
303 B.buildCopy(
DstOp, OrigOp);
308 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
309 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
312 {TargetOpcode::G_FREEZE, {MaybePoisonOperandRegTy}}))
320 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
331 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
332 "Invalid instruction");
342 assert(Def &&
"Operand not defined");
343 if (!
MRI.hasOneNonDBGUse(Reg))
345 switch (Def->getOpcode()) {
346 case TargetOpcode::G_BUILD_VECTOR:
351 Ops.push_back(BuildVecMO.getReg());
353 case TargetOpcode::G_IMPLICIT_DEF: {
354 LLT OpType =
MRI.getType(Reg);
361 OpType.getScalarType() &&
362 "All undefs should have the same type");
365 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
366 EltIdx != EltEnd; ++EltIdx)
367 Ops.push_back(
Undef->getOperand(0).getReg());
376 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
378 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
393 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
406 MI.eraseFromParent();
415 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
418 if (BC->
getOpcode() != TargetOpcode::G_BITCAST)
422 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
427 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
431 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
435 if (Src->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
444 if (BC->
getOpcode() != TargetOpcode::G_BITCAST ||
468 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
469 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
470 MI.eraseFromParent();
476 Register SrcVec1 = Shuffle.getSrc1Reg();
477 Register SrcVec2 = Shuffle.getSrc2Reg();
478 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
479 int Width =
MRI.getType(SrcVec1).getNumElements();
481 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
482 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
486 for (
int Val : Shuffle.getMask()) {
489 else if (Val < Width)
490 Extracts.
push_back(Unmerge1.getReg(Val));
492 Extracts.
push_back(Unmerge2.getReg(Val - Width));
494 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
495 if (Extracts.
size() == 1)
496 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
498 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
499 MI.eraseFromParent();
509 if (!ConcatMI1 || !ConcatMI2)
513 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
514 MRI.getType(ConcatMI2->getSourceReg(0)))
517 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
518 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
520 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
524 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
525 if (i + j >= Mask.size())
527 if (Mask[i + j] != -1)
531 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
534 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
535 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
536 if (i + j >= Mask.size())
538 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
544 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
546 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
547 ConcatMI1->getNumSources()));
555 {TargetOpcode::G_CONCAT_VECTORS,
556 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
567 SrcTy =
MRI.getType(Reg);
569 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
576 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
582 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
585 MI.eraseFromParent();
590 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
591 "Invalid instruction kind");
592 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
594 LLT SrcType =
MRI.getType(Src1);
596 unsigned DstNumElts = DstType.getNumElements();
597 unsigned SrcNumElts = SrcType.getNumElements();
614 if (DstNumElts < 2 * SrcNumElts)
619 if (DstNumElts % SrcNumElts != 0)
625 unsigned NumConcat = DstNumElts / SrcNumElts;
628 for (
unsigned i = 0; i != DstNumElts; ++i) {
635 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
636 (ConcatSrcs[i / SrcNumElts] >= 0 &&
637 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
640 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
647 for (
auto Src : ConcatSrcs) {
651 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
653 Ops.push_back(UndefReg);
666 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
674 MI.eraseFromParent();
683 const LLT TyForCandidate,
684 unsigned OpcodeForCandidate,
689 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
700 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
703 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
704 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
705 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
713 OpcodeForCandidate == TargetOpcode::G_ZEXT)
715 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
716 OpcodeForCandidate == TargetOpcode::G_SEXT)
717 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
726 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
737static void InsertInsnsWithoutSideEffectsBeforeUse(
749 InsertBB = PredBB->
getMBB();
754 if (InsertBB ==
DefMI.getParent()) {
756 Inserter(InsertBB, std::next(InsertPt), UseMO);
775 unsigned CandidateLoadOpc;
777 case TargetOpcode::G_ANYEXT:
778 CandidateLoadOpc = TargetOpcode::G_LOAD;
780 case TargetOpcode::G_SEXT:
781 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
783 case TargetOpcode::G_ZEXT:
784 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
789 return CandidateLoadOpc;
806 LLT LoadValueTy =
MRI.getType(LoadReg);
828 unsigned PreferredOpcode =
830 ? TargetOpcode::G_ANYEXT
832 Preferred = {
LLT(), PreferredOpcode,
nullptr};
833 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
834 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
835 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
836 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
837 const auto &MMO = LoadMI->
getMMO();
845 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
847 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
851 Preferred = ChoosePreferredUse(
MI, Preferred,
852 MRI.getType(
UseMI.getOperand(0).getReg()),
862 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
880 if (PreviouslyEmitted) {
887 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
888 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
890 EmittedInsns[InsertIntoBB] = NewMI;
896 MI.setDesc(
Builder.getTII().get(LoadOpc));
903 for (
auto *UseMO :
Uses) {
909 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
912 const LLT UseDstTy =
MRI.getType(UseDstReg);
913 if (UseDstReg != ChosenDstReg) {
914 if (Preferred.
Ty == UseDstTy) {
951 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
966 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
969 MI.getOperand(0).setReg(ChosenDstReg);
975 assert(
MI.getOpcode() == TargetOpcode::G_AND);
986 if (
MRI.getType(Dst).isVector())
994 APInt MaskVal = MaybeMask->Value;
1007 LLT RegTy =
MRI.getType(LoadReg);
1011 unsigned MaskSizeBits = MaskVal.
countr_one();
1014 !
MRI.hasOneNonDBGUse(LoadReg))
1019 if (MaskSizeBits > LoadSizeBits)
1039 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1044 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1048 B.setInstrAndDebugLoc(*LoadMI);
1049 auto &MF =
B.getMF();
1051 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
1052 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1062 "shouldn't consider debug uses");
1070 if (DefOrUse ==
MBB.end())
1072 return &*DefOrUse == &
DefMI;
1078 "shouldn't consider debug uses");
1081 else if (
DefMI.getParent() !=
UseMI.getParent())
1088 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1092 if (
MRI.getType(SrcReg).isVector())
1097 LoadUser = TruncSrc;
1099 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1104 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1106 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1108 if (LoadSizeBits == SizeInBits)
1115 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1116 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1117 MI.eraseFromParent();
1121 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1122 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1125 LLT RegTy =
MRI.getType(DstReg);
1136 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1137 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1139 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1145 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1148 if (NewSizeBits < 8)
1160 if (LoadDef->isSimple())
1162 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1167 {
MRI.getType(LoadDef->getDstReg()),
1168 MRI.getType(LoadDef->getPointerReg())},
1172 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1177 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1178 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1180 unsigned ScalarSizeBits;
1181 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1190 auto &MMO = LoadDef->
getMMO();
1191 Builder.setInstrAndDebugLoc(*LoadDef);
1193 auto PtrInfo = MMO.getPointerInfo();
1194 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1195 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1198 MI.eraseFromParent();
1209 auto *MF =
MI->getMF();
1216 AM.
BaseOffs = CstOff->getSExtValue();
1221 MF->getDataLayout(), AM,
1223 MF->getFunction().getContext()),
1224 MI->getMMO().getAddrSpace());
1229 case TargetOpcode::G_LOAD:
1230 return TargetOpcode::G_INDEXED_LOAD;
1231 case TargetOpcode::G_STORE:
1232 return TargetOpcode::G_INDEXED_STORE;
1233 case TargetOpcode::G_ZEXTLOAD:
1234 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1235 case TargetOpcode::G_SEXTLOAD:
1236 return TargetOpcode::G_INDEXED_SEXTLOAD;
1242bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1252 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1253 OpTys = {PtrTy, Ty, Ty};
1255 OpTys = {Ty, PtrTy};
1257 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1263 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1264 "considered for post-indexing."));
1268 bool &RematOffset)
const {
1281 if (!isIndexedLoadStoreLegal(LdSt))
1290 unsigned NumUsesChecked = 0;
1303 if (StoredValDef == &
Use)
1306 Offset = PtrAdd->getOffsetReg();
1308 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1314 RematOffset =
false;
1318 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1323 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1324 if (&BasePtrUse == PtrDef)
1330 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1332 isIndexedLoadStoreLegal(*BasePtrLdSt))
1338 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1339 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1342 if (BaseUseUse.getParent() != LdSt.
getParent())
1354 Addr = PtrAdd->getReg(0);
1355 Base = PtrAdd->getBaseReg();
1370 MRI.hasOneNonDBGUse(Addr))
1377 if (!isIndexedLoadStoreLegal(LdSt))
1381 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1386 if (
Base == St->getValueReg())
1391 if (St->getValueReg() == Addr)
1396 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1397 if (AddrUse.getParent() != LdSt.
getParent())
1402 bool RealUse =
false;
1403 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1421 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1431 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1438 if (!LoadMI->isSimple())
1450 const unsigned MaxIter = 20;
1453 if (
II->isLoadFoldBarrier())
1455 if (Iter++ == MaxIter)
1471 int Elt = CVal->getZExtValue();
1484 Register VecPtr = LoadMI->getPointerReg();
1485 LLT PtrTy =
MRI.getType(VecPtr);
1493 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1516 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1531 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1533 if (!MatchInfo.
IsPre &&
1534 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1544 unsigned Opcode =
MI.getOpcode();
1545 bool IsStore = Opcode == TargetOpcode::G_STORE;
1551 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1553 *OldCst->getOperand(1).getCImm());
1554 MatchInfo.
Offset = NewCst.getReg(0);
1557 auto MIB =
Builder.buildInstr(NewOpcode);
1559 MIB.addDef(MatchInfo.
Addr);
1560 MIB.addUse(
MI.getOperand(0).getReg());
1562 MIB.addDef(
MI.getOperand(0).getReg());
1563 MIB.addDef(MatchInfo.
Addr);
1566 MIB.addUse(MatchInfo.
Base);
1567 MIB.addUse(MatchInfo.
Offset);
1568 MIB.addImm(MatchInfo.
IsPre);
1569 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1570 MI.eraseFromParent();
1578 unsigned Opcode =
MI.getOpcode();
1579 bool IsDiv, IsSigned;
1584 case TargetOpcode::G_SDIV:
1585 case TargetOpcode::G_UDIV: {
1587 IsSigned = Opcode == TargetOpcode::G_SDIV;
1590 case TargetOpcode::G_SREM:
1591 case TargetOpcode::G_UREM: {
1593 IsSigned = Opcode == TargetOpcode::G_SREM;
1599 unsigned DivOpcode, RemOpcode, DivremOpcode;
1601 DivOpcode = TargetOpcode::G_SDIV;
1602 RemOpcode = TargetOpcode::G_SREM;
1603 DivremOpcode = TargetOpcode::G_SDIVREM;
1605 DivOpcode = TargetOpcode::G_UDIV;
1606 RemOpcode = TargetOpcode::G_UREM;
1607 DivremOpcode = TargetOpcode::G_UDIVREM;
1625 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1626 if (
MI.getParent() ==
UseMI.getParent() &&
1627 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1628 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1641 unsigned Opcode =
MI.getOpcode();
1642 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1645 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1646 DestDivReg =
MI.getOperand(0).getReg();
1650 DestRemReg =
MI.getOperand(0).getReg();
1654 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1661 Builder.setInstrAndDebugLoc(*FirstInst);
1663 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1664 : TargetOpcode::G_UDIVREM,
1665 {DestDivReg, DestRemReg},
1667 MI.eraseFromParent();
1673 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1690 if (BrIt ==
MBB->begin())
1692 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1694 BrCond = &*std::prev(BrIt);
1695 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1701 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1702 MBB->isLayoutSuccessor(BrCondTarget);
1708 Builder.setInstrAndDebugLoc(*BrCond);
1713 auto True =
Builder.buildConstant(
1719 MI.getOperand(0).setMBB(FallthroughBB);
1732 unsigned MaxLen)
const {
1733 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1735 DstAlignCanChange, MemOps);
1740 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1745 DstAlignCanChange, MemOps) ==
1747 assert(
Changed &&
"expected memcpy-family instruction to lower");
1752 unsigned MaxLen)
const {
1764 switch (
MI.getOpcode()) {
1767 case TargetOpcode::G_FNEG: {
1768 Result.changeSign();
1771 case TargetOpcode::G_FABS: {
1775 case TargetOpcode::G_FCEIL:
1778 case TargetOpcode::G_FFLOOR:
1781 case TargetOpcode::G_INTRINSIC_TRUNC:
1784 case TargetOpcode::G_INTRINSIC_ROUND:
1787 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1790 case TargetOpcode::G_FRINT:
1791 case TargetOpcode::G_FNEARBYINT:
1795 case TargetOpcode::G_FPEXT:
1796 case TargetOpcode::G_FPTRUNC: {
1803 case TargetOpcode::G_FSQRT: {
1807 Result =
APFloat(sqrt(Result.convertToDouble()));
1810 case TargetOpcode::G_FLOG2: {
1830 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1831 MI.eraseFromParent();
1842 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1852 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1865 Type *AccessTy =
nullptr;
1866 auto &MF = *
MI.getMF();
1867 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1870 MF.getFunction().getContext());
1875 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1880 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1882 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1883 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1884 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1885 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1894 unsigned PtrAddFlags =
MI.getFlags();
1895 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1911 MatchInfo.
Flags = Flags;
1917 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1919 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1923 MI.getOperand(1).setReg(MatchInfo.
Base);
1924 MI.getOperand(2).setReg(NewOffset.getReg(0));
1938 unsigned Opcode =
MI.getOpcode();
1939 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1940 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1941 Opcode == TargetOpcode::G_USHLSAT) &&
1942 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1962 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1967 if (Opcode == TargetOpcode::G_USHLSAT &&
1968 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1976 unsigned Opcode =
MI.getOpcode();
1977 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1978 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1979 Opcode == TargetOpcode::G_USHLSAT) &&
1980 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1982 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1983 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1984 auto Imm = MatchInfo.
Imm;
1986 if (Imm >= ScalarSizeInBits) {
1988 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1989 Builder.buildConstant(
MI.getOperand(0), 0);
1990 MI.eraseFromParent();
1995 Imm = ScalarSizeInBits - 1;
1998 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
2001 MI.getOperand(1).setReg(MatchInfo.
Reg);
2002 MI.getOperand(2).setReg(NewImm);
2018 unsigned ShiftOpcode =
MI.getOpcode();
2019 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2020 ShiftOpcode == TargetOpcode::G_ASHR ||
2021 ShiftOpcode == TargetOpcode::G_LSHR ||
2022 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2023 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2024 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2027 Register LogicDest =
MI.getOperand(1).getReg();
2028 if (!
MRI.hasOneNonDBGUse(LogicDest))
2032 unsigned LogicOpcode = LogicMI->
getOpcode();
2033 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2034 LogicOpcode != TargetOpcode::G_XOR)
2038 const Register C1 =
MI.getOperand(2).getReg();
2040 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2043 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2047 if (
MI->getOpcode() != ShiftOpcode ||
2048 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2057 ShiftVal = MaybeImmVal->Value.getSExtValue();
2068 if (matchFirstShift(LogicMIOp1, C0Val)) {
2070 MatchInfo.
Shift2 = LogicMIOp1;
2071 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2073 MatchInfo.
Shift2 = LogicMIOp2;
2077 MatchInfo.
ValSum = C0Val + C1Val;
2080 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2083 MatchInfo.
Logic = LogicMI;
2089 unsigned Opcode =
MI.getOpcode();
2090 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2091 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2092 Opcode == TargetOpcode::G_SSHLSAT) &&
2093 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2095 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2096 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2102 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2111 Register Shift2Const =
MI.getOperand(2).getReg();
2113 .buildInstr(Opcode, {DestType},
2123 MI.eraseFromParent();
2128 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2150 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2151 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2152 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2153 LLT SrcTy =
MRI.getType(SrcReg);
2155 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2156 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2157 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2165 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2169 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2184 LLT InnerShiftTy =
MRI.getType(InnerShift);
2186 if ((N1C + N001C).ult(InnerShiftSize)) {
2192 if ((N001C + OpSizeInBits) == InnerShiftSize)
2194 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2195 MatchInfo.
Mask =
true;
2205 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2212 if (MatchInfo.
Mask ==
true) {
2220 Builder.buildTrunc(Dst, Shift);
2221 MI.eraseFromParent();
2225 unsigned &ShiftVal)
const {
2226 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2232 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2233 return (
static_cast<int32_t
>(ShiftVal) != -1);
2237 unsigned &ShiftVal)
const {
2238 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2240 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2243 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2244 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2265 auto NegCst =
B.buildConstant(Ty, -Imm);
2267 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2268 MI.getOperand(2).setReg(NegCst.getReg(0));
2270 if (Imm.isMinSignedValue())
2280 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2294 if (!MaybeShiftAmtVal)
2298 LLT SrcTy =
MRI.getType(ExtSrc);
2308 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2309 MatchData.
Reg = ExtSrc;
2310 MatchData.
Imm = ShiftAmt;
2312 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2313 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2314 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2320 int64_t ShiftAmtVal = MatchData.
Imm;
2322 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2323 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2325 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2326 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2327 MI.eraseFromParent();
2334 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2338 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2341 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2342 if (MergedValues[
I] != Unmerge->getReg(
I))
2345 MatchInfo = Unmerge->getSourceReg();
2359 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2360 "Expected an unmerge");
2369 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2370 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2372 if (SrcMergeTy != Dst0Ty && !SameSize)
2376 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2377 Operands.push_back(SrcInstr->getSourceReg(Idx));
2383 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2384 "Expected an unmerge");
2386 "Not enough operands to replace all defs");
2387 unsigned NumElems =
MI.getNumOperands() - 1;
2390 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2391 bool CanReuseInputDirectly = DstTy == SrcTy;
2392 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2393 Register DstReg =
MI.getOperand(Idx).getReg();
2398 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2399 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2400 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2401 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2404 if (CanReuseInputDirectly)
2407 Builder.buildCast(DstReg, SrcReg);
2409 MI.eraseFromParent();
2414 unsigned SrcIdx =
MI.getNumOperands() - 1;
2415 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2417 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2418 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2426 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2429 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2431 Val = Val.
lshr(ShiftAmt);
2439 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2440 "Expected an unmerge");
2442 "Not enough operands to replace all defs");
2443 unsigned NumElems =
MI.getNumOperands() - 1;
2444 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2445 Register DstReg =
MI.getOperand(Idx).getReg();
2446 Builder.buildConstant(DstReg, Csts[Idx]);
2449 MI.eraseFromParent();
2455 unsigned SrcIdx =
MI.getNumOperands() - 1;
2456 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2458 unsigned NumElems =
MI.getNumOperands() - 1;
2459 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2460 Register DstReg =
MI.getOperand(Idx).getReg();
2461 B.buildUndef(DstReg);
2469 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2470 "Expected an unmerge");
2471 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2472 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2475 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2476 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2484 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2485 Register Dst0Reg =
MI.getOperand(0).getReg();
2486 Builder.buildTrunc(Dst0Reg, SrcReg);
2487 MI.eraseFromParent();
2491 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2492 "Expected an unmerge");
2493 Register Dst0Reg =
MI.getOperand(0).getReg();
2494 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2500 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2501 LLT SrcTy =
MRI.getType(SrcReg);
2502 if (SrcTy.isVector())
2512 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2517 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2518 "Expected an unmerge");
2520 Register Dst0Reg =
MI.getOperand(0).getReg();
2523 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2525 "Expecting a G_ZEXT");
2528 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2529 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2532 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2535 "ZExt src doesn't fit in destination");
2540 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2542 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2545 MI.eraseFromParent();
2549 unsigned TargetShiftSize,
2550 unsigned &ShiftVal)
const {
2551 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2552 MI.getOpcode() == TargetOpcode::G_LSHR ||
2553 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2555 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2560 unsigned Size = Ty.getSizeInBits();
2561 if (
Size <= TargetShiftSize)
2569 ShiftVal = MaybeImmVal->Value.getSExtValue();
2570 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2577 LLT Ty =
MRI.getType(SrcReg);
2578 unsigned Size = Ty.getSizeInBits();
2579 unsigned HalfSize =
Size / 2;
2580 assert(ShiftVal >= HalfSize);
2584 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2585 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2587 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2588 Register Narrowed = Unmerge.getReg(1);
2595 if (NarrowShiftAmt != 0) {
2596 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2597 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2600 auto Zero =
Builder.buildConstant(HalfTy, 0);
2601 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2602 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2603 Register Narrowed = Unmerge.getReg(0);
2608 if (NarrowShiftAmt != 0) {
2609 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2610 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2613 auto Zero =
Builder.buildConstant(HalfTy, 0);
2614 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2616 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2618 HalfTy, Unmerge.getReg(1),
2619 Builder.buildConstant(HalfTy, HalfSize - 1));
2621 if (ShiftVal == HalfSize) {
2624 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2625 }
else if (ShiftVal ==
Size - 1) {
2633 HalfTy, Unmerge.getReg(1),
2634 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2642 MI.eraseFromParent();
2658 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2660 LLT DstTy =
MRI.getType(DstReg);
2668 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2670 Builder.buildCopy(DstReg, Reg);
2671 MI.eraseFromParent();
2676 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2678 Builder.buildZExtOrTrunc(DstReg, Reg);
2679 MI.eraseFromParent();
2684 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2687 LLT IntTy =
MRI.getType(LHS);
2691 PtrReg.second =
false;
2692 for (
Register SrcReg : {LHS, RHS}) {
2696 LLT PtrTy =
MRI.getType(PtrReg.first);
2701 PtrReg.second =
true;
2713 const bool DoCommute = PtrReg.second;
2718 LLT PtrTy =
MRI.getType(LHS);
2720 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2721 Builder.buildPtrToInt(Dst, PtrAdd);
2722 MI.eraseFromParent();
2726 APInt &NewCst)
const {
2728 Register LHS = PtrAdd.getBaseReg();
2729 Register RHS = PtrAdd.getOffsetReg();
2735 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2738 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2747 APInt &NewCst)
const {
2751 Builder.buildConstant(Dst, NewCst);
2752 PtrAdd.eraseFromParent();
2757 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2762 SrcReg = OriginalSrcReg;
2763 LLT DstTy =
MRI.getType(DstReg);
2771 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2774 LLT DstTy =
MRI.getType(DstReg);
2779 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2780 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2790 if (ShiftSize > 32 && TruncSize < 32)
2803 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2804 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2808 if (!
MRI.hasOneNonDBGUse(SrcReg))
2811 LLT SrcTy =
MRI.getType(SrcReg);
2812 LLT DstTy =
MRI.getType(DstReg);
2821 case TargetOpcode::G_SHL: {
2830 case TargetOpcode::G_LSHR:
2831 case TargetOpcode::G_ASHR: {
2837 for (
auto &
User :
MRI.use_instructions(DstReg))
2838 if (
User.getOpcode() == TargetOpcode::G_STORE)
2842 if (NewShiftTy == SrcTy)
2856 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2859 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2864 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2866 LLT NewShiftTy = MatchInfo.second;
2869 LLT DstTy =
MRI.getType(Dst);
2873 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2876 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2877 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2878 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2882 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2885 if (NewShiftTy == DstTy)
2888 Builder.buildTrunc(Dst, NewShift);
2895 return MO.isReg() &&
2896 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2902 return !MO.isReg() ||
2903 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2908 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2910 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2914 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2915 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2920 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2921 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2927 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2928 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2929 "Expected an insert/extract element op");
2930 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2935 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2943 unsigned &
OpIdx)
const {
2948 OpIdx = Cst->isZero() ? 3 : 2;
2993 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
3020 return MO.isReg() && MO.getReg().isPhysical();
3030 return I1->isIdenticalTo(*I2);
3038 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
3045 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
3056 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
3057 MaybeCst->getSExtValue() ==
C;
3064 std::optional<FPValueAndVReg> MaybeCst;
3068 return MaybeCst->Value.isExactlyValue(
C);
3072 unsigned OpIdx)
const {
3073 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3078 MI.eraseFromParent();
3083 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3087 MI.eraseFromParent();
3091 unsigned ConstIdx)
const {
3092 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3093 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3105 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3106 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3107 "This is not a funnel shift operation");
3109 Register ConstReg =
MI.getOperand(3).getReg();
3110 LLT ConstTy =
MRI.getType(ConstReg);
3111 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3114 assert((VRegAndVal) &&
"Value is not a constant");
3117 APInt NewConst = VRegAndVal->Value.
urem(
3122 MI.getOpcode(), {MI.getOperand(0)},
3123 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3125 MI.eraseFromParent();
3129 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3143 unsigned OpIdx)
const {
3145 return MO.
isReg() &&
3156 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3158 MI.eraseFromParent();
3163 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3165 MI.eraseFromParent();
3169 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3171 MI.eraseFromParent();
3176 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3178 MI.eraseFromParent();
3182 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3184 MI.eraseFromParent();
3188 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3191 Register &NewLHS = std::get<0>(MatchInfo);
3192 Register &NewRHS = std::get<1>(MatchInfo);
3200 NewLHS = MaybeNewLHS;
3204 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3209 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3212 LLT DstTy =
MRI.getType(DstReg);
3221 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3222 TargetOpcode::G_INSERT_VECTOR_ELT)
3228 MatchInfo.
resize(NumElts);
3232 if (IntImm >= NumElts || IntImm < 0)
3234 if (!MatchInfo[IntImm])
3235 MatchInfo[IntImm] = TmpReg;
3239 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3241 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3250 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3257 auto GetUndef = [&]() {
3260 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3268 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3269 MI.eraseFromParent();
3273 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3275 std::tie(SubLHS, SubRHS) = MatchInfo;
3276 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3277 MI.eraseFromParent();
3290 unsigned InnerOpc = InnerDef->
getOpcode();
3291 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3315 if (!TryMatch(InnerLHS, InnerRHS) &&
3316 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3320 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3321 : TargetOpcode::G_ADD;
3324 MatchInfo = [=](MachineIRBuilder &
Builder) {
3325 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3326 auto NewNot =
Builder.buildNot(Ty, NewInner);
3327 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3339 unsigned RootOpc =
MI.getOpcode();
3341 LLT Ty =
MRI.getType(Dst);
3346 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3347 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3358 unsigned LogicOpcode =
MI.getOpcode();
3359 assert(LogicOpcode == TargetOpcode::G_AND ||
3360 LogicOpcode == TargetOpcode::G_OR ||
3361 LogicOpcode == TargetOpcode::G_XOR);
3368 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3374 if (!LeftHandInst || !RightHandInst)
3376 unsigned HandOpcode = LeftHandInst->
getOpcode();
3377 if (HandOpcode != RightHandInst->
getOpcode())
3391 if (!XTy.
isValid() || XTy != YTy)
3396 switch (HandOpcode) {
3399 case TargetOpcode::G_ANYEXT:
3400 case TargetOpcode::G_SEXT:
3401 case TargetOpcode::G_ZEXT: {
3405 case TargetOpcode::G_TRUNC: {
3410 LLT DstTy =
MRI.getType(Dst);
3419 case TargetOpcode::G_AND:
3420 case TargetOpcode::G_ASHR:
3421 case TargetOpcode::G_LSHR:
3422 case TargetOpcode::G_SHL: {
3427 ExtraHandOpSrcReg = ZOp.
getReg();
3438 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3449 if (ExtraHandOpSrcReg.
isValid())
3461 "Expected at least one instr to build?");
3463 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3464 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3466 for (
auto &OperandFn : InstrToBuild.OperandFns)
3469 MI.eraseFromParent();
3473 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3474 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3475 int64_t ShlCst, AshrCst;
3481 if (ShlCst != AshrCst)
3484 {TargetOpcode::G_SEXT_INREG,
3487 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3489 MatchInfo = std::make_tuple(Src, ShlCst);
3494 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3495 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3498 std::tie(Src, ShiftAmt) = MatchInfo;
3499 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3500 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3501 MI.eraseFromParent();
3508 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3511 LLT Ty =
MRI.getType(Dst);
3523 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3526 auto Zero =
B.buildConstant(Ty, 0);
3549 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3573 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3580 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3597 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3615 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3622 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3633 unsigned ExtBits =
MI.getOperand(2).getImm();
3634 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3635 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3639 int64_t Cst,
bool IsVector,
bool IsFP) {
3641 return (ScalarSizeBits == 1 && Cst == -1) ||
3663 unsigned BuildUseCount = BV.getNumSources();
3664 if (BuildUseCount % 2 != 0)
3667 unsigned NumUnmerge = BuildUseCount / 2;
3673 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3676 UnmergeSrc = Unmerge->getSourceReg();
3678 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3679 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3686 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3691 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3692 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3695 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3698 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3703 if (Unmerge->getNumDefs() != NumUnmerge)
3707 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3710 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3721 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3722 B.setInstrAndDebugLoc(
MI);
3724 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3725 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3727 MI.eraseFromParent();
3749 unsigned NumOperands =
BuildMI->getNumSources();
3759 for (
I = 0;
I < NumOperands; ++
I) {
3760 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3761 auto SrcMIOpc = SrcMI->getOpcode();
3764 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3765 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3767 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3768 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3771 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3772 if (UnmergeMI != UnmergeSrcMI)
3787 for (;
I < NumOperands; ++
I) {
3788 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3789 auto SrcMIOpc = SrcMI->getOpcode();
3791 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3797 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3804 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3805 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3813 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3816 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3828 LLT DstTy =
MRI.getType(DstReg);
3829 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3834 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3839 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3843 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3846 Builder.buildTrunc(DstReg, MidReg);
3847 MI.eraseFromParent();
3852 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3853 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3854 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3862 if (!
MRI.hasOneNonDBGUse(XorSrc))
3872 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3874 if (!
MRI.hasOneNonDBGUse(Reg))
3877 switch (Def->getOpcode()) {
3882 case TargetOpcode::G_ICMP:
3888 case TargetOpcode::G_FCMP:
3894 case TargetOpcode::G_AND:
3895 case TargetOpcode::G_OR:
3901 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3902 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3910 if (Ty.isVector()) {
3915 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3929 for (
Register Reg : RegsToNegate) {
3934 switch (Def->getOpcode()) {
3937 case TargetOpcode::G_ICMP:
3938 case TargetOpcode::G_FCMP: {
3945 case TargetOpcode::G_AND:
3946 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3948 case TargetOpcode::G_OR:
3949 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3956 MI.eraseFromParent();
3960 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3962 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3966 Register SharedReg =
MI.getOperand(2).getReg();
3980 if (!
MRI.hasOneNonDBGUse(AndReg))
3987 return Y == SharedReg;
3991 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3994 std::tie(
X,
Y) = MatchInfo;
3997 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3998 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3999 MI.getOperand(2).setReg(
Y);
4005 Register DstReg = PtrAdd.getReg(0);
4006 LLT Ty =
MRI.getType(DstReg);
4009 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
4012 if (Ty.isPointer()) {
4014 return ConstVal && *ConstVal == 0;
4017 assert(Ty.isVector() &&
"Expecting a vector type");
4024 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
4025 PtrAdd.eraseFromParent();
4032 Register Pow2Src1 =
MI.getOperand(2).getReg();
4033 LLT Ty =
MRI.getType(DstReg);
4036 auto NegOne =
Builder.buildConstant(Ty, -1);
4037 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
4039 MI.eraseFromParent();
4043 unsigned &SelectOpNo)
const {
4053 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
4054 !
MRI.hasOneNonDBGUse(LHS)) {
4055 OtherOperandReg = LHS;
4058 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
4059 !
MRI.hasOneNonDBGUse(RHS))
4075 unsigned BinOpcode =
MI.getOpcode();
4080 bool CanFoldNonConst =
4081 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4086 if (CanFoldNonConst)
4107 LLT Ty =
MRI.getType(Dst);
4108 unsigned BinOpcode =
MI.getOpcode();
4115 if (SelectOperand == 1) {
4119 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4121 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4123 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4125 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4128 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4129 MI.eraseFromParent();
4132std::optional<SmallVector<Register, 8>>
4133CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4134 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4163 const unsigned MaxIter =
4165 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4174 return std::nullopt;
4190 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4191 return std::nullopt;
4203static std::optional<std::pair<GZExtLoad *, int64_t>>
4207 "Expected Reg to only have one non-debug use?");
4216 if (Shift % MemSizeInBits != 0)
4217 return std::nullopt;
4222 return std::nullopt;
4224 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
4225 return std::nullopt;
4227 return std::make_pair(
Load, Shift / MemSizeInBits);
4230std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4231CombinerHelper::findLoadOffsetsForLoadOrCombine(
4234 const unsigned MemSizeInBits)
const {
4237 SmallSetVector<const MachineInstr *, 8> Loads;
4243 GZExtLoad *LowestIdxLoad =
nullptr;
4246 SmallSet<int64_t, 8> SeenIdx;
4250 MachineBasicBlock *
MBB =
nullptr;
4251 const MachineMemOperand *MMO =
nullptr;
4254 GZExtLoad *EarliestLoad =
nullptr;
4257 GZExtLoad *LatestLoad =
nullptr;
4266 for (
auto Reg : RegsToVisit) {
4271 return std::nullopt;
4274 std::tie(
Load, DstPos) = *LoadAndPos;
4278 MachineBasicBlock *LoadMBB =
Load->getParent();
4282 return std::nullopt;
4285 auto &LoadMMO =
Load->getMMO();
4289 return std::nullopt;
4296 LoadPtr =
Load->getOperand(1).getReg();
4301 if (!SeenIdx.
insert(Idx).second)
4302 return std::nullopt;
4309 if (BasePtr != LoadPtr)
4310 return std::nullopt;
4312 if (Idx < LowestIdx) {
4314 LowestIdxLoad =
Load;
4321 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4322 return std::nullopt;
4331 EarliestLoad =
Load;
4339 "Expected to find a load for each register?");
4340 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4341 LatestLoad &&
"Expected at least two loads?");
4350 const unsigned MaxIter = 20;
4356 if (
MI.isLoadFoldBarrier())
4357 return std::nullopt;
4358 if (Iter++ == MaxIter)
4359 return std::nullopt;
4362 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4368 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4381 LLT Ty =
MRI.getType(Dst);
4387 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4388 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4392 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4399 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4400 if (NarrowMemSizeInBits % 8 != 0)
4413 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4414 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4417 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4424 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4427 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4439 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4440 const unsigned ZeroByteOffset =
4444 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4445 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4446 ZeroOffsetIdx->second != LowestIdx)
4456 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4470 MIB.setInstrAndDebugLoc(*LatestLoad);
4471 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4472 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4474 MIB.buildBSwap(Dst, LoadDst);
4486 if (
MRI.getType(DstReg).isVector())
4490 if (!
MRI.hasOneNonDBGUse(DstReg))
4492 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4494 case TargetOpcode::G_ANYEXT:
4496 case TargetOpcode::G_ZEXT:
4497 case TargetOpcode::G_SEXT:
4504 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4511 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4513 switch (
DefMI->getOpcode()) {
4514 case TargetOpcode::G_LOAD:
4515 case TargetOpcode::G_TRUNC:
4516 case TargetOpcode::G_SEXT:
4517 case TargetOpcode::G_ZEXT:
4518 case TargetOpcode::G_ANYEXT:
4519 case TargetOpcode::G_CONSTANT:
4523 if (InSrcs.
size() > 2)
4537 LLT ExtTy =
MRI.getType(DstReg);
4544 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4545 auto SrcReg =
PHI.getIncomingValue(
I);
4546 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4547 if (!SrcMIs.
insert(SrcMI))
4551 auto *
MBB = SrcMI->getParent();
4553 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4554 InsertPt =
MBB->getFirstNonPHI();
4556 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4559 OldToNewSrcMap[SrcMI] = NewExt;
4564 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4565 NewPhi.addDef(DstReg);
4568 NewPhi.addMBB(MO.getMBB());
4571 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4572 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4580 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4584 LLT SrcTy =
MRI.getType(SrcVec);
4585 if (SrcTy.isScalableVector())
4589 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4592 unsigned VecIdx = Cst->Value.getZExtValue();
4597 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4601 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4602 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4606 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4618 LLT ScalarTy =
MRI.getType(Reg);
4620 LLT DstTy =
MRI.getType(DstReg);
4622 if (ScalarTy != DstTy) {
4624 Builder.buildTrunc(DstReg, Reg);
4625 MI.eraseFromParent();
4633 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4634 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4652 LLT DstTy =
MRI.getType(DstReg);
4657 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4662 unsigned Idx = Cst->getZExtValue();
4665 ExtractedElts.
set(Idx);
4666 SrcDstPairs.emplace_back(
4667 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4670 return ExtractedElts.
all();
4675 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4676 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4677 for (
auto &Pair : SrcDstPairs) {
4678 auto *ExtMI = Pair.second;
4680 ExtMI->eraseFromParent();
4682 MI.eraseFromParent();
4689 MI.eraseFromParent();
4699 bool AllowScalarConstants,
4701 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4704 LLT Ty =
MRI.getType(Dst);
4705 unsigned BitWidth = Ty.getScalarSizeInBits();
4707 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4708 unsigned FshOpc = 0;
4719 int64_t CstShlAmt = 0, CstLShrAmt;
4722 CstShlAmt + CstLShrAmt ==
BitWidth) {
4723 FshOpc = TargetOpcode::G_FSHR;
4729 FshOpc = TargetOpcode::G_FSHL;
4734 FshOpc = TargetOpcode::G_FSHR;
4739 LLT AmtTy =
MRI.getType(Amt);
4741 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4745 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4752 unsigned Opc =
MI.getOpcode();
4753 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4758 unsigned RotateOpc =
4759 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4764 unsigned Opc =
MI.getOpcode();
4765 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4766 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4768 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4769 : TargetOpcode::G_ROTR));
4770 MI.removeOperand(2);
4776 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4777 MI.getOpcode() == TargetOpcode::G_ROTR);
4779 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4781 bool OutOfRange =
false;
4782 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4784 OutOfRange |= CI->getValue().uge(Bitsize);
4791 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4792 MI.getOpcode() == TargetOpcode::G_ROTR);
4794 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4796 LLT AmtTy =
MRI.getType(Amt);
4797 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4798 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4800 MI.getOperand(2).setReg(Amt);
4805 int64_t &MatchInfo)
const {
4806 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4817 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4818 if (KnownRHS.isUnknown())
4821 std::optional<bool> KnownVal;
4822 if (KnownRHS.isZero()) {
4832 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4842 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4851 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4867 LLT DstTy =
MRI.getType(Dst);
4875 auto KnownLHS =
VT->getKnownBits(LHS);
4876 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4879 LLT LHSTy =
MRI.getType(LHS);
4882 unsigned Op = TargetOpcode::COPY;
4883 if (DstSize != LHSSize)
4884 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4895 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4899 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4905 int64_t AndMaskBits;
4913 if (AndMaskBits & OrMaskBits)
4919 if (
MI.getOperand(1).getReg() == AndMaskReg)
4920 MI.getOperand(2).setReg(AndMaskReg);
4921 MI.getOperand(1).setReg(Src);
4931 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4934 LLT Ty =
MRI.getType(Src);
4936 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4938 int64_t Width =
MI.getOperand(2).getImm();
4946 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4950 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4951 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4952 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4962 LLT Ty =
MRI.getType(Dst);
4966 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4969 int64_t AndImm, LSBImm;
4971 const unsigned Size = Ty.getScalarSizeInBits();
4978 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4979 if (MaybeMask & (MaybeMask + 1))
4988 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4989 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4990 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4998 const unsigned Opcode =
MI.getOpcode();
4999 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
5001 const Register Dst =
MI.getOperand(0).getReg();
5003 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
5004 ? TargetOpcode::G_SBFX
5005 : TargetOpcode::G_UBFX;
5008 LLT Ty =
MRI.getType(Dst);
5010 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
5016 const unsigned Size = Ty.getScalarSizeInBits();
5026 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
5030 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
5034 const int64_t Pos = ShrAmt - ShlAmt;
5035 const int64_t Width =
Size - ShrAmt;
5038 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5039 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5040 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
5048 const unsigned Opcode =
MI.getOpcode();
5049 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
5051 const Register Dst =
MI.getOperand(0).getReg();
5052 LLT Ty =
MRI.getType(Dst);
5054 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
5067 const unsigned Size = Ty.getScalarSizeInBits();
5068 if (ShrAmt < 0 || ShrAmt >=
Size)
5072 if (0 == (SMask >> ShrAmt)) {
5074 B.buildConstant(Dst, 0);
5080 uint64_t UMask = SMask;
5087 const int64_t Pos = ShrAmt;
5092 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5096 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5097 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5098 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5103bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5107 Register Src1Reg = PtrAdd.getBaseReg();
5112 Register Src2Reg = PtrAdd.getOffsetReg();
5114 if (
MRI.hasOneNonDBGUse(Src1Reg))
5124 const APInt &C1APIntVal = *C1;
5125 const APInt &C2APIntVal = *C2;
5126 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5128 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5131 MachineInstr *ConvUseMI = &
UseMI;
5132 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5133 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5134 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5136 if (!
MRI.hasOneNonDBGUse(DefReg))
5138 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5147 TargetLoweringBase::AddrMode AM;
5150 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5152 PtrAdd.getMF()->getFunction().getContext());
5153 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5154 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5160 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5172 Register Src1Reg =
MI.getOperand(1).getReg();
5173 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5185 unsigned PtrAddFlags =
MI.getFlags();
5186 unsigned AddFlags = RHS->getFlags();
5199 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5202 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5204 MI.getOperand(1).setReg(NewBase.getReg(0));
5205 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5209 return !reassociationCanBreakAddressingModePattern(
MI);
5219 std::optional<ValueAndVReg> LHSCstOff;
5229 unsigned PtrAddFlags =
MI.getFlags();
5230 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5232 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5234 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5248 LHSPtrAdd->moveBefore(&
MI);
5251 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5253 MI.getOperand(2).setReg(NewCst.getReg(0));
5256 Observer.changingInstr(*LHSPtrAdd);
5257 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5258 LHSPtrAdd->setFlags(Flags);
5261 return !reassociationCanBreakAddressingModePattern(
MI);
5272 Register Src2Reg =
MI.getOperand(2).getReg();
5273 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5274 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5287 unsigned PtrAddFlags =
MI.getFlags();
5288 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5301 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5303 MI.getOperand(1).setReg(LHSSrc1);
5304 MI.getOperand(2).setReg(NewCst.getReg(0));
5308 return !reassociationCanBreakAddressingModePattern(
MI);
5346 LLT OpRHSTy =
MRI.getType(OpRHS);
5364 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5365 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5373 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5374 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5387 unsigned Opc =
MI.getOpcode();
5400 APInt &MatchInfo)
const {
5401 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5405 MatchInfo = *MaybeCst;
5416 MI.getOperand(1).getReg(),
MRI);
5421 if (Csts.size() == 1)
5422 B.buildConstant(Dst, Csts[0]);
5424 B.buildBuildVectorConstant(Dst, Csts);
5430 APInt &MatchInfo)
const {
5436 MatchInfo = *MaybeCst;
5448 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5454 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5455 MI.getOpcode() == TargetOpcode::G_FMAD);
5456 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5473 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5496 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5500 LLT WideTy =
MRI.getType(Dst);
5504 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5520 case TargetOpcode::G_ADD:
5521 case TargetOpcode::G_SUB:
5522 case TargetOpcode::G_MUL:
5523 case TargetOpcode::G_AND:
5524 case TargetOpcode::G_OR:
5525 case TargetOpcode::G_XOR:
5533 auto Mask = Cst->Value;
5538 unsigned NarrowWidth = Mask.countr_one();
5544 auto &MF = *
MI.getMF();
5547 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5548 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5556 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5557 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5559 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5560 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5562 MI.getOperand(1).setReg(Ext.getReg(0));
5570 unsigned Opc =
MI.getOpcode();
5571 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5578 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5579 : TargetOpcode::G_SADDO;
5580 MI.setDesc(
Builder.getTII().get(NewOpc));
5581 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5590 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5591 MI.getOpcode() == TargetOpcode::G_SMULO);
5600 B.buildConstant(Dst, 0);
5601 B.buildConstant(Carry, 0);
5610 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5611 MI.getOpcode() == TargetOpcode::G_SADDE ||
5612 MI.getOpcode() == TargetOpcode::G_USUBE ||
5613 MI.getOpcode() == TargetOpcode::G_SSUBE);
5618 switch (
MI.getOpcode()) {
5619 case TargetOpcode::G_UADDE:
5620 NewOpcode = TargetOpcode::G_UADDO;
5622 case TargetOpcode::G_SADDE:
5623 NewOpcode = TargetOpcode::G_SADDO;
5625 case TargetOpcode::G_USUBE:
5626 NewOpcode = TargetOpcode::G_USUBO;
5628 case TargetOpcode::G_SSUBE:
5629 NewOpcode = TargetOpcode::G_SSUBO;
5633 MI.setDesc(
B.getTII().get(NewOpcode));
5634 MI.removeOperand(4);
5642 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5675 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5676 B.buildSub(Dst, Zero, ReplaceReg);
5685 unsigned Opcode =
MI.getOpcode();
5686 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5688 Register Dst = UDivorRem.getReg(0);
5689 Register LHS = UDivorRem.getReg(1);
5690 Register RHS = UDivorRem.getReg(2);
5691 LLT Ty =
MRI.getType(Dst);
5699 bool UseSRL =
false;
5704 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5706 if (IsSplat && !Factors.
empty()) {
5713 APInt Divisor = CI->getValue();
5722 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5723 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5733 if (Ty.isVector()) {
5734 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5735 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5738 Factor = Factors[0];
5746 return MIB.buildMul(Ty, Res, Factor);
5749 unsigned KnownLeadingZeros =
5750 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5752 bool UseNPQ =
false;
5754 auto BuildUDIVPattern = [&](
const Constant *
C) {
5756 const APInt &Divisor = CI->getValue();
5758 bool SelNPQ =
false;
5760 unsigned PreShift = 0, PostShift = 0;
5765 if (!Divisor.
isOne()) {
5771 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5773 Magic = std::move(magics.
Magic);
5776 "We shouldn't generate an undefined shift!");
5778 "We shouldn't generate an undefined shift!");
5782 SelNPQ = magics.
IsAdd;
5786 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5787 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5789 MIB.buildConstant(ScalarTy,
5794 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5802 assert(Matched &&
"Expected unary predicate match to succeed");
5804 Register PreShift, PostShift, MagicFactor, NPQFactor;
5807 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5808 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5809 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5810 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5813 "Non-build_vector operation should have been a scalar");
5814 PreShift = PreShifts[0];
5815 MagicFactor = MagicFactors[0];
5816 PostShift = PostShifts[0];
5820 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5823 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5826 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5831 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5833 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5835 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5838 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5839 auto One = MIB.buildConstant(Ty, 1);
5840 auto IsOne = MIB.buildICmp(
5844 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5846 if (Opcode == TargetOpcode::G_UREM) {
5847 auto Prod = MIB.buildMul(Ty, ret, RHS);
5848 return MIB.buildSub(Ty, LHS, Prod);
5854 unsigned Opcode =
MI.getOpcode();
5855 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5858 LLT DstTy =
MRI.getType(Dst);
5860 auto &MF = *
MI.getMF();
5861 AttributeList Attr = MF.getFunction().getAttributes();
5870 if (MF.getFunction().hasMinSize())
5873 if (Opcode == TargetOpcode::G_UDIV &&
5876 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5879 auto *RHSDef =
MRI.getVRegDef(RHS);
5890 {TargetOpcode::G_ICMP,
5894 if (Opcode == TargetOpcode::G_UREM &&
5900 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5909 unsigned Opcode =
MI.getOpcode();
5910 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5913 LLT DstTy =
MRI.getType(Dst);
5917 auto &MF = *
MI.getMF();
5918 AttributeList Attr = MF.getFunction().getAttributes();
5927 if (MF.getFunction().hasMinSize())
5931 if (Opcode == TargetOpcode::G_SDIV &&
5934 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5937 auto *RHSDef =
MRI.getVRegDef(RHS);
5945 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5948 if (Opcode == TargetOpcode::G_SREM &&
5954 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5963 unsigned Opcode =
MI.getOpcode();
5964 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5965 Opcode == TargetOpcode::G_SREM);
5967 Register Dst = SDivorRem.getReg(0);
5968 Register LHS = SDivorRem.getReg(1);
5969 Register RHS = SDivorRem.getReg(2);
5970 LLT Ty =
MRI.getType(Dst);
5977 bool UseSRA =
false;
5983 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5985 if (IsSplat && !ExactFactors.
empty()) {
5987 ExactFactors.
push_back(ExactFactors[0]);
5992 APInt Divisor = CI->getValue();
6002 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
6003 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
6011 assert(Matched &&
"Expected unary predicate match to succeed");
6014 if (Ty.isVector()) {
6015 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
6016 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
6018 Shift = ExactShifts[0];
6019 Factor = ExactFactors[0];
6027 return MIB.buildMul(Ty, Res, Factor);
6032 auto BuildSDIVPattern = [&](
const Constant *
C) {
6034 const APInt &Divisor = CI->getValue();
6038 int NumeratorFactor = 0;
6049 NumeratorFactor = 1;
6052 NumeratorFactor = -1;
6055 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
6056 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
6058 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
6059 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
6067 assert(Matched &&
"Expected unary predicate match to succeed");
6069 Register MagicFactor, Factor, Shift, ShiftMask;
6072 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
6073 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
6074 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
6075 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
6078 "Non-build_vector operation should have been a scalar");
6079 MagicFactor = MagicFactors[0];
6080 Factor = Factors[0];
6082 ShiftMask = ShiftMasks[0];
6086 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6089 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6090 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6093 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6096 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6097 auto T = MIB.buildLShr(Ty, Q, SignShift);
6098 T = MIB.buildAnd(Ty,
T, ShiftMask);
6099 auto ret = MIB.buildAdd(Ty, Q,
T);
6101 if (Opcode == TargetOpcode::G_SREM) {
6102 auto Prod = MIB.buildMul(Ty, ret, RHS);
6103 return MIB.buildSub(Ty, LHS, Prod);
6109 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6110 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6111 "Expected SDIV or UDIV");
6114 auto MatchPow2 = [&](
const Constant *
C) {
6116 return CI && (CI->getValue().isPowerOf2() ||
6117 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6123 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6128 LLT Ty =
MRI.getType(Dst);
6148 unsigned BitWidth = Ty.getScalarSizeInBits();
6149 auto Zero =
Builder.buildConstant(Ty, 0);
6152 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6153 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6155 auto Sign =
Builder.buildAShr(
6159 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6165 auto One =
Builder.buildConstant(Ty, 1);
6166 auto MinusOne =
Builder.buildConstant(Ty, -1);
6170 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6171 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6175 auto Neg =
Builder.buildNeg(Ty, AShr);
6177 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6178 MI.eraseFromParent();
6182 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6187 LLT Ty =
MRI.getType(Dst);
6190 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6191 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6192 MI.eraseFromParent();
6196 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6201 LLT Ty =
MRI.getType(Dst);
6220 unsigned BitWidth = Ty.getScalarSizeInBits();
6221 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6222 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6224 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6225 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6226 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6229 MI.eraseFromParent();
6233 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6236 LLT Ty =
MRI.getType(Dst);
6237 LLT RHSTy =
MRI.getType(RHS);
6239 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6241 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6256 LLT Ty =
MRI.getType(Dst);
6262 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6263 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6264 Builder.buildLShr(Dst, LHS, Trunc);
6265 MI.eraseFromParent();
6272 LLT DstTy =
MRI.getType(Dst);
6273 LLT SrcTy =
MRI.getType(Src);
6275 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6276 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6279 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6297 Builder.buildTruncSSatS(Dst, MatchInfo);
6298 MI.eraseFromParent();
6305 LLT DstTy =
MRI.getType(Dst);
6306 LLT SrcTy =
MRI.getType(Src);
6308 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6309 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6312 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6330 Builder.buildTruncSSatU(Dst, MatchInfo);
6331 MI.eraseFromParent();
6338 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6339 LLT SrcTy =
MRI.getType(Val);
6341 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6342 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6345 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6354 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6363 unsigned Opc =
MI.getOpcode();
6364 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6365 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6366 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6378 Opc = TargetOpcode::G_FSUB;
6383 Opc = TargetOpcode::G_FADD;
6389 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6390 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6399 MI.setDesc(
B.getTII().get(
Opc));
6400 MI.getOperand(1).setReg(
X);
6401 MI.getOperand(2).setReg(
Y);
6409 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6412 MatchInfo =
MI.getOperand(2).getReg();
6413 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6415 const auto LHSCst = Ty.isVector()
6422 if (LHSCst->Value.isNegZero())
6426 if (LHSCst->Value.isPosZero())
6436 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6443 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6457 bool &AllowFusionGlobally,
6459 bool CanReassociate)
const {
6461 auto *MF =
MI.getMF();
6462 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6464 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6472 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6475 if (!HasFMAD && !HasFMA)
6483 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6490 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6492 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6500 unsigned PreferredFusedOpcode =
6501 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6515 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6516 {LHS.MI->getOperand(1).getReg(),
6517 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6526 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6527 {RHS.MI->getOperand(1).getReg(),
6528 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6539 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6541 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6545 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6550 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6552 unsigned PreferredFusedOpcode =
6553 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6567 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6572 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6573 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6582 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6587 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6588 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6599 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6601 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6609 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6611 unsigned PreferredFusedOpcode =
6612 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6625 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6626 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6627 TargetOpcode::G_FMUL) &&
6628 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6629 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6634 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6635 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6636 TargetOpcode::G_FMUL) &&
6637 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6638 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6645 Register X = FMA->getOperand(1).getReg();
6646 Register Y = FMA->getOperand(2).getReg();
6651 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6652 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6653 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6665 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6667 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6674 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6675 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6681 unsigned PreferredFusedOpcode =
6682 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6695 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6696 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6698 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6700 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6707 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6711 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6716 LHS.MI->getOperand(1).getReg(),
6717 LHS.MI->getOperand(2).getReg(),
B);
6728 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6731 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6736 X =
B.buildFPExt(DstType,
X).getReg(0);
6737 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6748 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6752 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6757 RHS.MI->getOperand(1).getReg(),
6758 RHS.MI->getOperand(2).getReg(),
B);
6769 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6772 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6777 X =
B.buildFPExt(DstType,
X).getReg(0);
6778 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6792 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6794 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6802 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6806 int FirstMulHasFewerUses =
true;
6810 FirstMulHasFewerUses =
false;
6812 unsigned PreferredFusedOpcode =
6813 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6816 if (FirstMulHasFewerUses &&
6820 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6821 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6822 {LHS.MI->getOperand(1).getReg(),
6823 LHS.MI->getOperand(2).getReg(), NegZ});
6832 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6833 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6834 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6845 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6847 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6853 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6855 unsigned PreferredFusedOpcode =
6856 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6867 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6868 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6880 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6893 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6895 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6901 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6903 unsigned PreferredFusedOpcode =
6904 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6916 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6917 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6918 {FpExtX, FpExtY, NegZ});
6930 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6933 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6934 {NegY, FpExtZ, LHSReg});
6945 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6947 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6951 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6952 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6956 unsigned PreferredFusedOpcode =
6957 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6961 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6962 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6963 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6974 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6977 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6980 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6990 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
7003 unsigned &IdxToPropagate)
const {
7005 switch (
MI.getOpcode()) {
7008 case TargetOpcode::G_FMINNUM:
7009 case TargetOpcode::G_FMAXNUM:
7010 PropagateNaN =
false;
7012 case TargetOpcode::G_FMINIMUM:
7013 case TargetOpcode::G_FMAXIMUM:
7014 PropagateNaN =
true;
7018 auto MatchNaN = [&](
unsigned Idx) {
7019 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
7023 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
7027 return MatchNaN(1) || MatchNaN(2);
7035 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
7045 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
7062 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
7063 if (&U == &
MI || U.getParent() !=
MI.getParent())
7065 if (U.getOpcode() == TargetOpcode::G_FDIV &&
7066 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
7067 !IsOne(U.getOperand(1).getReg())) {
7080 return MatchInfo.
size() >= MinUses;
7088 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7089 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7090 MatchInfo[0]->getOperand(2).getReg(),
7091 MatchInfo[0]->getFlags());
7096 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7097 Div->getOperand(0).getReg(),
MI->getFlags());
7098 MI->eraseFromParent();
7103 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7113 Reg == MaybeSameReg;
7115 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7136 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7145 return MRI.getType(MatchInfo) == DstVecTy;
7148 std::optional<ValueAndVReg> ShiftAmount;
7157 return MRI.getType(MatchInfo) == DstVecTy;
7172 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7179 std::optional<ValueAndVReg> ShiftAmt;
7185 LLT MatchTy =
MRI.getType(MatchInfo);
7186 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7187 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7190unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7192 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7193 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7194 "Expected a NaN behaviour?");
7204 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7205 return TargetOpcode::G_FMAXNUM;
7206 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7207 return TargetOpcode::G_FMAXIMUM;
7208 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7209 return TargetOpcode::G_FMAXNUM;
7210 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7211 return TargetOpcode::G_FMAXIMUM;
7217 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7218 return TargetOpcode::G_FMINNUM;
7219 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7220 return TargetOpcode::G_FMINIMUM;
7221 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7222 return TargetOpcode::G_FMINNUM;
7223 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7225 return TargetOpcode::G_FMINIMUM;
7229CombinerHelper::SelectPatternNaNBehaviour
7231 bool IsOrderedComparison)
const {
7232 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7233 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7235 if (!LHSSafe && !RHSSafe)
7236 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7237 if (LHSSafe && RHSSafe)
7238 return SelectPatternNaNBehaviour::RETURNS_ANY;
7241 if (IsOrderedComparison)
7242 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7243 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7246 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7247 : SelectPatternNaNBehaviour::RETURNS_NAN;
7256 LLT DstTy =
MRI.getType(Dst);
7269 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7271 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7273 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7276 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7277 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7278 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7279 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7281 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7284 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7289 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7294 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7296 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7300 MatchInfo = [=](MachineIRBuilder &
B) {
7301 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7309 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7316 Register TrueVal =
MI.getOperand(2).getReg();
7317 Register FalseVal =
MI.getOperand(3).getReg();
7318 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7323 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7336 if (MatchedSub &&
X != OpLHS)
7344 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7347 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7348 B.buildICmp(Pred, Dst,
Y, Zero);
7355static std::optional<unsigned>
7357 std::optional<int64_t> &Result) {
7358 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7359 Opcode == TargetOpcode::G_ASHR) &&
7360 "Expect G_SHL, G_LSHR or G_ASHR.");
7361 auto SignificantBits = 0;
7363 case TargetOpcode::G_SHL:
7367 case TargetOpcode::G_LSHR:
7371 case TargetOpcode::G_ASHR:
7380 Result = std::nullopt;
7391 Register ShiftVal =
MI.getOperand(1).getReg();
7392 Register ShiftReg =
MI.getOperand(2).getReg();
7393 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7394 auto IsShiftTooBig = [&](
const Constant *
C) {
7399 MatchInfo = std::nullopt;
7403 MI.getOpcode(), MatchInfo);
7404 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7410 unsigned LHSOpndIdx = 1;
7411 unsigned RHSOpndIdx = 2;
7412 switch (
MI.getOpcode()) {
7413 case TargetOpcode::G_UADDO:
7414 case TargetOpcode::G_SADDO:
7415 case TargetOpcode::G_UMULO:
7416 case TargetOpcode::G_SMULO:
7423 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7424 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7429 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7430 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7434 return MRI.getVRegDef(RHS)->getOpcode() !=
7435 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7442 std::optional<FPValueAndVReg> ValAndVReg;
7450 unsigned LHSOpndIdx = 1;
7451 unsigned RHSOpndIdx = 2;
7452 switch (
MI.getOpcode()) {
7453 case TargetOpcode::G_UADDO:
7454 case TargetOpcode::G_SADDO:
7455 case TargetOpcode::G_UMULO:
7456 case TargetOpcode::G_SMULO:
7463 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7464 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7465 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7466 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7470bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7472 if (SrcTy.isFixedVector())
7474 if (SrcTy.isScalar()) {
7478 return IConstant && IConstant->Value == 1;
7483bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7484 LLT SrcTy =
MRI.getType(Src);
7486 return isConstantSplatVector(Src, 0, AllowUndefs);
7491 return IConstant && IConstant->Value == 0;
7498bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7499 bool AllowUndefs)
const {
7505 for (
unsigned I = 0;
I < NumSources; ++
I) {
7506 GImplicitDef *ImplicitDef =
7508 if (ImplicitDef && AllowUndefs)
7510 if (ImplicitDef && !AllowUndefs)
7512 std::optional<ValueAndVReg> IConstant =
7514 if (IConstant && IConstant->Value == SplatValue)
7524CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7527 return IConstant->Value;
7531 return std::nullopt;
7534 std::optional<APInt>
Value = std::nullopt;
7535 for (
unsigned I = 0;
I < NumSources; ++
I) {
7536 std::optional<ValueAndVReg> IConstant =
7539 return std::nullopt;
7541 Value = IConstant->Value;
7542 else if (*
Value != IConstant->Value)
7543 return std::nullopt;
7549bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7559 for (
unsigned I = 0;
I < NumSources; ++
I) {
7560 std::optional<ValueAndVReg> IConstant =
7569bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7576 LLT CondTy =
MRI.getType(
Select->getCondReg());
7577 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7587 std::optional<ValueAndVReg> TrueOpt =
7589 std::optional<ValueAndVReg> FalseOpt =
7592 if (!TrueOpt || !FalseOpt)
7595 APInt TrueValue = TrueOpt->Value;
7596 APInt FalseValue = FalseOpt->Value;
7600 MatchInfo = [=](MachineIRBuilder &
B) {
7601 B.setInstrAndDebugLoc(*
Select);
7602 B.buildZExtOrTrunc(Dest,
Cond);
7609 MatchInfo = [=](MachineIRBuilder &
B) {
7610 B.setInstrAndDebugLoc(*
Select);
7611 B.buildSExtOrTrunc(Dest,
Cond);
7618 MatchInfo = [=](MachineIRBuilder &
B) {
7619 B.setInstrAndDebugLoc(*
Select);
7620 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7621 B.buildNot(Inner,
Cond);
7622 B.buildZExtOrTrunc(Dest, Inner);
7629 MatchInfo = [=](MachineIRBuilder &
B) {
7630 B.setInstrAndDebugLoc(*
Select);
7631 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7632 B.buildNot(Inner,
Cond);
7633 B.buildSExtOrTrunc(Dest, Inner);
7639 if (TrueValue - 1 == FalseValue) {
7640 MatchInfo = [=](MachineIRBuilder &
B) {
7641 B.setInstrAndDebugLoc(*
Select);
7642 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7643 B.buildZExtOrTrunc(Inner,
Cond);
7644 B.buildAdd(Dest, Inner, False);
7650 if (TrueValue + 1 == FalseValue) {
7651 MatchInfo = [=](MachineIRBuilder &
B) {
7652 B.setInstrAndDebugLoc(*
Select);
7653 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7654 B.buildSExtOrTrunc(Inner,
Cond);
7655 B.buildAdd(Dest, Inner, False);
7662 MatchInfo = [=](MachineIRBuilder &
B) {
7663 B.setInstrAndDebugLoc(*
Select);
7664 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7665 B.buildZExtOrTrunc(Inner,
Cond);
7668 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7669 B.buildShl(Dest, Inner, ShAmtC, Flags);
7676 MatchInfo = [=](MachineIRBuilder &
B) {
7677 B.setInstrAndDebugLoc(*
Select);
7679 B.buildNot(Not,
Cond);
7680 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7681 B.buildZExtOrTrunc(Inner, Not);
7684 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7685 B.buildShl(Dest, Inner, ShAmtC, Flags);
7692 MatchInfo = [=](MachineIRBuilder &
B) {
7693 B.setInstrAndDebugLoc(*
Select);
7694 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7695 B.buildSExtOrTrunc(Inner,
Cond);
7696 B.buildOr(Dest, Inner, False, Flags);
7703 MatchInfo = [=](MachineIRBuilder &
B) {
7704 B.setInstrAndDebugLoc(*
Select);
7706 B.buildNot(Not,
Cond);
7707 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7708 B.buildSExtOrTrunc(Inner, Not);
7709 B.buildOr(Dest, Inner, True, Flags);
7718bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7725 LLT CondTy =
MRI.getType(
Select->getCondReg());
7726 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7735 if (CondTy != TrueTy)
7740 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7741 MatchInfo = [=](MachineIRBuilder &
B) {
7742 B.setInstrAndDebugLoc(*
Select);
7743 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7744 B.buildZExtOrTrunc(Ext,
Cond);
7745 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7746 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7753 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7754 MatchInfo = [=](MachineIRBuilder &
B) {
7755 B.setInstrAndDebugLoc(*
Select);
7756 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7757 B.buildZExtOrTrunc(Ext,
Cond);
7758 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7759 B.buildAnd(DstReg, Ext, FreezeTrue);
7765 if (isOneOrOneSplat(False,
true)) {
7766 MatchInfo = [=](MachineIRBuilder &
B) {
7767 B.setInstrAndDebugLoc(*
Select);
7769 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7770 B.buildNot(Inner,
Cond);
7772 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7773 B.buildZExtOrTrunc(Ext, Inner);
7774 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7775 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7781 if (isZeroOrZeroSplat(True,
true)) {
7782 MatchInfo = [=](MachineIRBuilder &
B) {
7783 B.setInstrAndDebugLoc(*
Select);
7785 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7786 B.buildNot(Inner,
Cond);
7788 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7789 B.buildZExtOrTrunc(Ext, Inner);
7790 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7791 B.buildAnd(DstReg, Ext, FreezeFalse);
7807 LLT DstTy =
MRI.getType(DstReg);
7813 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7822 Register CmpLHS = Cmp->getLHSReg();
7823 Register CmpRHS = Cmp->getRHSReg();
7826 if (True == CmpRHS && False == CmpLHS) {
7834 if (True != CmpLHS || False != CmpRHS)
7874 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7875 Register DestReg =
MI.getOperand(0).getReg();
7876 LLT DestTy =
MRI.getType(DestReg);
7888 if (
isLegal({NewOpc, {DestTy}})) {
7890 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7902 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7905 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7915bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7917 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7918 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7922 unsigned Flags = Logic->
getFlags();
7941 std::optional<ValueAndVReg> MaybeC1 =
7945 C1 = MaybeC1->Value;
7947 std::optional<ValueAndVReg> MaybeC2 =
7951 C2 = MaybeC2->Value;
7972 std::optional<APInt> Offset1;
7973 std::optional<APInt> Offset2;
7976 std::optional<ValueAndVReg> MaybeOffset1 =
7979 R1 =
Add->getLHSReg();
7980 Offset1 = MaybeOffset1->Value;
7984 std::optional<ValueAndVReg> MaybeOffset2 =
7987 R2 =
Add->getLHSReg();
7988 Offset2 = MaybeOffset2->Value;
8007 bool CreateMask =
false;
8020 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
8033 CR->getEquivalentICmp(NewPred, NewC,
Offset);
8042 MatchInfo = [=](MachineIRBuilder &
B) {
8043 if (CreateMask &&
Offset != 0) {
8044 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8045 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8046 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8047 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
8048 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8049 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8050 B.buildZExtOrTrunc(DstReg, ICmp);
8051 }
else if (CreateMask &&
Offset == 0) {
8052 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8053 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8054 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8055 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
8056 B.buildZExtOrTrunc(DstReg, ICmp);
8057 }
else if (!CreateMask &&
Offset != 0) {
8058 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8059 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
8060 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8061 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8062 B.buildZExtOrTrunc(DstReg, ICmp);
8063 }
else if (!CreateMask &&
Offset == 0) {
8064 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8065 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
8066 B.buildZExtOrTrunc(DstReg, ICmp);
8074bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
8080 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8092 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8098 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8099 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8100 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8101 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8112 if (LHS0 == RHS1 && LHS1 == RHS0) {
8118 if (LHS0 == RHS0 && LHS1 == RHS1) {
8122 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8124 MatchInfo = [=](MachineIRBuilder &
B) {
8129 auto False =
B.buildConstant(CmpTy, 0);
8130 B.buildZExtOrTrunc(DestReg, False);
8137 B.buildZExtOrTrunc(DestReg, True);
8139 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8140 B.buildZExtOrTrunc(DestReg, Cmp);
8152 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8155 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8164 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8167 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8182 bool IsSigned =
Add->isSigned();
8183 LLT DstTy =
MRI.getType(Dst);
8184 LLT CarryTy =
MRI.getType(Carry);
8187 if (
MRI.use_nodbg_empty(Carry) &&
8190 B.buildAdd(Dst, LHS, RHS);
8191 B.buildUndef(Carry);
8197 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8200 B.buildSAddo(Dst, Carry, RHS, LHS);
8206 B.buildUAddo(Dst, Carry, RHS, LHS);
8211 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8212 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8218 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8219 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8221 B.buildConstant(Dst, Result);
8222 B.buildConstant(Carry, Overflow);
8230 B.buildCopy(Dst, LHS);
8231 B.buildConstant(Carry, 0);
8240 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8243 std::optional<APInt> MaybeAddRHS =
8244 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8247 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8248 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8252 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8253 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8259 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8260 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8285 B.buildConstant(Carry, 0);
8292 B.buildAdd(Dst, LHS, RHS);
8293 B.buildConstant(Carry, 1);
8305 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8308 B.buildConstant(Carry, 0);
8324 B.buildConstant(Carry, 0);
8331 B.buildAdd(Dst, LHS, RHS);
8332 B.buildConstant(Carry, 1);
8350 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8356 auto [Dst,
Base] =
MI.getFirst2Regs();
8357 LLT Ty =
MRI.getType(Dst);
8361 Builder.buildFConstant(Dst, 1.0);
8362 MI.removeFromParent();
8374 std::optional<SrcOp> Res;
8376 while (ExpVal > 0) {
8381 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8384 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8391 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8395 MI.eraseFromParent();
8404 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8411 LLT DstTy =
MRI.getType(Dst);
8414 auto Const =
B.buildConstant(DstTy, C1 - C2);
8415 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8427 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8434 LLT DstTy =
MRI.getType(Dst);
8437 auto Const =
B.buildConstant(DstTy, C2 - C1);
8438 B.buildSub(Dst, Const,
Add->getLHSReg());
8450 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8457 LLT DstTy =
MRI.getType(Dst);
8460 auto Const =
B.buildConstant(DstTy, C1 + C2);
8473 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8480 LLT DstTy =
MRI.getType(Dst);
8483 auto Const =
B.buildConstant(DstTy, C1 - C2);
8496 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8503 LLT DstTy =
MRI.getType(Dst);
8506 auto Const =
B.buildConstant(DstTy, C2 - C1);
8507 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8554 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8558 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8561 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8562 LLT SmallBvTy = DstTy;
8566 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8571 {TargetOpcode::G_ANYEXT,
8583 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8584 Ops.push_back(AnyExt.getReg(0));
8602 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8603 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8604 const unsigned NumDstElts = OrigMask.
size();
8605 for (
unsigned i = 0; i != NumDstElts; ++i) {
8606 int Idx = OrigMask[i];
8607 if (Idx >= (
int)NumSrcElems) {
8618 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8619 std::move(NewMask));
8626 const unsigned MaskSize = Mask.size();
8627 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8632 if (Idx < (
int)NumElems)
8633 Mask[
I] = Idx + NumElems;
8635 Mask[
I] = Idx - NumElems;
8645 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8648 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8651 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8652 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8654 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8658 const unsigned NumSrcElems = Src1Ty.getNumElements();
8660 bool TouchesSrc1 =
false;
8661 bool TouchesSrc2 =
false;
8662 const unsigned NumElems = Mask.size();
8663 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8667 if (Mask[Idx] < (
int)NumSrcElems)
8673 if (TouchesSrc1 == TouchesSrc2)
8676 Register NewSrc1 = Shuffle.getSrc1Reg();
8679 NewSrc1 = Shuffle.getSrc2Reg();
8684 auto Undef =
B.buildUndef(Src1Ty);
8685 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8699 LLT DstTy =
MRI.getType(Dst);
8700 LLT CarryTy =
MRI.getType(Carry);
8722 B.buildConstant(Carry, 0);
8729 B.buildSub(Dst, LHS, RHS);
8747 B.buildConstant(Carry, 0);
8754 B.buildSub(Dst, LHS, RHS);
8771 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8772 "Expected G_CTLZ variant");
8777 LLT Ty =
MRI.getType(Dst);
8778 LLT SrcTy =
MRI.getType(Src);
8780 if (!(Ty.isValid() && Ty.isScalar()))
8789 switch (
LI->getAction(Query).Action) {
8800 bool NeedAdd =
true;
8808 unsigned BitWidth = Ty.getScalarSizeInBits();
8819 B.buildCTLS(Dst,
X);
8823 auto Ctls =
B.buildCTLS(Ty,
X);
8824 auto One =
B.buildConstant(Ty, 1);
8826 B.buildAdd(Dst, Ctls, One);
8836 unsigned TargetOpc)
const {
8837 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8838 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8839 "Expected G_LSHR/G_ASHR");
8842 return XTy ==
MRI.getType(
Y) &&
isLegal({TargetOpc, {XTy}});
8846 assert((
MI.getOpcode() == TargetOpcode::G_CTLZ ||
8847 MI.getOpcode() == TargetOpcode::G_CTTZ) &&
8848 "Expected count-zero opcode");
8849 switch (
MI.getOpcode()) {
8850 case TargetOpcode::G_CTLZ:
8851 return TargetOpcode::G_CTLZ_ZERO_POISON;
8852 case TargetOpcode::G_CTTZ:
8853 return TargetOpcode::G_CTTZ_ZERO_POISON;
8865 if (!
VT->isKnownNeverZero(Src))
8868 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8869 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)
MachineInstr unsigned OpIdx
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)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool 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
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
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.
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.
bool isSimple() const
Returns true if the memory operation is neither atomic or volatile.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
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
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
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.
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
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.
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
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.
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.
LLVM_ABI std::optional< int64_t > getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
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...