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();
259 if (!
MRI.hasOneNonDBGUse(OrigOp))
278 std::optional<MachineOperand> MaybePoisonOperand;
280 if (!Operand.isReg())
286 if (!MaybePoisonOperand)
287 MaybePoisonOperand = Operand;
296 if (!MaybePoisonOperand) {
301 B.buildCopy(
DstOp, OrigOp);
306 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
307 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
314 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
325 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
326 "Invalid instruction");
336 assert(Def &&
"Operand not defined");
337 if (!
MRI.hasOneNonDBGUse(Reg))
339 switch (Def->getOpcode()) {
340 case TargetOpcode::G_BUILD_VECTOR:
345 Ops.push_back(BuildVecMO.getReg());
347 case TargetOpcode::G_IMPLICIT_DEF: {
348 LLT OpType =
MRI.getType(Reg);
355 OpType.getScalarType() &&
356 "All undefs should have the same type");
359 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
360 EltIdx != EltEnd; ++EltIdx)
361 Ops.push_back(
Undef->getOperand(0).getReg());
370 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
372 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
387 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
400 MI.eraseFromParent();
409 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
412 if (BC->
getOpcode() != TargetOpcode::G_BITCAST)
416 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
421 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
425 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
429 if (Src->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
438 if (BC->
getOpcode() != TargetOpcode::G_BITCAST ||
462 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
463 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
464 MI.eraseFromParent();
470 Register SrcVec1 = Shuffle.getSrc1Reg();
471 Register SrcVec2 = Shuffle.getSrc2Reg();
472 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
473 int Width =
MRI.getType(SrcVec1).getNumElements();
475 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
476 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
480 for (
int Val : Shuffle.getMask()) {
483 else if (Val < Width)
484 Extracts.
push_back(Unmerge1.getReg(Val));
486 Extracts.
push_back(Unmerge2.getReg(Val - Width));
488 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
489 if (Extracts.
size() == 1)
490 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
492 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
493 MI.eraseFromParent();
503 if (!ConcatMI1 || !ConcatMI2)
507 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
508 MRI.getType(ConcatMI2->getSourceReg(0)))
511 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
512 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
514 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
518 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
519 if (i + j >= Mask.size())
521 if (Mask[i + j] != -1)
525 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
528 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
529 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
530 if (i + j >= Mask.size())
532 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
538 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
540 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
541 ConcatMI1->getNumSources()));
549 {TargetOpcode::G_CONCAT_VECTORS,
550 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
561 SrcTy =
MRI.getType(Reg);
563 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
570 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
576 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
579 MI.eraseFromParent();
584 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
585 "Invalid instruction kind");
586 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
588 LLT SrcType =
MRI.getType(Src1);
590 unsigned DstNumElts = DstType.getNumElements();
591 unsigned SrcNumElts = SrcType.getNumElements();
608 if (DstNumElts < 2 * SrcNumElts)
613 if (DstNumElts % SrcNumElts != 0)
619 unsigned NumConcat = DstNumElts / SrcNumElts;
622 for (
unsigned i = 0; i != DstNumElts; ++i) {
629 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
630 (ConcatSrcs[i / SrcNumElts] >= 0 &&
631 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
634 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
641 for (
auto Src : ConcatSrcs) {
645 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
647 Ops.push_back(UndefReg);
660 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
668 MI.eraseFromParent();
677 const LLT TyForCandidate,
678 unsigned OpcodeForCandidate,
683 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
694 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
697 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
698 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
699 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
707 OpcodeForCandidate == TargetOpcode::G_ZEXT)
709 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
710 OpcodeForCandidate == TargetOpcode::G_SEXT)
711 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
720 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
731static void InsertInsnsWithoutSideEffectsBeforeUse(
743 InsertBB = PredBB->
getMBB();
748 if (InsertBB ==
DefMI.getParent()) {
750 Inserter(InsertBB, std::next(InsertPt), UseMO);
769 unsigned CandidateLoadOpc;
771 case TargetOpcode::G_ANYEXT:
772 CandidateLoadOpc = TargetOpcode::G_LOAD;
774 case TargetOpcode::G_SEXT:
775 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
777 case TargetOpcode::G_ZEXT:
778 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
783 return CandidateLoadOpc;
800 LLT LoadValueTy =
MRI.getType(LoadReg);
822 unsigned PreferredOpcode =
824 ? TargetOpcode::G_ANYEXT
826 Preferred = {
LLT(), PreferredOpcode,
nullptr};
827 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
828 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
829 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
830 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
831 const auto &MMO = LoadMI->
getMMO();
839 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
841 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
845 Preferred = ChoosePreferredUse(
MI, Preferred,
846 MRI.getType(
UseMI.getOperand(0).getReg()),
856 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
874 if (PreviouslyEmitted) {
881 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
882 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
884 EmittedInsns[InsertIntoBB] = NewMI;
890 MI.setDesc(
Builder.getTII().get(LoadOpc));
897 for (
auto *UseMO :
Uses) {
903 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
906 const LLT UseDstTy =
MRI.getType(UseDstReg);
907 if (UseDstReg != ChosenDstReg) {
908 if (Preferred.
Ty == UseDstTy) {
945 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
960 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
963 MI.getOperand(0).setReg(ChosenDstReg);
969 assert(
MI.getOpcode() == TargetOpcode::G_AND);
980 if (
MRI.getType(Dst).isVector())
988 APInt MaskVal = MaybeMask->Value;
997 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
1001 LLT RegTy =
MRI.getType(LoadReg);
1005 unsigned MaskSizeBits = MaskVal.
countr_one();
1009 if (MaskSizeBits > LoadSizeBits.
getValue())
1029 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
1035 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1039 B.setInstrAndDebugLoc(*LoadMI);
1040 auto &MF =
B.getMF();
1042 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
1043 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1052 "shouldn't consider debug uses");
1060 if (DefOrUse ==
MBB.end())
1062 return &*DefOrUse == &
DefMI;
1068 "shouldn't consider debug uses");
1071 else if (
DefMI.getParent() !=
UseMI.getParent())
1078 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1082 if (
MRI.getType(SrcReg).isVector())
1087 LoadUser = TruncSrc;
1089 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1094 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1096 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1098 if (LoadSizeBits == SizeInBits)
1105 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1106 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1107 MI.eraseFromParent();
1111 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1112 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1115 LLT RegTy =
MRI.getType(DstReg);
1123 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1126 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1131 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1134 if (NewSizeBits < 8)
1146 if (LoadDef->isSimple())
1148 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1153 {
MRI.getType(LoadDef->getDstReg()),
1154 MRI.getType(LoadDef->getPointerReg())},
1158 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1163 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1164 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1166 unsigned ScalarSizeBits;
1167 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1176 auto &MMO = LoadDef->
getMMO();
1177 Builder.setInstrAndDebugLoc(*LoadDef);
1179 auto PtrInfo = MMO.getPointerInfo();
1180 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1181 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1183 MI.eraseFromParent();
1194 auto *MF =
MI->getMF();
1201 AM.
BaseOffs = CstOff->getSExtValue();
1206 MF->getDataLayout(), AM,
1208 MF->getFunction().getContext()),
1209 MI->getMMO().getAddrSpace());
1214 case TargetOpcode::G_LOAD:
1215 return TargetOpcode::G_INDEXED_LOAD;
1216 case TargetOpcode::G_STORE:
1217 return TargetOpcode::G_INDEXED_STORE;
1218 case TargetOpcode::G_ZEXTLOAD:
1219 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1220 case TargetOpcode::G_SEXTLOAD:
1221 return TargetOpcode::G_INDEXED_SEXTLOAD;
1227bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1237 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1238 OpTys = {PtrTy, Ty, Ty};
1240 OpTys = {Ty, PtrTy};
1242 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1248 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1249 "considered for post-indexing."));
1253 bool &RematOffset)
const {
1266 if (!isIndexedLoadStoreLegal(LdSt))
1275 unsigned NumUsesChecked = 0;
1288 if (StoredValDef == &
Use)
1291 Offset = PtrAdd->getOffsetReg();
1293 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1299 RematOffset =
false;
1303 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1308 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1309 if (&BasePtrUse == PtrDef)
1315 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1317 isIndexedLoadStoreLegal(*BasePtrLdSt))
1323 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1324 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1327 if (BaseUseUse.getParent() != LdSt.
getParent())
1339 Addr = PtrAdd->getReg(0);
1340 Base = PtrAdd->getBaseReg();
1355 MRI.hasOneNonDBGUse(Addr))
1362 if (!isIndexedLoadStoreLegal(LdSt))
1366 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1371 if (
Base == St->getValueReg())
1376 if (St->getValueReg() == Addr)
1381 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1382 if (AddrUse.getParent() != LdSt.
getParent())
1387 bool RealUse =
false;
1388 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1406 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1416 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1423 if (!LoadMI->isSimple())
1435 const unsigned MaxIter = 20;
1438 if (
II->isLoadFoldBarrier())
1440 if (Iter++ == MaxIter)
1456 int Elt = CVal->getZExtValue();
1469 Register VecPtr = LoadMI->getPointerReg();
1470 LLT PtrTy =
MRI.getType(VecPtr);
1478 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1501 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1516 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1518 if (!MatchInfo.
IsPre &&
1519 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1529 unsigned Opcode =
MI.getOpcode();
1530 bool IsStore = Opcode == TargetOpcode::G_STORE;
1536 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1538 *OldCst->getOperand(1).getCImm());
1539 MatchInfo.
Offset = NewCst.getReg(0);
1542 auto MIB =
Builder.buildInstr(NewOpcode);
1544 MIB.addDef(MatchInfo.
Addr);
1545 MIB.addUse(
MI.getOperand(0).getReg());
1547 MIB.addDef(
MI.getOperand(0).getReg());
1548 MIB.addDef(MatchInfo.
Addr);
1551 MIB.addUse(MatchInfo.
Base);
1552 MIB.addUse(MatchInfo.
Offset);
1553 MIB.addImm(MatchInfo.
IsPre);
1554 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1555 MI.eraseFromParent();
1563 unsigned Opcode =
MI.getOpcode();
1564 bool IsDiv, IsSigned;
1569 case TargetOpcode::G_SDIV:
1570 case TargetOpcode::G_UDIV: {
1572 IsSigned = Opcode == TargetOpcode::G_SDIV;
1575 case TargetOpcode::G_SREM:
1576 case TargetOpcode::G_UREM: {
1578 IsSigned = Opcode == TargetOpcode::G_SREM;
1584 unsigned DivOpcode, RemOpcode, DivremOpcode;
1586 DivOpcode = TargetOpcode::G_SDIV;
1587 RemOpcode = TargetOpcode::G_SREM;
1588 DivremOpcode = TargetOpcode::G_SDIVREM;
1590 DivOpcode = TargetOpcode::G_UDIV;
1591 RemOpcode = TargetOpcode::G_UREM;
1592 DivremOpcode = TargetOpcode::G_UDIVREM;
1610 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1611 if (
MI.getParent() ==
UseMI.getParent() &&
1612 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1613 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1626 unsigned Opcode =
MI.getOpcode();
1627 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1630 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1631 DestDivReg =
MI.getOperand(0).getReg();
1635 DestRemReg =
MI.getOperand(0).getReg();
1639 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1646 Builder.setInstrAndDebugLoc(*FirstInst);
1648 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1649 : TargetOpcode::G_UDIVREM,
1650 {DestDivReg, DestRemReg},
1652 MI.eraseFromParent();
1658 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1675 if (BrIt ==
MBB->begin())
1677 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1679 BrCond = &*std::prev(BrIt);
1680 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1686 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1687 MBB->isLayoutSuccessor(BrCondTarget);
1693 Builder.setInstrAndDebugLoc(*BrCond);
1698 auto True =
Builder.buildConstant(
1704 MI.getOperand(0).setMBB(FallthroughBB);
1719 return Helper.lowerMemcpyInline(
MI) ==
1724 unsigned MaxLen)
const {
1736 switch (
MI.getOpcode()) {
1739 case TargetOpcode::G_FNEG: {
1740 Result.changeSign();
1743 case TargetOpcode::G_FABS: {
1747 case TargetOpcode::G_FCEIL:
1750 case TargetOpcode::G_FFLOOR:
1753 case TargetOpcode::G_INTRINSIC_TRUNC:
1756 case TargetOpcode::G_INTRINSIC_ROUND:
1759 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1762 case TargetOpcode::G_FRINT:
1763 case TargetOpcode::G_FNEARBYINT:
1767 case TargetOpcode::G_FPEXT:
1768 case TargetOpcode::G_FPTRUNC: {
1775 case TargetOpcode::G_FSQRT: {
1779 Result =
APFloat(sqrt(Result.convertToDouble()));
1782 case TargetOpcode::G_FLOG2: {
1802 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1803 MI.eraseFromParent();
1814 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1824 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1837 Type *AccessTy =
nullptr;
1838 auto &MF = *
MI.getMF();
1839 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1842 MF.getFunction().getContext());
1847 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1852 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1854 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1855 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1856 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1857 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1866 unsigned PtrAddFlags =
MI.getFlags();
1867 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1883 MatchInfo.
Flags = Flags;
1889 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1891 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1895 MI.getOperand(1).setReg(MatchInfo.
Base);
1896 MI.getOperand(2).setReg(NewOffset.getReg(0));
1910 unsigned Opcode =
MI.getOpcode();
1911 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1912 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1913 Opcode == TargetOpcode::G_USHLSAT) &&
1914 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1934 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1939 if (Opcode == TargetOpcode::G_USHLSAT &&
1940 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1948 unsigned Opcode =
MI.getOpcode();
1949 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1950 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1951 Opcode == TargetOpcode::G_USHLSAT) &&
1952 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1954 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1955 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1956 auto Imm = MatchInfo.
Imm;
1958 if (Imm >= ScalarSizeInBits) {
1960 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1961 Builder.buildConstant(
MI.getOperand(0), 0);
1962 MI.eraseFromParent();
1967 Imm = ScalarSizeInBits - 1;
1970 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1973 MI.getOperand(1).setReg(MatchInfo.
Reg);
1974 MI.getOperand(2).setReg(NewImm);
1990 unsigned ShiftOpcode =
MI.getOpcode();
1991 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1992 ShiftOpcode == TargetOpcode::G_ASHR ||
1993 ShiftOpcode == TargetOpcode::G_LSHR ||
1994 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1995 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1996 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1999 Register LogicDest =
MI.getOperand(1).getReg();
2000 if (!
MRI.hasOneNonDBGUse(LogicDest))
2004 unsigned LogicOpcode = LogicMI->
getOpcode();
2005 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2006 LogicOpcode != TargetOpcode::G_XOR)
2010 const Register C1 =
MI.getOperand(2).getReg();
2012 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2015 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2019 if (
MI->getOpcode() != ShiftOpcode ||
2020 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2029 ShiftVal = MaybeImmVal->Value.getSExtValue();
2040 if (matchFirstShift(LogicMIOp1, C0Val)) {
2042 MatchInfo.
Shift2 = LogicMIOp1;
2043 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2045 MatchInfo.
Shift2 = LogicMIOp2;
2049 MatchInfo.
ValSum = C0Val + C1Val;
2052 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2055 MatchInfo.
Logic = LogicMI;
2061 unsigned Opcode =
MI.getOpcode();
2062 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2063 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2064 Opcode == TargetOpcode::G_SSHLSAT) &&
2065 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2067 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2068 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2074 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2083 Register Shift2Const =
MI.getOperand(2).getReg();
2085 .buildInstr(Opcode, {DestType},
2095 MI.eraseFromParent();
2100 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2122 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2123 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2124 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2125 LLT SrcTy =
MRI.getType(SrcReg);
2127 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2128 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2129 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2137 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2141 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2156 LLT InnerShiftTy =
MRI.getType(InnerShift);
2158 if ((N1C + N001C).ult(InnerShiftSize)) {
2164 if ((N001C + OpSizeInBits) == InnerShiftSize)
2166 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2167 MatchInfo.
Mask =
true;
2177 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2184 if (MatchInfo.
Mask ==
true) {
2192 Builder.buildTrunc(Dst, Shift);
2193 MI.eraseFromParent();
2197 unsigned &ShiftVal)
const {
2198 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2204 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2205 return (
static_cast<int32_t
>(ShiftVal) != -1);
2209 unsigned &ShiftVal)
const {
2210 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2212 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2215 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2216 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2237 auto NegCst =
B.buildConstant(Ty, -Imm);
2239 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2240 MI.getOperand(2).setReg(NegCst.getReg(0));
2242 if (Imm.isMinSignedValue())
2252 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2267 if (!MaybeShiftAmtVal)
2271 LLT SrcTy =
MRI.getType(ExtSrc);
2281 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2282 MatchData.
Reg = ExtSrc;
2283 MatchData.
Imm = ShiftAmt;
2285 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2286 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2287 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2293 int64_t ShiftAmtVal = MatchData.
Imm;
2295 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2296 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2298 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2299 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2300 MI.eraseFromParent();
2307 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2311 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2314 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2315 if (MergedValues[
I] != Unmerge->getReg(
I))
2318 MatchInfo = Unmerge->getSourceReg();
2332 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2333 "Expected an unmerge");
2342 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2343 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2345 if (SrcMergeTy != Dst0Ty && !SameSize)
2349 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2350 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2356 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2357 "Expected an unmerge");
2359 "Not enough operands to replace all defs");
2360 unsigned NumElems =
MI.getNumOperands() - 1;
2362 LLT SrcTy =
MRI.getType(Operands[0]);
2363 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2364 bool CanReuseInputDirectly = DstTy == SrcTy;
2365 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2366 Register DstReg =
MI.getOperand(Idx).getReg();
2371 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2372 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2373 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2374 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2377 if (CanReuseInputDirectly)
2380 Builder.buildCast(DstReg, SrcReg);
2382 MI.eraseFromParent();
2387 unsigned SrcIdx =
MI.getNumOperands() - 1;
2388 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2390 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2391 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2399 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2402 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2404 Val = Val.
lshr(ShiftAmt);
2412 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2413 "Expected an unmerge");
2415 "Not enough operands to replace all defs");
2416 unsigned NumElems =
MI.getNumOperands() - 1;
2417 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2418 Register DstReg =
MI.getOperand(Idx).getReg();
2419 Builder.buildConstant(DstReg, Csts[Idx]);
2422 MI.eraseFromParent();
2428 unsigned SrcIdx =
MI.getNumOperands() - 1;
2429 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2431 unsigned NumElems =
MI.getNumOperands() - 1;
2432 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2433 Register DstReg =
MI.getOperand(Idx).getReg();
2434 B.buildUndef(DstReg);
2442 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2443 "Expected an unmerge");
2444 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2445 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2448 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2449 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2457 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2458 Register Dst0Reg =
MI.getOperand(0).getReg();
2459 Builder.buildTrunc(Dst0Reg, SrcReg);
2460 MI.eraseFromParent();
2464 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2465 "Expected an unmerge");
2466 Register Dst0Reg =
MI.getOperand(0).getReg();
2467 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2473 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2474 LLT SrcTy =
MRI.getType(SrcReg);
2475 if (SrcTy.isVector())
2485 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2490 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2491 "Expected an unmerge");
2493 Register Dst0Reg =
MI.getOperand(0).getReg();
2496 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2498 "Expecting a G_ZEXT");
2501 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2502 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2505 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2508 "ZExt src doesn't fit in destination");
2513 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2515 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2518 MI.eraseFromParent();
2522 unsigned TargetShiftSize,
2523 unsigned &ShiftVal)
const {
2524 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2525 MI.getOpcode() == TargetOpcode::G_LSHR ||
2526 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2528 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2533 unsigned Size = Ty.getSizeInBits();
2534 if (
Size <= TargetShiftSize)
2542 ShiftVal = MaybeImmVal->Value.getSExtValue();
2543 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2550 LLT Ty =
MRI.getType(SrcReg);
2551 unsigned Size = Ty.getSizeInBits();
2552 unsigned HalfSize =
Size / 2;
2553 assert(ShiftVal >= HalfSize);
2557 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2558 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2560 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2561 Register Narrowed = Unmerge.getReg(1);
2568 if (NarrowShiftAmt != 0) {
2569 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2570 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2573 auto Zero =
Builder.buildConstant(HalfTy, 0);
2574 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2575 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2576 Register Narrowed = Unmerge.getReg(0);
2581 if (NarrowShiftAmt != 0) {
2582 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2583 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2586 auto Zero =
Builder.buildConstant(HalfTy, 0);
2587 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2589 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2591 HalfTy, Unmerge.getReg(1),
2592 Builder.buildConstant(HalfTy, HalfSize - 1));
2594 if (ShiftVal == HalfSize) {
2597 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2598 }
else if (ShiftVal ==
Size - 1) {
2606 HalfTy, Unmerge.getReg(1),
2607 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2615 MI.eraseFromParent();
2631 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2633 LLT DstTy =
MRI.getType(DstReg);
2641 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2643 Builder.buildCopy(DstReg, Reg);
2644 MI.eraseFromParent();
2649 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2651 Builder.buildZExtOrTrunc(DstReg, Reg);
2652 MI.eraseFromParent();
2657 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2660 LLT IntTy =
MRI.getType(LHS);
2664 PtrReg.second =
false;
2665 for (
Register SrcReg : {LHS, RHS}) {
2669 LLT PtrTy =
MRI.getType(PtrReg.first);
2674 PtrReg.second =
true;
2686 const bool DoCommute = PtrReg.second;
2691 LLT PtrTy =
MRI.getType(LHS);
2693 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2694 Builder.buildPtrToInt(Dst, PtrAdd);
2695 MI.eraseFromParent();
2699 APInt &NewCst)
const {
2701 Register LHS = PtrAdd.getBaseReg();
2702 Register RHS = PtrAdd.getOffsetReg();
2708 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2711 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2720 APInt &NewCst)
const {
2724 Builder.buildConstant(Dst, NewCst);
2725 PtrAdd.eraseFromParent();
2730 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2735 SrcReg = OriginalSrcReg;
2736 LLT DstTy =
MRI.getType(DstReg);
2744 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2747 LLT DstTy =
MRI.getType(DstReg);
2752 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2753 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2763 if (ShiftSize > 32 && TruncSize < 32)
2776 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2777 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2781 if (!
MRI.hasOneNonDBGUse(SrcReg))
2784 LLT SrcTy =
MRI.getType(SrcReg);
2785 LLT DstTy =
MRI.getType(DstReg);
2794 case TargetOpcode::G_SHL: {
2803 case TargetOpcode::G_LSHR:
2804 case TargetOpcode::G_ASHR: {
2810 for (
auto &
User :
MRI.use_instructions(DstReg))
2811 if (
User.getOpcode() == TargetOpcode::G_STORE)
2815 if (NewShiftTy == SrcTy)
2829 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2832 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2837 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2839 LLT NewShiftTy = MatchInfo.second;
2842 LLT DstTy =
MRI.getType(Dst);
2846 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2850 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2853 if (NewShiftTy == DstTy)
2856 Builder.buildTrunc(Dst, NewShift);
2863 return MO.isReg() &&
2864 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2870 return !MO.isReg() ||
2871 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2876 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2878 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2882 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2883 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2888 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2889 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2895 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2896 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2897 "Expected an insert/extract element op");
2898 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2903 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2911 unsigned &
OpIdx)
const {
2917 OpIdx = Cst->isZero() ? 3 : 2;
2962 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2989 return MO.isReg() && MO.getReg().isPhysical();
2999 return I1->isIdenticalTo(*I2);
3007 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
3014 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
3026 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
3027 MaybeCst->getSExtValue() ==
C;
3034 std::optional<FPValueAndVReg> MaybeCst;
3038 return MaybeCst->Value.isExactlyValue(
C);
3042 unsigned OpIdx)
const {
3043 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3048 MI.eraseFromParent();
3053 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3057 MI.eraseFromParent();
3061 unsigned ConstIdx)
const {
3062 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3063 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3075 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3076 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3077 "This is not a funnel shift operation");
3079 Register ConstReg =
MI.getOperand(3).getReg();
3080 LLT ConstTy =
MRI.getType(ConstReg);
3081 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3084 assert((VRegAndVal) &&
"Value is not a constant");
3087 APInt NewConst = VRegAndVal->Value.
urem(
3092 MI.getOpcode(), {MI.getOperand(0)},
3093 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3095 MI.eraseFromParent();
3099 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3113 unsigned OpIdx)
const {
3115 return MO.
isReg() &&
3126 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3128 MI.eraseFromParent();
3133 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3135 MI.eraseFromParent();
3139 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3141 MI.eraseFromParent();
3146 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3148 MI.eraseFromParent();
3152 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3154 MI.eraseFromParent();
3158 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3161 Register &NewLHS = std::get<0>(MatchInfo);
3162 Register &NewRHS = std::get<1>(MatchInfo);
3170 NewLHS = MaybeNewLHS;
3174 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3179 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3182 LLT DstTy =
MRI.getType(DstReg);
3191 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3192 TargetOpcode::G_INSERT_VECTOR_ELT)
3198 MatchInfo.
resize(NumElts);
3202 if (IntImm >= NumElts || IntImm < 0)
3204 if (!MatchInfo[IntImm])
3205 MatchInfo[IntImm] = TmpReg;
3209 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3211 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3220 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3227 auto GetUndef = [&]() {
3230 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3238 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3239 MI.eraseFromParent();
3243 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3245 std::tie(SubLHS, SubRHS) = MatchInfo;
3246 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3247 MI.eraseFromParent();
3260 unsigned InnerOpc = InnerDef->
getOpcode();
3261 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3284 if (!TryMatch(InnerLHS, InnerRHS) && !TryMatch(InnerRHS, InnerLHS))
3288 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3289 : TargetOpcode::G_ADD;
3292 MatchInfo = [=](MachineIRBuilder &
Builder) {
3293 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3294 auto NewNot =
Builder.buildNot(Ty, NewInner);
3295 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3307 unsigned RootOpc =
MI.getOpcode();
3309 LLT Ty =
MRI.getType(Dst);
3314 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3315 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3326 unsigned LogicOpcode =
MI.getOpcode();
3327 assert(LogicOpcode == TargetOpcode::G_AND ||
3328 LogicOpcode == TargetOpcode::G_OR ||
3329 LogicOpcode == TargetOpcode::G_XOR);
3336 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3342 if (!LeftHandInst || !RightHandInst)
3344 unsigned HandOpcode = LeftHandInst->
getOpcode();
3345 if (HandOpcode != RightHandInst->
getOpcode())
3359 if (!XTy.
isValid() || XTy != YTy)
3364 switch (HandOpcode) {
3367 case TargetOpcode::G_ANYEXT:
3368 case TargetOpcode::G_SEXT:
3369 case TargetOpcode::G_ZEXT: {
3373 case TargetOpcode::G_TRUNC: {
3378 LLT DstTy =
MRI.getType(Dst);
3387 case TargetOpcode::G_AND:
3388 case TargetOpcode::G_ASHR:
3389 case TargetOpcode::G_LSHR:
3390 case TargetOpcode::G_SHL: {
3395 ExtraHandOpSrcReg = ZOp.
getReg();
3406 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3417 if (ExtraHandOpSrcReg.
isValid())
3429 "Expected at least one instr to build?");
3431 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3432 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3434 for (
auto &OperandFn : InstrToBuild.OperandFns)
3437 MI.eraseFromParent();
3441 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3442 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3443 int64_t ShlCst, AshrCst;
3449 if (ShlCst != AshrCst)
3452 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3454 MatchInfo = std::make_tuple(Src, ShlCst);
3459 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3460 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3463 std::tie(Src, ShiftAmt) = MatchInfo;
3464 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3465 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3466 MI.eraseFromParent();
3473 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3476 LLT Ty =
MRI.getType(Dst);
3488 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3491 auto Zero =
B.buildConstant(Ty, 0);
3514 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3538 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3545 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3562 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3580 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3587 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3598 unsigned ExtBits =
MI.getOperand(2).getImm();
3599 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3600 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3604 int64_t Cst,
bool IsVector,
bool IsFP) {
3606 return (ScalarSizeBits == 1 && Cst == -1) ||
3628 unsigned BuildUseCount = BV.getNumSources();
3629 if (BuildUseCount % 2 != 0)
3632 unsigned NumUnmerge = BuildUseCount / 2;
3638 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3641 UnmergeSrc = Unmerge->getSourceReg();
3643 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3644 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3651 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3656 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3657 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3660 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3663 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3668 if (Unmerge->getNumDefs() != NumUnmerge)
3672 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3675 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3686 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3687 B.setInstrAndDebugLoc(
MI);
3689 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3690 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3692 MI.eraseFromParent();
3714 unsigned NumOperands =
BuildMI->getNumSources();
3724 for (
I = 0;
I < NumOperands; ++
I) {
3725 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3726 auto SrcMIOpc = SrcMI->getOpcode();
3729 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3730 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3732 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3733 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3736 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3737 if (UnmergeMI != UnmergeSrcMI)
3752 for (;
I < NumOperands; ++
I) {
3753 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3754 auto SrcMIOpc = SrcMI->getOpcode();
3756 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3762 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3769 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3770 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3778 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3781 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3793 LLT DstTy =
MRI.getType(DstReg);
3794 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3799 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3804 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3808 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3811 Builder.buildTrunc(DstReg, MidReg);
3812 MI.eraseFromParent();
3817 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3818 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3819 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3827 if (!
MRI.hasOneNonDBGUse(XorSrc))
3837 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3839 if (!
MRI.hasOneNonDBGUse(Reg))
3842 switch (Def->getOpcode()) {
3847 case TargetOpcode::G_ICMP:
3853 case TargetOpcode::G_FCMP:
3859 case TargetOpcode::G_AND:
3860 case TargetOpcode::G_OR:
3866 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3867 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3875 if (Ty.isVector()) {
3880 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3894 for (
Register Reg : RegsToNegate) {
3899 switch (Def->getOpcode()) {
3902 case TargetOpcode::G_ICMP:
3903 case TargetOpcode::G_FCMP: {
3910 case TargetOpcode::G_AND:
3911 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3913 case TargetOpcode::G_OR:
3914 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3921 MI.eraseFromParent();
3925 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3927 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3931 Register SharedReg =
MI.getOperand(2).getReg();
3945 if (!
MRI.hasOneNonDBGUse(AndReg))
3952 return Y == SharedReg;
3956 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3959 std::tie(
X,
Y) = MatchInfo;
3962 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3963 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3964 MI.getOperand(2).setReg(
Y);
3970 Register DstReg = PtrAdd.getReg(0);
3971 LLT Ty =
MRI.getType(DstReg);
3974 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3977 if (Ty.isPointer()) {
3979 return ConstVal && *ConstVal == 0;
3982 assert(Ty.isVector() &&
"Expecting a vector type");
3989 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3990 PtrAdd.eraseFromParent();
3997 Register Pow2Src1 =
MI.getOperand(2).getReg();
3998 LLT Ty =
MRI.getType(DstReg);
4001 auto NegOne =
Builder.buildConstant(Ty, -1);
4002 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
4004 MI.eraseFromParent();
4008 unsigned &SelectOpNo)
const {
4018 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
4019 !
MRI.hasOneNonDBGUse(LHS)) {
4020 OtherOperandReg = LHS;
4023 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
4024 !
MRI.hasOneNonDBGUse(RHS))
4040 unsigned BinOpcode =
MI.getOpcode();
4045 bool CanFoldNonConst =
4046 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4051 if (CanFoldNonConst)
4072 LLT Ty =
MRI.getType(Dst);
4073 unsigned BinOpcode =
MI.getOpcode();
4080 if (SelectOperand == 1) {
4084 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4086 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4088 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4090 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4093 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4094 MI.eraseFromParent();
4097std::optional<SmallVector<Register, 8>>
4098CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4099 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4128 const unsigned MaxIter =
4130 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4139 return std::nullopt;
4155 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4156 return std::nullopt;
4168static std::optional<std::pair<GZExtLoad *, int64_t>>
4172 "Expected Reg to only have one non-debug use?");
4181 if (Shift % MemSizeInBits != 0)
4182 return std::nullopt;
4187 return std::nullopt;
4189 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4190 return std::nullopt;
4192 return std::make_pair(Load, Shift / MemSizeInBits);
4195std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4196CombinerHelper::findLoadOffsetsForLoadOrCombine(
4199 const unsigned MemSizeInBits)
const {
4202 SmallSetVector<const MachineInstr *, 8> Loads;
4208 GZExtLoad *LowestIdxLoad =
nullptr;
4211 SmallSet<int64_t, 8> SeenIdx;
4215 MachineBasicBlock *
MBB =
nullptr;
4216 const MachineMemOperand *MMO =
nullptr;
4219 GZExtLoad *EarliestLoad =
nullptr;
4222 GZExtLoad *LatestLoad =
nullptr;
4231 for (
auto Reg : RegsToVisit) {
4236 return std::nullopt;
4239 std::tie(Load, DstPos) = *LoadAndPos;
4243 MachineBasicBlock *LoadMBB =
Load->getParent();
4247 return std::nullopt;
4250 auto &LoadMMO =
Load->getMMO();
4254 return std::nullopt;
4261 LoadPtr =
Load->getOperand(1).getReg();
4266 if (!SeenIdx.
insert(Idx).second)
4267 return std::nullopt;
4274 if (BasePtr != LoadPtr)
4275 return std::nullopt;
4277 if (Idx < LowestIdx) {
4279 LowestIdxLoad =
Load;
4286 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4287 return std::nullopt;
4295 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4296 EarliestLoad =
Load;
4297 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4304 "Expected to find a load for each register?");
4305 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4306 LatestLoad &&
"Expected at least two loads?");
4315 const unsigned MaxIter = 20;
4321 if (
MI.isLoadFoldBarrier())
4322 return std::nullopt;
4323 if (Iter++ == MaxIter)
4324 return std::nullopt;
4327 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4333 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4346 LLT Ty =
MRI.getType(Dst);
4352 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4353 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4357 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4364 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4365 if (NarrowMemSizeInBits % 8 != 0)
4378 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4379 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4382 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4389 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4392 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4404 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4405 const unsigned ZeroByteOffset =
4409 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4410 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4411 ZeroOffsetIdx->second != LowestIdx)
4421 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4435 MIB.setInstrAndDebugLoc(*LatestLoad);
4436 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4437 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4439 MIB.buildBSwap(Dst, LoadDst);
4451 if (
MRI.getType(DstReg).isVector())
4455 if (!
MRI.hasOneNonDBGUse(DstReg))
4457 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4459 case TargetOpcode::G_ANYEXT:
4461 case TargetOpcode::G_ZEXT:
4462 case TargetOpcode::G_SEXT:
4469 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4476 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4478 switch (
DefMI->getOpcode()) {
4479 case TargetOpcode::G_LOAD:
4480 case TargetOpcode::G_TRUNC:
4481 case TargetOpcode::G_SEXT:
4482 case TargetOpcode::G_ZEXT:
4483 case TargetOpcode::G_ANYEXT:
4484 case TargetOpcode::G_CONSTANT:
4488 if (InSrcs.
size() > 2)
4502 LLT ExtTy =
MRI.getType(DstReg);
4509 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4510 auto SrcReg =
PHI.getIncomingValue(
I);
4511 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4512 if (!SrcMIs.
insert(SrcMI))
4516 auto *
MBB = SrcMI->getParent();
4518 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4519 InsertPt =
MBB->getFirstNonPHI();
4521 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4524 OldToNewSrcMap[SrcMI] = NewExt;
4529 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4530 NewPhi.addDef(DstReg);
4533 NewPhi.addMBB(MO.getMBB());
4536 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4537 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4545 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4549 LLT SrcTy =
MRI.getType(SrcVec);
4550 if (SrcTy.isScalableVector())
4554 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4557 unsigned VecIdx = Cst->Value.getZExtValue();
4562 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4566 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4567 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4571 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4583 LLT ScalarTy =
MRI.getType(Reg);
4585 LLT DstTy =
MRI.getType(DstReg);
4587 if (ScalarTy != DstTy) {
4589 Builder.buildTrunc(DstReg, Reg);
4590 MI.eraseFromParent();
4598 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4599 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4617 LLT DstTy =
MRI.getType(DstReg);
4622 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4627 unsigned Idx = Cst->getZExtValue();
4630 ExtractedElts.
set(Idx);
4631 SrcDstPairs.emplace_back(
4632 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4635 return ExtractedElts.
all();
4640 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4641 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4642 for (
auto &Pair : SrcDstPairs) {
4643 auto *ExtMI = Pair.second;
4645 ExtMI->eraseFromParent();
4647 MI.eraseFromParent();
4654 MI.eraseFromParent();
4664 bool AllowScalarConstants,
4666 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4669 LLT Ty =
MRI.getType(Dst);
4670 unsigned BitWidth = Ty.getScalarSizeInBits();
4672 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4673 unsigned FshOpc = 0;
4684 int64_t CstShlAmt = 0, CstLShrAmt;
4687 CstShlAmt + CstLShrAmt ==
BitWidth) {
4688 FshOpc = TargetOpcode::G_FSHR;
4694 FshOpc = TargetOpcode::G_FSHL;
4699 FshOpc = TargetOpcode::G_FSHR;
4704 LLT AmtTy =
MRI.getType(Amt);
4706 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4710 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4717 unsigned Opc =
MI.getOpcode();
4718 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4723 unsigned RotateOpc =
4724 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4729 unsigned Opc =
MI.getOpcode();
4730 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4731 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4733 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4734 : TargetOpcode::G_ROTR));
4735 MI.removeOperand(2);
4741 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4742 MI.getOpcode() == TargetOpcode::G_ROTR);
4744 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4746 bool OutOfRange =
false;
4747 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4749 OutOfRange |= CI->getValue().uge(Bitsize);
4756 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4757 MI.getOpcode() == TargetOpcode::G_ROTR);
4759 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4761 LLT AmtTy =
MRI.getType(Amt);
4762 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4763 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4765 MI.getOperand(2).setReg(Amt);
4770 int64_t &MatchInfo)
const {
4771 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4782 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4783 if (KnownRHS.isUnknown())
4786 std::optional<bool> KnownVal;
4787 if (KnownRHS.isZero()) {
4797 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4807 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4816 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4832 LLT DstTy =
MRI.getType(Dst);
4840 auto KnownLHS =
VT->getKnownBits(LHS);
4841 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4844 LLT LHSTy =
MRI.getType(LHS);
4847 unsigned Op = TargetOpcode::COPY;
4848 if (DstSize != LHSSize)
4849 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4860 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4864 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4870 int64_t AndMaskBits;
4878 if (AndMaskBits & OrMaskBits)
4884 if (
MI.getOperand(1).getReg() == AndMaskReg)
4885 MI.getOperand(2).setReg(AndMaskReg);
4886 MI.getOperand(1).setReg(Src);
4896 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4899 LLT Ty =
MRI.getType(Src);
4901 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4903 int64_t Width =
MI.getOperand(2).getImm();
4911 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4915 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4916 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4917 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4927 LLT Ty =
MRI.getType(Dst);
4931 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4934 int64_t AndImm, LSBImm;
4936 const unsigned Size = Ty.getScalarSizeInBits();
4943 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4944 if (MaybeMask & (MaybeMask + 1))
4953 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4954 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4955 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4963 const unsigned Opcode =
MI.getOpcode();
4964 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4966 const Register Dst =
MI.getOperand(0).getReg();
4968 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4969 ? TargetOpcode::G_SBFX
4970 : TargetOpcode::G_UBFX;
4973 LLT Ty =
MRI.getType(Dst);
4975 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4981 const unsigned Size = Ty.getScalarSizeInBits();
4991 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4995 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4999 const int64_t Pos = ShrAmt - ShlAmt;
5000 const int64_t Width =
Size - ShrAmt;
5003 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5004 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5005 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
5013 const unsigned Opcode =
MI.getOpcode();
5014 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
5016 const Register Dst =
MI.getOperand(0).getReg();
5017 LLT Ty =
MRI.getType(Dst);
5019 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
5032 const unsigned Size = Ty.getScalarSizeInBits();
5033 if (ShrAmt < 0 || ShrAmt >=
Size)
5037 if (0 == (SMask >> ShrAmt)) {
5039 B.buildConstant(Dst, 0);
5045 uint64_t UMask = SMask;
5052 const int64_t Pos = ShrAmt;
5057 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5061 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5062 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5063 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5068bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5072 Register Src1Reg = PtrAdd.getBaseReg();
5077 Register Src2Reg = PtrAdd.getOffsetReg();
5079 if (
MRI.hasOneNonDBGUse(Src1Reg))
5089 const APInt &C1APIntVal = *C1;
5090 const APInt &C2APIntVal = *C2;
5091 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5093 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5096 MachineInstr *ConvUseMI = &
UseMI;
5097 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5098 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5099 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5101 if (!
MRI.hasOneNonDBGUse(DefReg))
5103 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5112 TargetLoweringBase::AddrMode AM;
5115 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5117 PtrAdd.getMF()->getFunction().getContext());
5118 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5119 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5125 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5137 Register Src1Reg =
MI.getOperand(1).getReg();
5138 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5150 unsigned PtrAddFlags =
MI.getFlags();
5151 unsigned AddFlags = RHS->getFlags();
5164 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5167 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5169 MI.getOperand(1).setReg(NewBase.getReg(0));
5170 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5174 return !reassociationCanBreakAddressingModePattern(
MI);
5184 std::optional<ValueAndVReg> LHSCstOff;
5194 unsigned PtrAddFlags =
MI.getFlags();
5195 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5197 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5199 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5213 LHSPtrAdd->moveBefore(&
MI);
5216 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5218 MI.getOperand(2).setReg(NewCst.getReg(0));
5221 Observer.changingInstr(*LHSPtrAdd);
5222 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5223 LHSPtrAdd->setFlags(Flags);
5226 return !reassociationCanBreakAddressingModePattern(
MI);
5237 Register Src2Reg =
MI.getOperand(2).getReg();
5238 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5239 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5252 unsigned PtrAddFlags =
MI.getFlags();
5253 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5266 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5268 MI.getOperand(1).setReg(LHSSrc1);
5269 MI.getOperand(2).setReg(NewCst.getReg(0));
5273 return !reassociationCanBreakAddressingModePattern(
MI);
5311 LLT OpRHSTy =
MRI.getType(OpRHS);
5330 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5331 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5339 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5340 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5353 unsigned Opc =
MI.getOpcode();
5366 APInt &MatchInfo)
const {
5367 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5371 MatchInfo = *MaybeCst;
5382 MI.getOperand(1).getReg(),
MRI);
5387 if (Csts.size() == 1)
5388 B.buildConstant(Dst, Csts[0]);
5390 B.buildBuildVectorConstant(Dst, Csts);
5396 APInt &MatchInfo)
const {
5402 MatchInfo = *MaybeCst;
5414 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5420 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5421 MI.getOpcode() == TargetOpcode::G_FMAD);
5422 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5439 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5462 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5466 LLT WideTy =
MRI.getType(Dst);
5470 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5486 case TargetOpcode::G_ADD:
5487 case TargetOpcode::G_SUB:
5488 case TargetOpcode::G_MUL:
5489 case TargetOpcode::G_AND:
5490 case TargetOpcode::G_OR:
5491 case TargetOpcode::G_XOR:
5499 auto Mask = Cst->Value;
5504 unsigned NarrowWidth = Mask.countr_one();
5510 auto &MF = *
MI.getMF();
5513 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5514 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5522 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5523 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5525 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5526 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5528 MI.getOperand(1).setReg(Ext.getReg(0));
5536 unsigned Opc =
MI.getOpcode();
5537 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5544 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5545 : TargetOpcode::G_SADDO;
5546 MI.setDesc(
Builder.getTII().get(NewOpc));
5547 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5556 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5557 MI.getOpcode() == TargetOpcode::G_SMULO);
5566 B.buildConstant(Dst, 0);
5567 B.buildConstant(Carry, 0);
5576 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5577 MI.getOpcode() == TargetOpcode::G_SADDE ||
5578 MI.getOpcode() == TargetOpcode::G_USUBE ||
5579 MI.getOpcode() == TargetOpcode::G_SSUBE);
5584 switch (
MI.getOpcode()) {
5585 case TargetOpcode::G_UADDE:
5586 NewOpcode = TargetOpcode::G_UADDO;
5588 case TargetOpcode::G_SADDE:
5589 NewOpcode = TargetOpcode::G_SADDO;
5591 case TargetOpcode::G_USUBE:
5592 NewOpcode = TargetOpcode::G_USUBO;
5594 case TargetOpcode::G_SSUBE:
5595 NewOpcode = TargetOpcode::G_SSUBO;
5599 MI.setDesc(
B.getTII().get(NewOpcode));
5600 MI.removeOperand(4);
5608 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5641 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5642 B.buildSub(Dst, Zero, ReplaceReg);
5651 unsigned Opcode =
MI.getOpcode();
5652 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5654 Register Dst = UDivorRem.getReg(0);
5655 Register LHS = UDivorRem.getReg(1);
5656 Register RHS = UDivorRem.getReg(2);
5657 LLT Ty =
MRI.getType(Dst);
5665 bool UseSRL =
false;
5670 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5672 if (IsSplat && !Factors.
empty()) {
5679 APInt Divisor = CI->getValue();
5688 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5689 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5699 if (Ty.isVector()) {
5700 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5701 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5704 Factor = Factors[0];
5712 return MIB.buildMul(Ty, Res, Factor);
5715 unsigned KnownLeadingZeros =
5716 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5718 bool UseNPQ =
false;
5720 auto BuildUDIVPattern = [&](
const Constant *
C) {
5722 const APInt &Divisor = CI->getValue();
5724 bool SelNPQ =
false;
5726 unsigned PreShift = 0, PostShift = 0;
5731 if (!Divisor.
isOne()) {
5737 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5739 Magic = std::move(magics.
Magic);
5742 "We shouldn't generate an undefined shift!");
5744 "We shouldn't generate an undefined shift!");
5748 SelNPQ = magics.
IsAdd;
5752 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5753 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5755 MIB.buildConstant(ScalarTy,
5760 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5768 assert(Matched &&
"Expected unary predicate match to succeed");
5770 Register PreShift, PostShift, MagicFactor, NPQFactor;
5773 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5774 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5775 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5776 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5779 "Non-build_vector operation should have been a scalar");
5780 PreShift = PreShifts[0];
5781 MagicFactor = MagicFactors[0];
5782 PostShift = PostShifts[0];
5786 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5789 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5792 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5797 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5799 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5801 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5804 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5805 auto One = MIB.buildConstant(Ty, 1);
5806 auto IsOne = MIB.buildICmp(
5810 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5812 if (Opcode == TargetOpcode::G_UREM) {
5813 auto Prod = MIB.buildMul(Ty, ret, RHS);
5814 return MIB.buildSub(Ty, LHS, Prod);
5820 unsigned Opcode =
MI.getOpcode();
5821 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5824 LLT DstTy =
MRI.getType(Dst);
5826 auto &MF = *
MI.getMF();
5827 AttributeList Attr = MF.getFunction().getAttributes();
5836 if (MF.getFunction().hasMinSize())
5839 if (Opcode == TargetOpcode::G_UDIV &&
5842 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5845 auto *RHSDef =
MRI.getVRegDef(RHS);
5856 {TargetOpcode::G_ICMP,
5860 if (Opcode == TargetOpcode::G_UREM &&
5866 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5875 unsigned Opcode =
MI.getOpcode();
5876 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5879 LLT DstTy =
MRI.getType(Dst);
5883 auto &MF = *
MI.getMF();
5884 AttributeList Attr = MF.getFunction().getAttributes();
5893 if (MF.getFunction().hasMinSize())
5897 if (Opcode == TargetOpcode::G_SDIV &&
5900 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5903 auto *RHSDef =
MRI.getVRegDef(RHS);
5911 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5914 if (Opcode == TargetOpcode::G_SREM &&
5920 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5929 unsigned Opcode =
MI.getOpcode();
5930 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5931 Opcode == TargetOpcode::G_SREM);
5933 Register Dst = SDivorRem.getReg(0);
5934 Register LHS = SDivorRem.getReg(1);
5935 Register RHS = SDivorRem.getReg(2);
5936 LLT Ty =
MRI.getType(Dst);
5943 bool UseSRA =
false;
5949 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5951 if (IsSplat && !ExactFactors.
empty()) {
5953 ExactFactors.
push_back(ExactFactors[0]);
5958 APInt Divisor = CI->getValue();
5968 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5969 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5977 assert(Matched &&
"Expected unary predicate match to succeed");
5980 if (Ty.isVector()) {
5981 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5982 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5984 Shift = ExactShifts[0];
5985 Factor = ExactFactors[0];
5993 return MIB.buildMul(Ty, Res, Factor);
5998 auto BuildSDIVPattern = [&](
const Constant *
C) {
6000 const APInt &Divisor = CI->getValue();
6004 int NumeratorFactor = 0;
6015 NumeratorFactor = 1;
6018 NumeratorFactor = -1;
6021 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
6022 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
6024 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
6025 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
6033 assert(Matched &&
"Expected unary predicate match to succeed");
6035 Register MagicFactor, Factor, Shift, ShiftMask;
6038 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
6039 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
6040 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
6041 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
6044 "Non-build_vector operation should have been a scalar");
6045 MagicFactor = MagicFactors[0];
6046 Factor = Factors[0];
6048 ShiftMask = ShiftMasks[0];
6052 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6055 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6056 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6059 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6062 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6063 auto T = MIB.buildLShr(Ty, Q, SignShift);
6064 T = MIB.buildAnd(Ty,
T, ShiftMask);
6065 auto ret = MIB.buildAdd(Ty, Q,
T);
6067 if (Opcode == TargetOpcode::G_SREM) {
6068 auto Prod = MIB.buildMul(Ty, ret, RHS);
6069 return MIB.buildSub(Ty, LHS, Prod);
6075 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6076 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6077 "Expected SDIV or UDIV");
6080 auto MatchPow2 = [&](
const Constant *
C) {
6082 return CI && (CI->getValue().isPowerOf2() ||
6083 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6089 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6094 LLT Ty =
MRI.getType(Dst);
6114 unsigned BitWidth = Ty.getScalarSizeInBits();
6115 auto Zero =
Builder.buildConstant(Ty, 0);
6118 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6119 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6121 auto Sign =
Builder.buildAShr(
6125 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6131 auto One =
Builder.buildConstant(Ty, 1);
6132 auto MinusOne =
Builder.buildConstant(Ty, -1);
6136 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6137 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6141 auto Neg =
Builder.buildNeg(Ty, AShr);
6143 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6144 MI.eraseFromParent();
6148 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6153 LLT Ty =
MRI.getType(Dst);
6156 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6157 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6158 MI.eraseFromParent();
6162 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6167 LLT Ty =
MRI.getType(Dst);
6186 unsigned BitWidth = Ty.getScalarSizeInBits();
6187 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6188 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6190 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6191 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6192 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6195 MI.eraseFromParent();
6199 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6202 LLT Ty =
MRI.getType(Dst);
6203 LLT RHSTy =
MRI.getType(RHS);
6205 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6207 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6222 LLT Ty =
MRI.getType(Dst);
6228 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6229 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6230 Builder.buildLShr(Dst, LHS, Trunc);
6231 MI.eraseFromParent();
6238 LLT DstTy =
MRI.getType(Dst);
6239 LLT SrcTy =
MRI.getType(Src);
6241 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6242 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6245 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6263 Builder.buildTruncSSatS(Dst, MatchInfo);
6264 MI.eraseFromParent();
6271 LLT DstTy =
MRI.getType(Dst);
6272 LLT SrcTy =
MRI.getType(Src);
6274 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6275 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6278 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6296 Builder.buildTruncSSatU(Dst, MatchInfo);
6297 MI.eraseFromParent();
6304 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6305 LLT SrcTy =
MRI.getType(Val);
6307 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6308 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6311 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6320 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6329 unsigned Opc =
MI.getOpcode();
6330 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6331 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6332 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6344 Opc = TargetOpcode::G_FSUB;
6349 Opc = TargetOpcode::G_FADD;
6355 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6356 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6365 MI.setDesc(
B.getTII().get(
Opc));
6366 MI.getOperand(1).setReg(
X);
6367 MI.getOperand(2).setReg(
Y);
6375 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6378 MatchInfo =
MI.getOperand(2).getReg();
6379 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6381 const auto LHSCst = Ty.isVector()
6388 if (LHSCst->Value.isNegZero())
6392 if (LHSCst->Value.isPosZero())
6402 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6409 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6423 bool &AllowFusionGlobally,
6425 bool CanReassociate)
const {
6427 auto *MF =
MI.getMF();
6428 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6430 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6438 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6441 if (!HasFMAD && !HasFMA)
6449 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6456 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6458 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6466 unsigned PreferredFusedOpcode =
6467 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6481 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6482 {LHS.MI->getOperand(1).getReg(),
6483 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6492 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6493 {RHS.MI->getOperand(1).getReg(),
6494 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6505 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6507 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6511 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6516 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6518 unsigned PreferredFusedOpcode =
6519 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6533 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6538 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6539 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6548 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6553 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6554 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6565 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6567 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6575 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6577 unsigned PreferredFusedOpcode =
6578 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6591 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6592 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6593 TargetOpcode::G_FMUL) &&
6594 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6595 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6600 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6601 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6602 TargetOpcode::G_FMUL) &&
6603 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6604 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6611 Register X = FMA->getOperand(1).getReg();
6612 Register Y = FMA->getOperand(2).getReg();
6617 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6618 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6619 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6631 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6633 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6640 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6641 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6647 unsigned PreferredFusedOpcode =
6648 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6661 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6662 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6664 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6666 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6673 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6677 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6682 LHS.MI->getOperand(1).getReg(),
6683 LHS.MI->getOperand(2).getReg(),
B);
6694 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6697 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6702 X =
B.buildFPExt(DstType,
X).getReg(0);
6703 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6714 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6718 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6723 RHS.MI->getOperand(1).getReg(),
6724 RHS.MI->getOperand(2).getReg(),
B);
6735 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6738 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6743 X =
B.buildFPExt(DstType,
X).getReg(0);
6744 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6758 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6760 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6768 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6772 int FirstMulHasFewerUses =
true;
6776 FirstMulHasFewerUses =
false;
6778 unsigned PreferredFusedOpcode =
6779 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6782 if (FirstMulHasFewerUses &&
6786 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6787 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6788 {LHS.MI->getOperand(1).getReg(),
6789 LHS.MI->getOperand(2).getReg(), NegZ});
6798 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6799 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6800 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6811 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6813 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6819 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6821 unsigned PreferredFusedOpcode =
6822 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6833 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6834 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6846 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6859 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6861 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6867 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6869 unsigned PreferredFusedOpcode =
6870 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6882 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6883 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6884 {FpExtX, FpExtY, NegZ});
6896 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6899 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6900 {NegY, FpExtZ, LHSReg});
6911 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6913 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6917 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6918 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6922 unsigned PreferredFusedOpcode =
6923 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6927 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6928 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6929 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6940 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6943 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6946 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6956 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6969 unsigned &IdxToPropagate)
const {
6971 switch (
MI.getOpcode()) {
6974 case TargetOpcode::G_FMINNUM:
6975 case TargetOpcode::G_FMAXNUM:
6976 PropagateNaN =
false;
6978 case TargetOpcode::G_FMINIMUM:
6979 case TargetOpcode::G_FMAXIMUM:
6980 PropagateNaN =
true;
6984 auto MatchNaN = [&](
unsigned Idx) {
6985 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6989 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6993 return MatchNaN(1) || MatchNaN(2);
7001 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
7011 return N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0));
7028 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
7029 if (&U == &
MI || U.getParent() !=
MI.getParent())
7031 if (U.getOpcode() == TargetOpcode::G_FDIV &&
7032 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
7033 !IsOne(U.getOperand(1).getReg())) {
7046 return MatchInfo.
size() >= MinUses;
7054 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7055 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7056 MatchInfo[0]->getOperand(2).getReg(),
7057 MatchInfo[0]->getFlags());
7062 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7063 Div->getOperand(0).getReg(),
MI->getFlags());
7064 MI->eraseFromParent();
7069 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7079 Reg == MaybeSameReg;
7081 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7102 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7111 return MRI.getType(MatchInfo) == DstVecTy;
7114 std::optional<ValueAndVReg> ShiftAmount;
7123 return MRI.getType(MatchInfo) == DstVecTy;
7138 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7145 std::optional<ValueAndVReg> ShiftAmt;
7151 LLT MatchTy =
MRI.getType(MatchInfo);
7152 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7153 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7156unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7158 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7159 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7160 "Expected a NaN behaviour?");
7170 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7171 return TargetOpcode::G_FMAXNUM;
7172 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7173 return TargetOpcode::G_FMAXIMUM;
7174 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7175 return TargetOpcode::G_FMAXNUM;
7176 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7177 return TargetOpcode::G_FMAXIMUM;
7183 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7184 return TargetOpcode::G_FMINNUM;
7185 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7186 return TargetOpcode::G_FMINIMUM;
7187 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7188 return TargetOpcode::G_FMINNUM;
7189 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7191 return TargetOpcode::G_FMINIMUM;
7195CombinerHelper::SelectPatternNaNBehaviour
7197 bool IsOrderedComparison)
const {
7198 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7199 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7201 if (!LHSSafe && !RHSSafe)
7202 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7203 if (LHSSafe && RHSSafe)
7204 return SelectPatternNaNBehaviour::RETURNS_ANY;
7207 if (IsOrderedComparison)
7208 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7209 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7212 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7213 : SelectPatternNaNBehaviour::RETURNS_NAN;
7222 LLT DstTy =
MRI.getType(Dst);
7235 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7237 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7239 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7242 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7243 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7244 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7245 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7247 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7250 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7255 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7260 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7262 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7266 MatchInfo = [=](MachineIRBuilder &
B) {
7267 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7275 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7282 Register TrueVal =
MI.getOperand(2).getReg();
7283 Register FalseVal =
MI.getOperand(3).getReg();
7284 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7289 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7302 if (MatchedSub &&
X != OpLHS)
7310 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7313 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7314 B.buildICmp(Pred, Dst,
Y, Zero);
7321static std::optional<unsigned>
7323 std::optional<int64_t> &Result) {
7324 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7325 Opcode == TargetOpcode::G_ASHR) &&
7326 "Expect G_SHL, G_LSHR or G_ASHR.");
7327 auto SignificantBits = 0;
7329 case TargetOpcode::G_SHL:
7333 case TargetOpcode::G_LSHR:
7337 case TargetOpcode::G_ASHR:
7346 Result = std::nullopt;
7357 Register ShiftVal =
MI.getOperand(1).getReg();
7358 Register ShiftReg =
MI.getOperand(2).getReg();
7359 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7360 auto IsShiftTooBig = [&](
const Constant *
C) {
7365 MatchInfo = std::nullopt;
7369 MI.getOpcode(), MatchInfo);
7370 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7376 unsigned LHSOpndIdx = 1;
7377 unsigned RHSOpndIdx = 2;
7378 switch (
MI.getOpcode()) {
7379 case TargetOpcode::G_UADDO:
7380 case TargetOpcode::G_SADDO:
7381 case TargetOpcode::G_UMULO:
7382 case TargetOpcode::G_SMULO:
7389 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7390 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7395 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7396 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7400 return MRI.getVRegDef(RHS)->getOpcode() !=
7401 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7408 std::optional<FPValueAndVReg> ValAndVReg;
7416 unsigned LHSOpndIdx = 1;
7417 unsigned RHSOpndIdx = 2;
7418 switch (
MI.getOpcode()) {
7419 case TargetOpcode::G_UADDO:
7420 case TargetOpcode::G_SADDO:
7421 case TargetOpcode::G_UMULO:
7422 case TargetOpcode::G_SMULO:
7429 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7430 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7431 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7432 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7436bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7438 if (SrcTy.isFixedVector())
7440 if (SrcTy.isScalar()) {
7444 return IConstant && IConstant->Value == 1;
7449bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7450 LLT SrcTy =
MRI.getType(Src);
7452 return isConstantSplatVector(Src, 0, AllowUndefs);
7457 return IConstant && IConstant->Value == 0;
7464bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7465 bool AllowUndefs)
const {
7471 for (
unsigned I = 0;
I < NumSources; ++
I) {
7472 GImplicitDef *ImplicitDef =
7474 if (ImplicitDef && AllowUndefs)
7476 if (ImplicitDef && !AllowUndefs)
7478 std::optional<ValueAndVReg> IConstant =
7480 if (IConstant && IConstant->Value == SplatValue)
7490CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7493 return IConstant->Value;
7497 return std::nullopt;
7500 std::optional<APInt>
Value = std::nullopt;
7501 for (
unsigned I = 0;
I < NumSources; ++
I) {
7502 std::optional<ValueAndVReg> IConstant =
7505 return std::nullopt;
7507 Value = IConstant->Value;
7508 else if (*
Value != IConstant->Value)
7509 return std::nullopt;
7515bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7525 for (
unsigned I = 0;
I < NumSources; ++
I) {
7526 std::optional<ValueAndVReg> IConstant =
7535bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7542 LLT CondTy =
MRI.getType(
Select->getCondReg());
7543 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7553 std::optional<ValueAndVReg> TrueOpt =
7555 std::optional<ValueAndVReg> FalseOpt =
7558 if (!TrueOpt || !FalseOpt)
7561 APInt TrueValue = TrueOpt->Value;
7562 APInt FalseValue = FalseOpt->Value;
7566 MatchInfo = [=](MachineIRBuilder &
B) {
7567 B.setInstrAndDebugLoc(*
Select);
7568 B.buildZExtOrTrunc(Dest,
Cond);
7575 MatchInfo = [=](MachineIRBuilder &
B) {
7576 B.setInstrAndDebugLoc(*
Select);
7577 B.buildSExtOrTrunc(Dest,
Cond);
7584 MatchInfo = [=](MachineIRBuilder &
B) {
7585 B.setInstrAndDebugLoc(*
Select);
7586 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7587 B.buildNot(Inner,
Cond);
7588 B.buildZExtOrTrunc(Dest, Inner);
7595 MatchInfo = [=](MachineIRBuilder &
B) {
7596 B.setInstrAndDebugLoc(*
Select);
7597 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7598 B.buildNot(Inner,
Cond);
7599 B.buildSExtOrTrunc(Dest, Inner);
7605 if (TrueValue - 1 == FalseValue) {
7606 MatchInfo = [=](MachineIRBuilder &
B) {
7607 B.setInstrAndDebugLoc(*
Select);
7608 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7609 B.buildZExtOrTrunc(Inner,
Cond);
7610 B.buildAdd(Dest, Inner, False);
7616 if (TrueValue + 1 == FalseValue) {
7617 MatchInfo = [=](MachineIRBuilder &
B) {
7618 B.setInstrAndDebugLoc(*
Select);
7619 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7620 B.buildSExtOrTrunc(Inner,
Cond);
7621 B.buildAdd(Dest, Inner, False);
7628 MatchInfo = [=](MachineIRBuilder &
B) {
7629 B.setInstrAndDebugLoc(*
Select);
7630 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7631 B.buildZExtOrTrunc(Inner,
Cond);
7634 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7635 B.buildShl(Dest, Inner, ShAmtC, Flags);
7642 MatchInfo = [=](MachineIRBuilder &
B) {
7643 B.setInstrAndDebugLoc(*
Select);
7645 B.buildNot(Not,
Cond);
7646 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7647 B.buildZExtOrTrunc(Inner, Not);
7650 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7651 B.buildShl(Dest, Inner, ShAmtC, Flags);
7658 MatchInfo = [=](MachineIRBuilder &
B) {
7659 B.setInstrAndDebugLoc(*
Select);
7660 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7661 B.buildSExtOrTrunc(Inner,
Cond);
7662 B.buildOr(Dest, Inner, False, Flags);
7669 MatchInfo = [=](MachineIRBuilder &
B) {
7670 B.setInstrAndDebugLoc(*
Select);
7672 B.buildNot(Not,
Cond);
7673 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7674 B.buildSExtOrTrunc(Inner, Not);
7675 B.buildOr(Dest, Inner, True, Flags);
7684bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7691 LLT CondTy =
MRI.getType(
Select->getCondReg());
7692 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7701 if (CondTy != TrueTy)
7706 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7707 MatchInfo = [=](MachineIRBuilder &
B) {
7708 B.setInstrAndDebugLoc(*
Select);
7709 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7710 B.buildZExtOrTrunc(Ext,
Cond);
7711 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7712 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7719 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7720 MatchInfo = [=](MachineIRBuilder &
B) {
7721 B.setInstrAndDebugLoc(*
Select);
7722 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7723 B.buildZExtOrTrunc(Ext,
Cond);
7724 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7725 B.buildAnd(DstReg, Ext, FreezeTrue);
7731 if (isOneOrOneSplat(False,
true)) {
7732 MatchInfo = [=](MachineIRBuilder &
B) {
7733 B.setInstrAndDebugLoc(*
Select);
7735 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7736 B.buildNot(Inner,
Cond);
7738 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7739 B.buildZExtOrTrunc(Ext, Inner);
7740 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7741 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7747 if (isZeroOrZeroSplat(True,
true)) {
7748 MatchInfo = [=](MachineIRBuilder &
B) {
7749 B.setInstrAndDebugLoc(*
Select);
7751 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7752 B.buildNot(Inner,
Cond);
7754 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7755 B.buildZExtOrTrunc(Ext, Inner);
7756 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7757 B.buildAnd(DstReg, Ext, FreezeFalse);
7773 LLT DstTy =
MRI.getType(DstReg);
7779 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7788 Register CmpLHS = Cmp->getLHSReg();
7789 Register CmpRHS = Cmp->getRHSReg();
7792 if (True == CmpRHS && False == CmpLHS) {
7800 if (True != CmpLHS || False != CmpRHS)
7840 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7841 Register DestReg =
MI.getOperand(0).getReg();
7842 LLT DestTy =
MRI.getType(DestReg);
7854 if (
isLegal({NewOpc, {DestTy}})) {
7856 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7868 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7871 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7881bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7883 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7884 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7888 unsigned Flags = Logic->
getFlags();
7907 std::optional<ValueAndVReg> MaybeC1 =
7911 C1 = MaybeC1->Value;
7913 std::optional<ValueAndVReg> MaybeC2 =
7917 C2 = MaybeC2->Value;
7938 std::optional<APInt> Offset1;
7939 std::optional<APInt> Offset2;
7942 std::optional<ValueAndVReg> MaybeOffset1 =
7945 R1 =
Add->getLHSReg();
7946 Offset1 = MaybeOffset1->Value;
7950 std::optional<ValueAndVReg> MaybeOffset2 =
7953 R2 =
Add->getLHSReg();
7954 Offset2 = MaybeOffset2->Value;
7973 bool CreateMask =
false;
7986 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7999 CR->getEquivalentICmp(NewPred, NewC,
Offset);
8008 MatchInfo = [=](MachineIRBuilder &
B) {
8009 if (CreateMask &&
Offset != 0) {
8010 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8011 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8012 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8013 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
8014 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8015 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8016 B.buildZExtOrTrunc(DstReg, ICmp);
8017 }
else if (CreateMask &&
Offset == 0) {
8018 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8019 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8020 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8021 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
8022 B.buildZExtOrTrunc(DstReg, ICmp);
8023 }
else if (!CreateMask &&
Offset != 0) {
8024 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8025 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
8026 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8027 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8028 B.buildZExtOrTrunc(DstReg, ICmp);
8029 }
else if (!CreateMask &&
Offset == 0) {
8030 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8031 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
8032 B.buildZExtOrTrunc(DstReg, ICmp);
8040bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
8046 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8058 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8064 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8065 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8066 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8067 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8078 if (LHS0 == RHS1 && LHS1 == RHS0) {
8084 if (LHS0 == RHS0 && LHS1 == RHS1) {
8088 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8090 MatchInfo = [=](MachineIRBuilder &
B) {
8095 auto False =
B.buildConstant(CmpTy, 0);
8096 B.buildZExtOrTrunc(DestReg, False);
8103 B.buildZExtOrTrunc(DestReg, True);
8105 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8106 B.buildZExtOrTrunc(DestReg, Cmp);
8118 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8121 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8130 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8133 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8148 bool IsSigned =
Add->isSigned();
8149 LLT DstTy =
MRI.getType(Dst);
8150 LLT CarryTy =
MRI.getType(Carry);
8153 if (
MRI.use_nodbg_empty(Carry) &&
8156 B.buildAdd(Dst, LHS, RHS);
8157 B.buildUndef(Carry);
8163 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8166 B.buildSAddo(Dst, Carry, RHS, LHS);
8172 B.buildUAddo(Dst, Carry, RHS, LHS);
8177 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8178 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8184 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8185 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8187 B.buildConstant(Dst, Result);
8188 B.buildConstant(Carry, Overflow);
8196 B.buildCopy(Dst, LHS);
8197 B.buildConstant(Carry, 0);
8206 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8209 std::optional<APInt> MaybeAddRHS =
8210 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8213 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8214 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8218 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8219 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8225 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8226 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8251 B.buildConstant(Carry, 0);
8258 B.buildAdd(Dst, LHS, RHS);
8259 B.buildConstant(Carry, 1);
8271 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8274 B.buildConstant(Carry, 0);
8290 B.buildConstant(Carry, 0);
8297 B.buildAdd(Dst, LHS, RHS);
8298 B.buildConstant(Carry, 1);
8316 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8322 auto [Dst,
Base] =
MI.getFirst2Regs();
8323 LLT Ty =
MRI.getType(Dst);
8327 Builder.buildFConstant(Dst, 1.0);
8328 MI.removeFromParent();
8340 std::optional<SrcOp> Res;
8342 while (ExpVal > 0) {
8347 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8350 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8357 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8361 MI.eraseFromParent();
8370 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8377 LLT DstTy =
MRI.getType(Dst);
8380 auto Const =
B.buildConstant(DstTy, C1 - C2);
8381 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8393 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8400 LLT DstTy =
MRI.getType(Dst);
8403 auto Const =
B.buildConstant(DstTy, C2 - C1);
8404 B.buildSub(Dst, Const,
Add->getLHSReg());
8416 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8423 LLT DstTy =
MRI.getType(Dst);
8426 auto Const =
B.buildConstant(DstTy, C1 + C2);
8439 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8446 LLT DstTy =
MRI.getType(Dst);
8449 auto Const =
B.buildConstant(DstTy, C1 - C2);
8462 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8469 LLT DstTy =
MRI.getType(Dst);
8472 auto Const =
B.buildConstant(DstTy, C2 - C1);
8473 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8520 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8524 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8527 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8528 LLT SmallBvTy = DstTy;
8532 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8537 {TargetOpcode::G_ANYEXT,
8549 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8550 Ops.push_back(AnyExt.getReg(0));
8568 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8569 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8570 const unsigned NumDstElts = OrigMask.
size();
8571 for (
unsigned i = 0; i != NumDstElts; ++i) {
8572 int Idx = OrigMask[i];
8573 if (Idx >= (
int)NumSrcElems) {
8584 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8585 std::move(NewMask));
8592 const unsigned MaskSize = Mask.size();
8593 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8598 if (Idx < (
int)NumElems)
8599 Mask[
I] = Idx + NumElems;
8601 Mask[
I] = Idx - NumElems;
8611 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8614 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8617 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8618 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8620 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8624 const unsigned NumSrcElems = Src1Ty.getNumElements();
8626 bool TouchesSrc1 =
false;
8627 bool TouchesSrc2 =
false;
8628 const unsigned NumElems = Mask.size();
8629 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8633 if (Mask[Idx] < (
int)NumSrcElems)
8639 if (TouchesSrc1 == TouchesSrc2)
8642 Register NewSrc1 = Shuffle.getSrc1Reg();
8645 NewSrc1 = Shuffle.getSrc2Reg();
8650 auto Undef =
B.buildUndef(Src1Ty);
8651 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8665 LLT DstTy =
MRI.getType(Dst);
8666 LLT CarryTy =
MRI.getType(Carry);
8688 B.buildConstant(Carry, 0);
8695 B.buildSub(Dst, LHS, RHS);
8713 B.buildConstant(Carry, 0);
8720 B.buildSub(Dst, LHS, RHS);
8737 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8738 "Expected G_CTLZ variant");
8743 LLT Ty =
MRI.getType(Dst);
8744 LLT SrcTy =
MRI.getType(Src);
8746 if (!(Ty.isValid() && Ty.isScalar()))
8755 switch (
LI->getAction(Query).Action) {
8766 bool NeedAdd =
true;
8774 unsigned BitWidth = Ty.getScalarSizeInBits();
8785 B.buildCTLS(Dst,
X);
8789 auto Ctls =
B.buildCTLS(Ty,
X);
8790 auto One =
B.buildConstant(Ty, 1);
8792 B.buildAdd(Dst, Ctls, One);
8802 unsigned TargetOpc)
const {
8803 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8804 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8805 "Expected G_LSHR/G_ASHR");
8808 return XTy ==
MRI.getType(
Y) &&
isLegal({TargetOpc, {XTy}});
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< 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 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 ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
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.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
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.
void applyCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
void applyPtrAddZero(MachineInstr &MI) const
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
void applyUDivOrURemByConst(MachineInstr &MI) const
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchAVG(MachineInstr &MI, MachineRegisterInfo &MRI, Register X, Register Y, unsigned TargetOpc) const
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchPtrAddZero(MachineInstr &MI) const
}
const TargetInstrInfo * TII
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
bool matchShiftsTooBig(MachineInstr &MI, std::optional< int64_t > &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
const DataLayout & getDataLayout() const
bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
void applyUMulHToLShr(MachineInstr &MI) const
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
bool isLegalOrHasFewerElements(const LegalityQuery &Query) const
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
const TargetLowering & getTargetLowering() const
bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
void applySDivByPow2(MachineInstr &MI) const
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
bool tryEmitMemcpyInline(MachineInstr &MI) const
Emit loads and stores that perform the given memcpy.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
void applyCombineCopy(MachineInstr &MI) const
bool matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
bool matchSextTruncSextLoad(MachineInstr &MI) const
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchCombineCopy(MachineInstr &MI) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
bool matchRedundantSExtInReg(MachineInstr &MI) const
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
bool tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool isPreLegalize() const
bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVMContext & getContext() const
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
bool matchConstantFoldUnaryIntOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold a unary integer op (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON variants,...
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
bool isLegal(const LegalityQuery &Query) const
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
bool matchOperandIsKnownToBeAPowerOfTwo(const MachineOperand &MO, bool OrNegative=false) const
Check if operand MO is known to be a power of 2.
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
void eraseInst(MachineInstr &MI) const
Erase MI.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
bool matchConstantFPOp(const MachineOperand &MOP, double C) const
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
void applySimplifySRemByPow2(MachineInstr &MI) const
Combine G_SREM x, (+/-2^k) to a bias-and-mask sequence.
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
void applyFunnelShiftToRotate(MachineInstr &MI) const
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
bool matchBinopWithNeg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold a bitwiseop (~b +/- c) -> a bitwiseop ~(b -/+ c)
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal) const
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applySDivOrSRemByConst(MachineInstr &MI) const
MachineInstr * buildSDivOrSRemUsingMul(MachineInstr &MI) const
Given an G_SDIV MI or G_SREM MI expressing a signed divide by constant, return an expression that imp...
bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
void applyCommuteBinOpOperands(MachineInstr &MI) const
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
void applySextTruncSextLoad(MachineInstr &MI) const
const MachineFunction & getMachineFunction() const
bool matchCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
Combine G_BUILD_VECTOR(G_UNMERGE(G_BITCAST), Undef) to G_BITCAST(G_BUILD_VECTOR(.....
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
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.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
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.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
@ 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.
FunctionAddr VTableAddr Value
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
@ 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)
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
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.
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 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...
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a float constant integer or a splat vector of float constant integers.
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.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
bool isNegative() const
Returns true if this value is known to be negative.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
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...