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();
593 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
594 "Invalid instruction kind");
595 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
597 LLT SrcType =
MRI.getType(Src1);
599 unsigned DstNumElts = DstType.getNumElements();
600 unsigned SrcNumElts = SrcType.getNumElements();
617 if (DstNumElts < 2 * SrcNumElts)
622 if (DstNumElts % SrcNumElts != 0)
628 unsigned NumConcat = DstNumElts / SrcNumElts;
631 for (
unsigned i = 0; i != DstNumElts; ++i) {
638 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
639 (ConcatSrcs[i / SrcNumElts] >= 0 &&
640 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
643 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
650 for (
auto Src : ConcatSrcs) {
654 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
656 Ops.push_back(UndefReg);
669 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
677 MI.eraseFromParent();
686 const LLT TyForCandidate,
687 unsigned OpcodeForCandidate,
692 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
703 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
706 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
707 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
708 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
716 OpcodeForCandidate == TargetOpcode::G_ZEXT)
718 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
719 OpcodeForCandidate == TargetOpcode::G_SEXT)
720 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
729 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
740static void InsertInsnsWithoutSideEffectsBeforeUse(
752 InsertBB = PredBB->
getMBB();
757 if (InsertBB ==
DefMI.getParent()) {
759 Inserter(InsertBB, std::next(InsertPt), UseMO);
778 unsigned CandidateLoadOpc;
780 case TargetOpcode::G_ANYEXT:
781 CandidateLoadOpc = TargetOpcode::G_LOAD;
783 case TargetOpcode::G_SEXT:
784 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
786 case TargetOpcode::G_ZEXT:
787 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
792 return CandidateLoadOpc;
809 LLT LoadValueTy =
MRI.getType(LoadReg);
831 unsigned PreferredOpcode =
833 ? TargetOpcode::G_ANYEXT
835 Preferred = {
LLT(), PreferredOpcode,
nullptr};
836 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
837 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
838 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
839 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
840 const auto &MMO = LoadMI->
getMMO();
848 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
850 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
854 Preferred = ChoosePreferredUse(
MI, Preferred,
855 MRI.getType(
UseMI.getOperand(0).getReg()),
865 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
883 if (PreviouslyEmitted) {
890 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
891 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
893 EmittedInsns[InsertIntoBB] = NewMI;
899 MI.setDesc(
Builder.getTII().get(LoadOpc));
906 for (
auto *UseMO :
Uses) {
912 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
915 const LLT UseDstTy =
MRI.getType(UseDstReg);
916 if (UseDstReg != ChosenDstReg) {
917 if (Preferred.
Ty == UseDstTy) {
954 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
969 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
972 MI.getOperand(0).setReg(ChosenDstReg);
978 assert(
MI.getOpcode() == TargetOpcode::G_AND);
989 if (
MRI.getType(Dst).isVector())
997 APInt MaskVal = MaybeMask->Value;
1006 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
1010 LLT RegTy =
MRI.getType(LoadReg);
1014 unsigned MaskSizeBits = MaskVal.
countr_one();
1018 if (MaskSizeBits > LoadSizeBits.
getValue())
1038 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
1044 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1048 B.setInstrAndDebugLoc(*LoadMI);
1049 auto &MF =
B.getMF();
1051 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
1052 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1061 "shouldn't consider debug uses");
1069 if (DefOrUse ==
MBB.end())
1071 return &*DefOrUse == &
DefMI;
1077 "shouldn't consider debug uses");
1080 else if (
DefMI.getParent() !=
UseMI.getParent())
1087 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1091 if (
MRI.getType(SrcReg).isVector())
1096 LoadUser = TruncSrc;
1098 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1103 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1105 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1107 if (LoadSizeBits == SizeInBits)
1114 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1115 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1116 MI.eraseFromParent();
1120 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1121 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1124 LLT RegTy =
MRI.getType(DstReg);
1132 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1135 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1140 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1143 if (NewSizeBits < 8)
1155 if (LoadDef->isSimple())
1157 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1162 {
MRI.getType(LoadDef->getDstReg()),
1163 MRI.getType(LoadDef->getPointerReg())},
1167 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1172 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1173 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1175 unsigned ScalarSizeBits;
1176 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1185 auto &MMO = LoadDef->
getMMO();
1186 Builder.setInstrAndDebugLoc(*LoadDef);
1188 auto PtrInfo = MMO.getPointerInfo();
1189 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1190 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1192 MI.eraseFromParent();
1203 auto *MF =
MI->getMF();
1210 AM.
BaseOffs = CstOff->getSExtValue();
1215 MF->getDataLayout(), AM,
1217 MF->getFunction().getContext()),
1218 MI->getMMO().getAddrSpace());
1223 case TargetOpcode::G_LOAD:
1224 return TargetOpcode::G_INDEXED_LOAD;
1225 case TargetOpcode::G_STORE:
1226 return TargetOpcode::G_INDEXED_STORE;
1227 case TargetOpcode::G_ZEXTLOAD:
1228 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1229 case TargetOpcode::G_SEXTLOAD:
1230 return TargetOpcode::G_INDEXED_SEXTLOAD;
1236bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1246 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1247 OpTys = {PtrTy, Ty, Ty};
1249 OpTys = {Ty, PtrTy};
1251 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1257 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1258 "considered for post-indexing."));
1262 bool &RematOffset)
const {
1275 if (!isIndexedLoadStoreLegal(LdSt))
1284 unsigned NumUsesChecked = 0;
1297 if (StoredValDef == &
Use)
1300 Offset = PtrAdd->getOffsetReg();
1302 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1308 RematOffset =
false;
1312 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1317 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1318 if (&BasePtrUse == PtrDef)
1324 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1326 isIndexedLoadStoreLegal(*BasePtrLdSt))
1332 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1333 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1336 if (BaseUseUse.getParent() != LdSt.
getParent())
1348 Addr = PtrAdd->getReg(0);
1349 Base = PtrAdd->getBaseReg();
1364 MRI.hasOneNonDBGUse(Addr))
1371 if (!isIndexedLoadStoreLegal(LdSt))
1375 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1380 if (
Base == St->getValueReg())
1385 if (St->getValueReg() == Addr)
1390 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1391 if (AddrUse.getParent() != LdSt.
getParent())
1396 bool RealUse =
false;
1397 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1415 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1425 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1432 if (!LoadMI->isSimple())
1444 const unsigned MaxIter = 20;
1447 if (
II->isLoadFoldBarrier())
1449 if (Iter++ == MaxIter)
1465 int Elt = CVal->getZExtValue();
1478 Register VecPtr = LoadMI->getPointerReg();
1479 LLT PtrTy =
MRI.getType(VecPtr);
1487 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1510 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1525 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1527 if (!MatchInfo.
IsPre &&
1528 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1538 unsigned Opcode =
MI.getOpcode();
1539 bool IsStore = Opcode == TargetOpcode::G_STORE;
1545 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1547 *OldCst->getOperand(1).getCImm());
1548 MatchInfo.
Offset = NewCst.getReg(0);
1551 auto MIB =
Builder.buildInstr(NewOpcode);
1553 MIB.addDef(MatchInfo.
Addr);
1554 MIB.addUse(
MI.getOperand(0).getReg());
1556 MIB.addDef(
MI.getOperand(0).getReg());
1557 MIB.addDef(MatchInfo.
Addr);
1560 MIB.addUse(MatchInfo.
Base);
1561 MIB.addUse(MatchInfo.
Offset);
1562 MIB.addImm(MatchInfo.
IsPre);
1563 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1564 MI.eraseFromParent();
1572 unsigned Opcode =
MI.getOpcode();
1573 bool IsDiv, IsSigned;
1578 case TargetOpcode::G_SDIV:
1579 case TargetOpcode::G_UDIV: {
1581 IsSigned = Opcode == TargetOpcode::G_SDIV;
1584 case TargetOpcode::G_SREM:
1585 case TargetOpcode::G_UREM: {
1587 IsSigned = Opcode == TargetOpcode::G_SREM;
1593 unsigned DivOpcode, RemOpcode, DivremOpcode;
1595 DivOpcode = TargetOpcode::G_SDIV;
1596 RemOpcode = TargetOpcode::G_SREM;
1597 DivremOpcode = TargetOpcode::G_SDIVREM;
1599 DivOpcode = TargetOpcode::G_UDIV;
1600 RemOpcode = TargetOpcode::G_UREM;
1601 DivremOpcode = TargetOpcode::G_UDIVREM;
1619 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1620 if (
MI.getParent() ==
UseMI.getParent() &&
1621 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1622 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1635 unsigned Opcode =
MI.getOpcode();
1636 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1639 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1640 DestDivReg =
MI.getOperand(0).getReg();
1644 DestRemReg =
MI.getOperand(0).getReg();
1648 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1655 Builder.setInstrAndDebugLoc(*FirstInst);
1657 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1658 : TargetOpcode::G_UDIVREM,
1659 {DestDivReg, DestRemReg},
1661 MI.eraseFromParent();
1667 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1684 if (BrIt ==
MBB->begin())
1686 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1688 BrCond = &*std::prev(BrIt);
1689 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1695 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1696 MBB->isLayoutSuccessor(BrCondTarget);
1702 Builder.setInstrAndDebugLoc(*BrCond);
1707 auto True =
Builder.buildConstant(
1713 MI.getOperand(0).setMBB(FallthroughBB);
1728 return Helper.lowerMemcpyInline(
MI) ==
1733 unsigned MaxLen)
const {
1745 switch (
MI.getOpcode()) {
1748 case TargetOpcode::G_FNEG: {
1749 Result.changeSign();
1752 case TargetOpcode::G_FABS: {
1756 case TargetOpcode::G_FCEIL:
1759 case TargetOpcode::G_FFLOOR:
1762 case TargetOpcode::G_INTRINSIC_TRUNC:
1765 case TargetOpcode::G_INTRINSIC_ROUND:
1768 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1771 case TargetOpcode::G_FRINT:
1772 case TargetOpcode::G_FNEARBYINT:
1776 case TargetOpcode::G_FPEXT:
1777 case TargetOpcode::G_FPTRUNC: {
1784 case TargetOpcode::G_FSQRT: {
1788 Result =
APFloat(sqrt(Result.convertToDouble()));
1791 case TargetOpcode::G_FLOG2: {
1811 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1812 MI.eraseFromParent();
1823 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1833 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1846 Type *AccessTy =
nullptr;
1847 auto &MF = *
MI.getMF();
1848 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1851 MF.getFunction().getContext());
1856 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1861 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1863 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1864 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1865 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1866 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1875 unsigned PtrAddFlags =
MI.getFlags();
1876 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1892 MatchInfo.
Flags = Flags;
1898 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1900 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1904 MI.getOperand(1).setReg(MatchInfo.
Base);
1905 MI.getOperand(2).setReg(NewOffset.getReg(0));
1919 unsigned Opcode =
MI.getOpcode();
1920 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1921 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1922 Opcode == TargetOpcode::G_USHLSAT) &&
1923 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1943 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1948 if (Opcode == TargetOpcode::G_USHLSAT &&
1949 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1957 unsigned Opcode =
MI.getOpcode();
1958 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1959 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1960 Opcode == TargetOpcode::G_USHLSAT) &&
1961 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1963 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1964 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1965 auto Imm = MatchInfo.
Imm;
1967 if (Imm >= ScalarSizeInBits) {
1969 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1970 Builder.buildConstant(
MI.getOperand(0), 0);
1971 MI.eraseFromParent();
1976 Imm = ScalarSizeInBits - 1;
1979 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1982 MI.getOperand(1).setReg(MatchInfo.
Reg);
1983 MI.getOperand(2).setReg(NewImm);
1999 unsigned ShiftOpcode =
MI.getOpcode();
2000 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2001 ShiftOpcode == TargetOpcode::G_ASHR ||
2002 ShiftOpcode == TargetOpcode::G_LSHR ||
2003 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2004 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2005 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2008 Register LogicDest =
MI.getOperand(1).getReg();
2009 if (!
MRI.hasOneNonDBGUse(LogicDest))
2013 unsigned LogicOpcode = LogicMI->
getOpcode();
2014 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2015 LogicOpcode != TargetOpcode::G_XOR)
2019 const Register C1 =
MI.getOperand(2).getReg();
2021 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2024 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2028 if (
MI->getOpcode() != ShiftOpcode ||
2029 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2038 ShiftVal = MaybeImmVal->Value.getSExtValue();
2049 if (matchFirstShift(LogicMIOp1, C0Val)) {
2051 MatchInfo.
Shift2 = LogicMIOp1;
2052 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2054 MatchInfo.
Shift2 = LogicMIOp2;
2058 MatchInfo.
ValSum = C0Val + C1Val;
2061 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2064 MatchInfo.
Logic = LogicMI;
2070 unsigned Opcode =
MI.getOpcode();
2071 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2072 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2073 Opcode == TargetOpcode::G_SSHLSAT) &&
2074 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2076 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2077 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2083 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2092 Register Shift2Const =
MI.getOperand(2).getReg();
2094 .buildInstr(Opcode, {DestType},
2104 MI.eraseFromParent();
2109 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2131 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2132 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2133 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2134 LLT SrcTy =
MRI.getType(SrcReg);
2136 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2137 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2138 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2146 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2150 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2165 LLT InnerShiftTy =
MRI.getType(InnerShift);
2167 if ((N1C + N001C).ult(InnerShiftSize)) {
2173 if ((N001C + OpSizeInBits) == InnerShiftSize)
2175 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2176 MatchInfo.
Mask =
true;
2186 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2193 if (MatchInfo.
Mask ==
true) {
2201 Builder.buildTrunc(Dst, Shift);
2202 MI.eraseFromParent();
2206 unsigned &ShiftVal)
const {
2207 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2213 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2214 return (
static_cast<int32_t
>(ShiftVal) != -1);
2218 unsigned &ShiftVal)
const {
2219 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2221 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2224 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2225 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2246 auto NegCst =
B.buildConstant(Ty, -Imm);
2248 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2249 MI.getOperand(2).setReg(NegCst.getReg(0));
2251 if (Imm.isMinSignedValue())
2261 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2276 if (!MaybeShiftAmtVal)
2280 LLT SrcTy =
MRI.getType(ExtSrc);
2290 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2291 MatchData.
Reg = ExtSrc;
2292 MatchData.
Imm = ShiftAmt;
2294 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2295 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2296 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2302 int64_t ShiftAmtVal = MatchData.
Imm;
2304 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2305 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2307 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2308 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2309 MI.eraseFromParent();
2316 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2320 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2323 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2324 if (MergedValues[
I] != Unmerge->getReg(
I))
2327 MatchInfo = Unmerge->getSourceReg();
2341 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2342 "Expected an unmerge");
2351 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2352 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2354 if (SrcMergeTy != Dst0Ty && !SameSize)
2358 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2359 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2365 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2366 "Expected an unmerge");
2368 "Not enough operands to replace all defs");
2369 unsigned NumElems =
MI.getNumOperands() - 1;
2371 LLT SrcTy =
MRI.getType(Operands[0]);
2372 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2373 bool CanReuseInputDirectly = DstTy == SrcTy;
2374 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2375 Register DstReg =
MI.getOperand(Idx).getReg();
2380 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2381 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2382 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2383 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2386 if (CanReuseInputDirectly)
2389 Builder.buildCast(DstReg, SrcReg);
2391 MI.eraseFromParent();
2396 unsigned SrcIdx =
MI.getNumOperands() - 1;
2397 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2399 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2400 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2408 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2411 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2413 Val = Val.
lshr(ShiftAmt);
2421 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2422 "Expected an unmerge");
2424 "Not enough operands to replace all defs");
2425 unsigned NumElems =
MI.getNumOperands() - 1;
2426 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2427 Register DstReg =
MI.getOperand(Idx).getReg();
2428 Builder.buildConstant(DstReg, Csts[Idx]);
2431 MI.eraseFromParent();
2437 unsigned SrcIdx =
MI.getNumOperands() - 1;
2438 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2440 unsigned NumElems =
MI.getNumOperands() - 1;
2441 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2442 Register DstReg =
MI.getOperand(Idx).getReg();
2443 B.buildUndef(DstReg);
2451 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2452 "Expected an unmerge");
2453 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2454 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2457 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2458 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2466 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2467 Register Dst0Reg =
MI.getOperand(0).getReg();
2468 Builder.buildTrunc(Dst0Reg, SrcReg);
2469 MI.eraseFromParent();
2473 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2474 "Expected an unmerge");
2475 Register Dst0Reg =
MI.getOperand(0).getReg();
2476 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2482 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2483 LLT SrcTy =
MRI.getType(SrcReg);
2484 if (SrcTy.isVector())
2494 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2499 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2500 "Expected an unmerge");
2502 Register Dst0Reg =
MI.getOperand(0).getReg();
2505 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2507 "Expecting a G_ZEXT");
2510 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2511 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2514 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2517 "ZExt src doesn't fit in destination");
2522 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2524 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2527 MI.eraseFromParent();
2531 unsigned TargetShiftSize,
2532 unsigned &ShiftVal)
const {
2533 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2534 MI.getOpcode() == TargetOpcode::G_LSHR ||
2535 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2537 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2542 unsigned Size = Ty.getSizeInBits();
2543 if (
Size <= TargetShiftSize)
2551 ShiftVal = MaybeImmVal->Value.getSExtValue();
2552 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2559 LLT Ty =
MRI.getType(SrcReg);
2560 unsigned Size = Ty.getSizeInBits();
2561 unsigned HalfSize =
Size / 2;
2562 assert(ShiftVal >= HalfSize);
2566 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2567 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2569 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2570 Register Narrowed = Unmerge.getReg(1);
2577 if (NarrowShiftAmt != 0) {
2578 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2579 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2582 auto Zero =
Builder.buildConstant(HalfTy, 0);
2583 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2584 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2585 Register Narrowed = Unmerge.getReg(0);
2590 if (NarrowShiftAmt != 0) {
2591 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2592 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2595 auto Zero =
Builder.buildConstant(HalfTy, 0);
2596 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2598 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2600 HalfTy, Unmerge.getReg(1),
2601 Builder.buildConstant(HalfTy, HalfSize - 1));
2603 if (ShiftVal == HalfSize) {
2606 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2607 }
else if (ShiftVal ==
Size - 1) {
2615 HalfTy, Unmerge.getReg(1),
2616 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2624 MI.eraseFromParent();
2640 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2642 LLT DstTy =
MRI.getType(DstReg);
2650 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2652 Builder.buildCopy(DstReg, Reg);
2653 MI.eraseFromParent();
2658 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2660 Builder.buildZExtOrTrunc(DstReg, Reg);
2661 MI.eraseFromParent();
2666 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2669 LLT IntTy =
MRI.getType(LHS);
2673 PtrReg.second =
false;
2674 for (
Register SrcReg : {LHS, RHS}) {
2678 LLT PtrTy =
MRI.getType(PtrReg.first);
2683 PtrReg.second =
true;
2695 const bool DoCommute = PtrReg.second;
2700 LLT PtrTy =
MRI.getType(LHS);
2702 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2703 Builder.buildPtrToInt(Dst, PtrAdd);
2704 MI.eraseFromParent();
2708 APInt &NewCst)
const {
2710 Register LHS = PtrAdd.getBaseReg();
2711 Register RHS = PtrAdd.getOffsetReg();
2717 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2720 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2729 APInt &NewCst)
const {
2733 Builder.buildConstant(Dst, NewCst);
2734 PtrAdd.eraseFromParent();
2739 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2744 SrcReg = OriginalSrcReg;
2745 LLT DstTy =
MRI.getType(DstReg);
2753 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2756 LLT DstTy =
MRI.getType(DstReg);
2761 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2762 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2772 if (ShiftSize > 32 && TruncSize < 32)
2785 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2786 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2790 if (!
MRI.hasOneNonDBGUse(SrcReg))
2793 LLT SrcTy =
MRI.getType(SrcReg);
2794 LLT DstTy =
MRI.getType(DstReg);
2803 case TargetOpcode::G_SHL: {
2812 case TargetOpcode::G_LSHR:
2813 case TargetOpcode::G_ASHR: {
2819 for (
auto &
User :
MRI.use_instructions(DstReg))
2820 if (
User.getOpcode() == TargetOpcode::G_STORE)
2824 if (NewShiftTy == SrcTy)
2838 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2841 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2846 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2848 LLT NewShiftTy = MatchInfo.second;
2851 LLT DstTy =
MRI.getType(Dst);
2855 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2859 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2862 if (NewShiftTy == DstTy)
2865 Builder.buildTrunc(Dst, NewShift);
2872 return MO.isReg() &&
2873 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2879 return !MO.isReg() ||
2880 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2885 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2887 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2891 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2892 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2897 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2898 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2904 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2905 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2906 "Expected an insert/extract element op");
2907 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2912 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2920 unsigned &
OpIdx)
const {
2926 OpIdx = Cst->isZero() ? 3 : 2;
2971 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2998 return MO.isReg() && MO.getReg().isPhysical();
3008 return I1->isIdenticalTo(*I2);
3016 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
3023 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
3035 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
3036 MaybeCst->getSExtValue() ==
C;
3043 std::optional<FPValueAndVReg> MaybeCst;
3047 return MaybeCst->Value.isExactlyValue(
C);
3051 unsigned OpIdx)
const {
3052 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3057 MI.eraseFromParent();
3062 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3066 MI.eraseFromParent();
3070 unsigned ConstIdx)
const {
3071 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3072 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3084 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3085 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3086 "This is not a funnel shift operation");
3088 Register ConstReg =
MI.getOperand(3).getReg();
3089 LLT ConstTy =
MRI.getType(ConstReg);
3090 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3093 assert((VRegAndVal) &&
"Value is not a constant");
3096 APInt NewConst = VRegAndVal->Value.
urem(
3101 MI.getOpcode(), {MI.getOperand(0)},
3102 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3104 MI.eraseFromParent();
3108 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3122 unsigned OpIdx)
const {
3124 return MO.
isReg() &&
3135 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3137 MI.eraseFromParent();
3142 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3144 MI.eraseFromParent();
3148 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3150 MI.eraseFromParent();
3155 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3157 MI.eraseFromParent();
3161 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3163 MI.eraseFromParent();
3167 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3170 Register &NewLHS = std::get<0>(MatchInfo);
3171 Register &NewRHS = std::get<1>(MatchInfo);
3179 NewLHS = MaybeNewLHS;
3183 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3188 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3191 LLT DstTy =
MRI.getType(DstReg);
3200 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3201 TargetOpcode::G_INSERT_VECTOR_ELT)
3207 MatchInfo.
resize(NumElts);
3211 if (IntImm >= NumElts || IntImm < 0)
3213 if (!MatchInfo[IntImm])
3214 MatchInfo[IntImm] = TmpReg;
3218 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3220 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3229 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3236 auto GetUndef = [&]() {
3239 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3247 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3248 MI.eraseFromParent();
3252 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3254 std::tie(SubLHS, SubRHS) = MatchInfo;
3255 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3256 MI.eraseFromParent();
3269 unsigned InnerOpc = InnerDef->
getOpcode();
3270 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3293 if (!TryMatch(InnerLHS, InnerRHS) && !TryMatch(InnerRHS, InnerLHS))
3297 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3298 : TargetOpcode::G_ADD;
3301 MatchInfo = [=](MachineIRBuilder &
Builder) {
3302 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3303 auto NewNot =
Builder.buildNot(Ty, NewInner);
3304 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3316 unsigned RootOpc =
MI.getOpcode();
3318 LLT Ty =
MRI.getType(Dst);
3323 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3324 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3335 unsigned LogicOpcode =
MI.getOpcode();
3336 assert(LogicOpcode == TargetOpcode::G_AND ||
3337 LogicOpcode == TargetOpcode::G_OR ||
3338 LogicOpcode == TargetOpcode::G_XOR);
3345 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3351 if (!LeftHandInst || !RightHandInst)
3353 unsigned HandOpcode = LeftHandInst->
getOpcode();
3354 if (HandOpcode != RightHandInst->
getOpcode())
3368 if (!XTy.
isValid() || XTy != YTy)
3373 switch (HandOpcode) {
3376 case TargetOpcode::G_ANYEXT:
3377 case TargetOpcode::G_SEXT:
3378 case TargetOpcode::G_ZEXT: {
3382 case TargetOpcode::G_TRUNC: {
3387 LLT DstTy =
MRI.getType(Dst);
3396 case TargetOpcode::G_AND:
3397 case TargetOpcode::G_ASHR:
3398 case TargetOpcode::G_LSHR:
3399 case TargetOpcode::G_SHL: {
3404 ExtraHandOpSrcReg = ZOp.
getReg();
3415 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3426 if (ExtraHandOpSrcReg.
isValid())
3438 "Expected at least one instr to build?");
3440 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3441 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3443 for (
auto &OperandFn : InstrToBuild.OperandFns)
3446 MI.eraseFromParent();
3450 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3451 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3452 int64_t ShlCst, AshrCst;
3458 if (ShlCst != AshrCst)
3461 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3463 MatchInfo = std::make_tuple(Src, ShlCst);
3468 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3469 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3472 std::tie(Src, ShiftAmt) = MatchInfo;
3473 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3474 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3475 MI.eraseFromParent();
3482 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3485 LLT Ty =
MRI.getType(Dst);
3497 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3500 auto Zero =
B.buildConstant(Ty, 0);
3523 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3547 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3554 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3571 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3589 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3596 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3607 unsigned ExtBits =
MI.getOperand(2).getImm();
3608 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3609 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3613 int64_t Cst,
bool IsVector,
bool IsFP) {
3615 return (ScalarSizeBits == 1 && Cst == -1) ||
3637 unsigned BuildUseCount = BV.getNumSources();
3638 if (BuildUseCount % 2 != 0)
3641 unsigned NumUnmerge = BuildUseCount / 2;
3647 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3650 UnmergeSrc = Unmerge->getSourceReg();
3652 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3653 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3660 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3665 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3666 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3669 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3672 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3677 if (Unmerge->getNumDefs() != NumUnmerge)
3681 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3684 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3695 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3696 B.setInstrAndDebugLoc(
MI);
3698 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3699 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3701 MI.eraseFromParent();
3723 unsigned NumOperands =
BuildMI->getNumSources();
3733 for (
I = 0;
I < NumOperands; ++
I) {
3734 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3735 auto SrcMIOpc = SrcMI->getOpcode();
3738 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3739 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3741 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3742 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3745 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3746 if (UnmergeMI != UnmergeSrcMI)
3761 for (;
I < NumOperands; ++
I) {
3762 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3763 auto SrcMIOpc = SrcMI->getOpcode();
3765 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3771 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3778 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3779 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3787 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3790 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3802 LLT DstTy =
MRI.getType(DstReg);
3803 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3808 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3813 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3817 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3820 Builder.buildTrunc(DstReg, MidReg);
3821 MI.eraseFromParent();
3826 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3827 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3828 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3836 if (!
MRI.hasOneNonDBGUse(XorSrc))
3846 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3848 if (!
MRI.hasOneNonDBGUse(Reg))
3851 switch (Def->getOpcode()) {
3856 case TargetOpcode::G_ICMP:
3862 case TargetOpcode::G_FCMP:
3868 case TargetOpcode::G_AND:
3869 case TargetOpcode::G_OR:
3875 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3876 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3884 if (Ty.isVector()) {
3889 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3903 for (
Register Reg : RegsToNegate) {
3908 switch (Def->getOpcode()) {
3911 case TargetOpcode::G_ICMP:
3912 case TargetOpcode::G_FCMP: {
3919 case TargetOpcode::G_AND:
3920 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3922 case TargetOpcode::G_OR:
3923 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3930 MI.eraseFromParent();
3934 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3936 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3940 Register SharedReg =
MI.getOperand(2).getReg();
3954 if (!
MRI.hasOneNonDBGUse(AndReg))
3961 return Y == SharedReg;
3965 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3968 std::tie(
X,
Y) = MatchInfo;
3971 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3972 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3973 MI.getOperand(2).setReg(
Y);
3979 Register DstReg = PtrAdd.getReg(0);
3980 LLT Ty =
MRI.getType(DstReg);
3983 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3986 if (Ty.isPointer()) {
3988 return ConstVal && *ConstVal == 0;
3991 assert(Ty.isVector() &&
"Expecting a vector type");
3998 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3999 PtrAdd.eraseFromParent();
4006 Register Pow2Src1 =
MI.getOperand(2).getReg();
4007 LLT Ty =
MRI.getType(DstReg);
4010 auto NegOne =
Builder.buildConstant(Ty, -1);
4011 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
4013 MI.eraseFromParent();
4017 unsigned &SelectOpNo)
const {
4027 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
4028 !
MRI.hasOneNonDBGUse(LHS)) {
4029 OtherOperandReg = LHS;
4032 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
4033 !
MRI.hasOneNonDBGUse(RHS))
4049 unsigned BinOpcode =
MI.getOpcode();
4054 bool CanFoldNonConst =
4055 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4060 if (CanFoldNonConst)
4081 LLT Ty =
MRI.getType(Dst);
4082 unsigned BinOpcode =
MI.getOpcode();
4089 if (SelectOperand == 1) {
4093 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4095 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4097 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4099 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4102 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4103 MI.eraseFromParent();
4106std::optional<SmallVector<Register, 8>>
4107CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4108 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4137 const unsigned MaxIter =
4139 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4148 return std::nullopt;
4164 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4165 return std::nullopt;
4177static std::optional<std::pair<GZExtLoad *, int64_t>>
4181 "Expected Reg to only have one non-debug use?");
4190 if (Shift % MemSizeInBits != 0)
4191 return std::nullopt;
4196 return std::nullopt;
4198 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4199 return std::nullopt;
4201 return std::make_pair(Load, Shift / MemSizeInBits);
4204std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4205CombinerHelper::findLoadOffsetsForLoadOrCombine(
4208 const unsigned MemSizeInBits)
const {
4211 SmallSetVector<const MachineInstr *, 8> Loads;
4217 GZExtLoad *LowestIdxLoad =
nullptr;
4220 SmallSet<int64_t, 8> SeenIdx;
4224 MachineBasicBlock *
MBB =
nullptr;
4225 const MachineMemOperand *MMO =
nullptr;
4228 GZExtLoad *EarliestLoad =
nullptr;
4231 GZExtLoad *LatestLoad =
nullptr;
4240 for (
auto Reg : RegsToVisit) {
4245 return std::nullopt;
4248 std::tie(Load, DstPos) = *LoadAndPos;
4252 MachineBasicBlock *LoadMBB =
Load->getParent();
4256 return std::nullopt;
4259 auto &LoadMMO =
Load->getMMO();
4263 return std::nullopt;
4270 LoadPtr =
Load->getOperand(1).getReg();
4275 if (!SeenIdx.
insert(Idx).second)
4276 return std::nullopt;
4283 if (BasePtr != LoadPtr)
4284 return std::nullopt;
4286 if (Idx < LowestIdx) {
4288 LowestIdxLoad =
Load;
4295 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4296 return std::nullopt;
4304 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4305 EarliestLoad =
Load;
4306 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4313 "Expected to find a load for each register?");
4314 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4315 LatestLoad &&
"Expected at least two loads?");
4324 const unsigned MaxIter = 20;
4330 if (
MI.isLoadFoldBarrier())
4331 return std::nullopt;
4332 if (Iter++ == MaxIter)
4333 return std::nullopt;
4336 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4342 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4355 LLT Ty =
MRI.getType(Dst);
4361 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4362 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4366 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4373 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4374 if (NarrowMemSizeInBits % 8 != 0)
4387 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4388 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4391 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4398 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4401 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4413 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4414 const unsigned ZeroByteOffset =
4418 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4419 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4420 ZeroOffsetIdx->second != LowestIdx)
4430 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4444 MIB.setInstrAndDebugLoc(*LatestLoad);
4445 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4446 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4448 MIB.buildBSwap(Dst, LoadDst);
4460 if (
MRI.getType(DstReg).isVector())
4464 if (!
MRI.hasOneNonDBGUse(DstReg))
4466 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4468 case TargetOpcode::G_ANYEXT:
4470 case TargetOpcode::G_ZEXT:
4471 case TargetOpcode::G_SEXT:
4478 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4485 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4487 switch (
DefMI->getOpcode()) {
4488 case TargetOpcode::G_LOAD:
4489 case TargetOpcode::G_TRUNC:
4490 case TargetOpcode::G_SEXT:
4491 case TargetOpcode::G_ZEXT:
4492 case TargetOpcode::G_ANYEXT:
4493 case TargetOpcode::G_CONSTANT:
4497 if (InSrcs.
size() > 2)
4511 LLT ExtTy =
MRI.getType(DstReg);
4518 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4519 auto SrcReg =
PHI.getIncomingValue(
I);
4520 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4521 if (!SrcMIs.
insert(SrcMI))
4525 auto *
MBB = SrcMI->getParent();
4527 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4528 InsertPt =
MBB->getFirstNonPHI();
4530 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4533 OldToNewSrcMap[SrcMI] = NewExt;
4538 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4539 NewPhi.addDef(DstReg);
4542 NewPhi.addMBB(MO.getMBB());
4545 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4546 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4554 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4558 LLT SrcTy =
MRI.getType(SrcVec);
4559 if (SrcTy.isScalableVector())
4563 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4566 unsigned VecIdx = Cst->Value.getZExtValue();
4571 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4575 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4576 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4580 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4592 LLT ScalarTy =
MRI.getType(Reg);
4594 LLT DstTy =
MRI.getType(DstReg);
4596 if (ScalarTy != DstTy) {
4598 Builder.buildTrunc(DstReg, Reg);
4599 MI.eraseFromParent();
4607 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4608 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4626 LLT DstTy =
MRI.getType(DstReg);
4631 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4636 unsigned Idx = Cst->getZExtValue();
4639 ExtractedElts.
set(Idx);
4640 SrcDstPairs.emplace_back(
4641 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4644 return ExtractedElts.
all();
4649 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4650 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4651 for (
auto &Pair : SrcDstPairs) {
4652 auto *ExtMI = Pair.second;
4654 ExtMI->eraseFromParent();
4656 MI.eraseFromParent();
4663 MI.eraseFromParent();
4673 bool AllowScalarConstants,
4675 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4678 LLT Ty =
MRI.getType(Dst);
4679 unsigned BitWidth = Ty.getScalarSizeInBits();
4681 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4682 unsigned FshOpc = 0;
4693 int64_t CstShlAmt = 0, CstLShrAmt;
4696 CstShlAmt + CstLShrAmt ==
BitWidth) {
4697 FshOpc = TargetOpcode::G_FSHR;
4703 FshOpc = TargetOpcode::G_FSHL;
4708 FshOpc = TargetOpcode::G_FSHR;
4713 LLT AmtTy =
MRI.getType(Amt);
4715 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4719 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4726 unsigned Opc =
MI.getOpcode();
4727 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4732 unsigned RotateOpc =
4733 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4738 unsigned Opc =
MI.getOpcode();
4739 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4740 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4742 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4743 : TargetOpcode::G_ROTR));
4744 MI.removeOperand(2);
4750 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4751 MI.getOpcode() == TargetOpcode::G_ROTR);
4753 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4755 bool OutOfRange =
false;
4756 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4758 OutOfRange |= CI->getValue().uge(Bitsize);
4765 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4766 MI.getOpcode() == TargetOpcode::G_ROTR);
4768 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4770 LLT AmtTy =
MRI.getType(Amt);
4771 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4772 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4774 MI.getOperand(2).setReg(Amt);
4779 int64_t &MatchInfo)
const {
4780 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4791 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4792 if (KnownRHS.isUnknown())
4795 std::optional<bool> KnownVal;
4796 if (KnownRHS.isZero()) {
4806 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4816 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4825 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4841 LLT DstTy =
MRI.getType(Dst);
4849 auto KnownLHS =
VT->getKnownBits(LHS);
4850 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4853 LLT LHSTy =
MRI.getType(LHS);
4856 unsigned Op = TargetOpcode::COPY;
4857 if (DstSize != LHSSize)
4858 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4869 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4873 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4879 int64_t AndMaskBits;
4887 if (AndMaskBits & OrMaskBits)
4893 if (
MI.getOperand(1).getReg() == AndMaskReg)
4894 MI.getOperand(2).setReg(AndMaskReg);
4895 MI.getOperand(1).setReg(Src);
4905 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4908 LLT Ty =
MRI.getType(Src);
4910 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4912 int64_t Width =
MI.getOperand(2).getImm();
4920 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4924 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4925 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4926 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4936 LLT Ty =
MRI.getType(Dst);
4940 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4943 int64_t AndImm, LSBImm;
4945 const unsigned Size = Ty.getScalarSizeInBits();
4952 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4953 if (MaybeMask & (MaybeMask + 1))
4962 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4963 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4964 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4972 const unsigned Opcode =
MI.getOpcode();
4973 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4975 const Register Dst =
MI.getOperand(0).getReg();
4977 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4978 ? TargetOpcode::G_SBFX
4979 : TargetOpcode::G_UBFX;
4982 LLT Ty =
MRI.getType(Dst);
4984 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4990 const unsigned Size = Ty.getScalarSizeInBits();
5000 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
5004 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
5008 const int64_t Pos = ShrAmt - ShlAmt;
5009 const int64_t Width =
Size - ShrAmt;
5012 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5013 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5014 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
5022 const unsigned Opcode =
MI.getOpcode();
5023 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
5025 const Register Dst =
MI.getOperand(0).getReg();
5026 LLT Ty =
MRI.getType(Dst);
5028 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
5041 const unsigned Size = Ty.getScalarSizeInBits();
5042 if (ShrAmt < 0 || ShrAmt >=
Size)
5046 if (0 == (SMask >> ShrAmt)) {
5048 B.buildConstant(Dst, 0);
5054 uint64_t UMask = SMask;
5061 const int64_t Pos = ShrAmt;
5066 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5070 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5071 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5072 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5077bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5081 Register Src1Reg = PtrAdd.getBaseReg();
5086 Register Src2Reg = PtrAdd.getOffsetReg();
5088 if (
MRI.hasOneNonDBGUse(Src1Reg))
5098 const APInt &C1APIntVal = *C1;
5099 const APInt &C2APIntVal = *C2;
5100 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5102 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5105 MachineInstr *ConvUseMI = &
UseMI;
5106 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5107 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5108 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5110 if (!
MRI.hasOneNonDBGUse(DefReg))
5112 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5121 TargetLoweringBase::AddrMode AM;
5124 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5126 PtrAdd.getMF()->getFunction().getContext());
5127 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5128 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5134 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5146 Register Src1Reg =
MI.getOperand(1).getReg();
5147 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5159 unsigned PtrAddFlags =
MI.getFlags();
5160 unsigned AddFlags = RHS->getFlags();
5173 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5176 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5178 MI.getOperand(1).setReg(NewBase.getReg(0));
5179 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5183 return !reassociationCanBreakAddressingModePattern(
MI);
5193 std::optional<ValueAndVReg> LHSCstOff;
5203 unsigned PtrAddFlags =
MI.getFlags();
5204 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5206 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5208 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5222 LHSPtrAdd->moveBefore(&
MI);
5225 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5227 MI.getOperand(2).setReg(NewCst.getReg(0));
5230 Observer.changingInstr(*LHSPtrAdd);
5231 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5232 LHSPtrAdd->setFlags(Flags);
5235 return !reassociationCanBreakAddressingModePattern(
MI);
5246 Register Src2Reg =
MI.getOperand(2).getReg();
5247 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5248 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5261 unsigned PtrAddFlags =
MI.getFlags();
5262 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5275 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5277 MI.getOperand(1).setReg(LHSSrc1);
5278 MI.getOperand(2).setReg(NewCst.getReg(0));
5282 return !reassociationCanBreakAddressingModePattern(
MI);
5320 LLT OpRHSTy =
MRI.getType(OpRHS);
5339 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5340 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5348 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5349 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5362 unsigned Opc =
MI.getOpcode();
5375 APInt &MatchInfo)
const {
5376 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5380 MatchInfo = *MaybeCst;
5391 MI.getOperand(1).getReg(),
MRI);
5396 if (Csts.size() == 1)
5397 B.buildConstant(Dst, Csts[0]);
5399 B.buildBuildVectorConstant(Dst, Csts);
5405 APInt &MatchInfo)
const {
5411 MatchInfo = *MaybeCst;
5423 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5429 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5430 MI.getOpcode() == TargetOpcode::G_FMAD);
5431 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5448 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5471 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5475 LLT WideTy =
MRI.getType(Dst);
5479 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5495 case TargetOpcode::G_ADD:
5496 case TargetOpcode::G_SUB:
5497 case TargetOpcode::G_MUL:
5498 case TargetOpcode::G_AND:
5499 case TargetOpcode::G_OR:
5500 case TargetOpcode::G_XOR:
5508 auto Mask = Cst->Value;
5513 unsigned NarrowWidth = Mask.countr_one();
5519 auto &MF = *
MI.getMF();
5522 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5523 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5531 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5532 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5534 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5535 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5537 MI.getOperand(1).setReg(Ext.getReg(0));
5545 unsigned Opc =
MI.getOpcode();
5546 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5553 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5554 : TargetOpcode::G_SADDO;
5555 MI.setDesc(
Builder.getTII().get(NewOpc));
5556 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5565 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5566 MI.getOpcode() == TargetOpcode::G_SMULO);
5575 B.buildConstant(Dst, 0);
5576 B.buildConstant(Carry, 0);
5585 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5586 MI.getOpcode() == TargetOpcode::G_SADDE ||
5587 MI.getOpcode() == TargetOpcode::G_USUBE ||
5588 MI.getOpcode() == TargetOpcode::G_SSUBE);
5593 switch (
MI.getOpcode()) {
5594 case TargetOpcode::G_UADDE:
5595 NewOpcode = TargetOpcode::G_UADDO;
5597 case TargetOpcode::G_SADDE:
5598 NewOpcode = TargetOpcode::G_SADDO;
5600 case TargetOpcode::G_USUBE:
5601 NewOpcode = TargetOpcode::G_USUBO;
5603 case TargetOpcode::G_SSUBE:
5604 NewOpcode = TargetOpcode::G_SSUBO;
5608 MI.setDesc(
B.getTII().get(NewOpcode));
5609 MI.removeOperand(4);
5617 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5650 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5651 B.buildSub(Dst, Zero, ReplaceReg);
5660 unsigned Opcode =
MI.getOpcode();
5661 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5663 Register Dst = UDivorRem.getReg(0);
5664 Register LHS = UDivorRem.getReg(1);
5665 Register RHS = UDivorRem.getReg(2);
5666 LLT Ty =
MRI.getType(Dst);
5674 bool UseSRL =
false;
5679 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5681 if (IsSplat && !Factors.
empty()) {
5688 APInt Divisor = CI->getValue();
5697 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5698 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5708 if (Ty.isVector()) {
5709 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5710 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5713 Factor = Factors[0];
5721 return MIB.buildMul(Ty, Res, Factor);
5724 unsigned KnownLeadingZeros =
5725 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5727 bool UseNPQ =
false;
5729 auto BuildUDIVPattern = [&](
const Constant *
C) {
5731 const APInt &Divisor = CI->getValue();
5733 bool SelNPQ =
false;
5735 unsigned PreShift = 0, PostShift = 0;
5740 if (!Divisor.
isOne()) {
5746 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5748 Magic = std::move(magics.
Magic);
5751 "We shouldn't generate an undefined shift!");
5753 "We shouldn't generate an undefined shift!");
5757 SelNPQ = magics.
IsAdd;
5761 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5762 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5764 MIB.buildConstant(ScalarTy,
5769 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5777 assert(Matched &&
"Expected unary predicate match to succeed");
5779 Register PreShift, PostShift, MagicFactor, NPQFactor;
5782 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5783 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5784 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5785 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5788 "Non-build_vector operation should have been a scalar");
5789 PreShift = PreShifts[0];
5790 MagicFactor = MagicFactors[0];
5791 PostShift = PostShifts[0];
5795 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5798 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5801 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5806 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5808 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5810 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5813 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5814 auto One = MIB.buildConstant(Ty, 1);
5815 auto IsOne = MIB.buildICmp(
5819 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5821 if (Opcode == TargetOpcode::G_UREM) {
5822 auto Prod = MIB.buildMul(Ty, ret, RHS);
5823 return MIB.buildSub(Ty, LHS, Prod);
5829 unsigned Opcode =
MI.getOpcode();
5830 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5833 LLT DstTy =
MRI.getType(Dst);
5835 auto &MF = *
MI.getMF();
5836 AttributeList Attr = MF.getFunction().getAttributes();
5845 if (MF.getFunction().hasMinSize())
5848 if (Opcode == TargetOpcode::G_UDIV &&
5851 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5854 auto *RHSDef =
MRI.getVRegDef(RHS);
5865 {TargetOpcode::G_ICMP,
5869 if (Opcode == TargetOpcode::G_UREM &&
5875 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5884 unsigned Opcode =
MI.getOpcode();
5885 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5888 LLT DstTy =
MRI.getType(Dst);
5892 auto &MF = *
MI.getMF();
5893 AttributeList Attr = MF.getFunction().getAttributes();
5902 if (MF.getFunction().hasMinSize())
5906 if (Opcode == TargetOpcode::G_SDIV &&
5909 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5912 auto *RHSDef =
MRI.getVRegDef(RHS);
5920 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5923 if (Opcode == TargetOpcode::G_SREM &&
5929 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5938 unsigned Opcode =
MI.getOpcode();
5939 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5940 Opcode == TargetOpcode::G_SREM);
5942 Register Dst = SDivorRem.getReg(0);
5943 Register LHS = SDivorRem.getReg(1);
5944 Register RHS = SDivorRem.getReg(2);
5945 LLT Ty =
MRI.getType(Dst);
5952 bool UseSRA =
false;
5958 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5960 if (IsSplat && !ExactFactors.
empty()) {
5962 ExactFactors.
push_back(ExactFactors[0]);
5967 APInt Divisor = CI->getValue();
5977 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5978 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5986 assert(Matched &&
"Expected unary predicate match to succeed");
5989 if (Ty.isVector()) {
5990 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5991 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5993 Shift = ExactShifts[0];
5994 Factor = ExactFactors[0];
6002 return MIB.buildMul(Ty, Res, Factor);
6007 auto BuildSDIVPattern = [&](
const Constant *
C) {
6009 const APInt &Divisor = CI->getValue();
6013 int NumeratorFactor = 0;
6024 NumeratorFactor = 1;
6027 NumeratorFactor = -1;
6030 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
6031 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
6033 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
6034 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
6042 assert(Matched &&
"Expected unary predicate match to succeed");
6044 Register MagicFactor, Factor, Shift, ShiftMask;
6047 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
6048 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
6049 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
6050 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
6053 "Non-build_vector operation should have been a scalar");
6054 MagicFactor = MagicFactors[0];
6055 Factor = Factors[0];
6057 ShiftMask = ShiftMasks[0];
6061 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6064 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6065 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6068 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6071 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6072 auto T = MIB.buildLShr(Ty, Q, SignShift);
6073 T = MIB.buildAnd(Ty,
T, ShiftMask);
6074 auto ret = MIB.buildAdd(Ty, Q,
T);
6076 if (Opcode == TargetOpcode::G_SREM) {
6077 auto Prod = MIB.buildMul(Ty, ret, RHS);
6078 return MIB.buildSub(Ty, LHS, Prod);
6084 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6085 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6086 "Expected SDIV or UDIV");
6089 auto MatchPow2 = [&](
const Constant *
C) {
6091 return CI && (CI->getValue().isPowerOf2() ||
6092 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6098 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6103 LLT Ty =
MRI.getType(Dst);
6123 unsigned BitWidth = Ty.getScalarSizeInBits();
6124 auto Zero =
Builder.buildConstant(Ty, 0);
6127 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6128 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6130 auto Sign =
Builder.buildAShr(
6134 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6140 auto One =
Builder.buildConstant(Ty, 1);
6141 auto MinusOne =
Builder.buildConstant(Ty, -1);
6145 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6146 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6150 auto Neg =
Builder.buildNeg(Ty, AShr);
6152 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6153 MI.eraseFromParent();
6157 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6162 LLT Ty =
MRI.getType(Dst);
6165 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6166 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6167 MI.eraseFromParent();
6171 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6176 LLT Ty =
MRI.getType(Dst);
6195 unsigned BitWidth = Ty.getScalarSizeInBits();
6196 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6197 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6199 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6200 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6201 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6204 MI.eraseFromParent();
6208 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6211 LLT Ty =
MRI.getType(Dst);
6212 LLT RHSTy =
MRI.getType(RHS);
6214 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6216 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6231 LLT Ty =
MRI.getType(Dst);
6237 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6238 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6239 Builder.buildLShr(Dst, LHS, Trunc);
6240 MI.eraseFromParent();
6247 LLT DstTy =
MRI.getType(Dst);
6248 LLT SrcTy =
MRI.getType(Src);
6250 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6251 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6254 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6272 Builder.buildTruncSSatS(Dst, MatchInfo);
6273 MI.eraseFromParent();
6280 LLT DstTy =
MRI.getType(Dst);
6281 LLT SrcTy =
MRI.getType(Src);
6283 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6284 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6287 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6305 Builder.buildTruncSSatU(Dst, MatchInfo);
6306 MI.eraseFromParent();
6313 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6314 LLT SrcTy =
MRI.getType(Val);
6316 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6317 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6320 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6329 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6338 unsigned Opc =
MI.getOpcode();
6339 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6340 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6341 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6353 Opc = TargetOpcode::G_FSUB;
6358 Opc = TargetOpcode::G_FADD;
6364 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6365 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6374 MI.setDesc(
B.getTII().get(
Opc));
6375 MI.getOperand(1).setReg(
X);
6376 MI.getOperand(2).setReg(
Y);
6384 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6387 MatchInfo =
MI.getOperand(2).getReg();
6388 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6390 const auto LHSCst = Ty.isVector()
6397 if (LHSCst->Value.isNegZero())
6401 if (LHSCst->Value.isPosZero())
6411 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6418 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6432 bool &AllowFusionGlobally,
6434 bool CanReassociate)
const {
6436 auto *MF =
MI.getMF();
6437 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6439 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6447 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6450 if (!HasFMAD && !HasFMA)
6458 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6465 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6467 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6475 unsigned PreferredFusedOpcode =
6476 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6490 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6491 {LHS.MI->getOperand(1).getReg(),
6492 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6501 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6502 {RHS.MI->getOperand(1).getReg(),
6503 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6514 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6516 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6520 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6525 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6527 unsigned PreferredFusedOpcode =
6528 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6542 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6547 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6548 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6557 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6562 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6563 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6574 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6576 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6584 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6586 unsigned PreferredFusedOpcode =
6587 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6600 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6601 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6602 TargetOpcode::G_FMUL) &&
6603 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6604 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6609 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6610 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6611 TargetOpcode::G_FMUL) &&
6612 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6613 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6620 Register X = FMA->getOperand(1).getReg();
6621 Register Y = FMA->getOperand(2).getReg();
6626 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6627 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6628 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6640 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6642 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6649 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6650 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6656 unsigned PreferredFusedOpcode =
6657 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6670 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6671 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6673 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6675 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6682 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6686 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6691 LHS.MI->getOperand(1).getReg(),
6692 LHS.MI->getOperand(2).getReg(),
B);
6703 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6706 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6711 X =
B.buildFPExt(DstType,
X).getReg(0);
6712 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6723 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6727 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6732 RHS.MI->getOperand(1).getReg(),
6733 RHS.MI->getOperand(2).getReg(),
B);
6744 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6747 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6752 X =
B.buildFPExt(DstType,
X).getReg(0);
6753 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6767 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6769 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6777 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6781 int FirstMulHasFewerUses =
true;
6785 FirstMulHasFewerUses =
false;
6787 unsigned PreferredFusedOpcode =
6788 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6791 if (FirstMulHasFewerUses &&
6795 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6796 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6797 {LHS.MI->getOperand(1).getReg(),
6798 LHS.MI->getOperand(2).getReg(), NegZ});
6807 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6808 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6809 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6820 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6822 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6828 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6830 unsigned PreferredFusedOpcode =
6831 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6842 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6843 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6855 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6868 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6870 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6876 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6878 unsigned PreferredFusedOpcode =
6879 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6891 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6892 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6893 {FpExtX, FpExtY, NegZ});
6905 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6908 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6909 {NegY, FpExtZ, LHSReg});
6920 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6922 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6926 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6927 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6931 unsigned PreferredFusedOpcode =
6932 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6936 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6937 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6938 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6949 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6952 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6955 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6965 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6978 unsigned &IdxToPropagate)
const {
6980 switch (
MI.getOpcode()) {
6983 case TargetOpcode::G_FMINNUM:
6984 case TargetOpcode::G_FMAXNUM:
6985 PropagateNaN =
false;
6987 case TargetOpcode::G_FMINIMUM:
6988 case TargetOpcode::G_FMAXIMUM:
6989 PropagateNaN =
true;
6993 auto MatchNaN = [&](
unsigned Idx) {
6994 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6998 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
7002 return MatchNaN(1) || MatchNaN(2);
7010 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
7020 return N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0));
7037 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
7038 if (&U == &
MI || U.getParent() !=
MI.getParent())
7040 if (U.getOpcode() == TargetOpcode::G_FDIV &&
7041 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
7042 !IsOne(U.getOperand(1).getReg())) {
7055 return MatchInfo.
size() >= MinUses;
7063 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7064 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7065 MatchInfo[0]->getOperand(2).getReg(),
7066 MatchInfo[0]->getFlags());
7071 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7072 Div->getOperand(0).getReg(),
MI->getFlags());
7073 MI->eraseFromParent();
7078 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7088 Reg == MaybeSameReg;
7090 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7111 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7120 return MRI.getType(MatchInfo) == DstVecTy;
7123 std::optional<ValueAndVReg> ShiftAmount;
7132 return MRI.getType(MatchInfo) == DstVecTy;
7147 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7154 std::optional<ValueAndVReg> ShiftAmt;
7160 LLT MatchTy =
MRI.getType(MatchInfo);
7161 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7162 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7165unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7167 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7168 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7169 "Expected a NaN behaviour?");
7179 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7180 return TargetOpcode::G_FMAXNUM;
7181 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7182 return TargetOpcode::G_FMAXIMUM;
7183 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7184 return TargetOpcode::G_FMAXNUM;
7185 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7186 return TargetOpcode::G_FMAXIMUM;
7192 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7193 return TargetOpcode::G_FMINNUM;
7194 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7195 return TargetOpcode::G_FMINIMUM;
7196 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7197 return TargetOpcode::G_FMINNUM;
7198 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7200 return TargetOpcode::G_FMINIMUM;
7204CombinerHelper::SelectPatternNaNBehaviour
7206 bool IsOrderedComparison)
const {
7207 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7208 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7210 if (!LHSSafe && !RHSSafe)
7211 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7212 if (LHSSafe && RHSSafe)
7213 return SelectPatternNaNBehaviour::RETURNS_ANY;
7216 if (IsOrderedComparison)
7217 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7218 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7221 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7222 : SelectPatternNaNBehaviour::RETURNS_NAN;
7231 LLT DstTy =
MRI.getType(Dst);
7244 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7246 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7248 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7251 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7252 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7253 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7254 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7256 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7259 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7264 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7269 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7271 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7275 MatchInfo = [=](MachineIRBuilder &
B) {
7276 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7284 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7291 Register TrueVal =
MI.getOperand(2).getReg();
7292 Register FalseVal =
MI.getOperand(3).getReg();
7293 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7298 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7311 if (MatchedSub &&
X != OpLHS)
7319 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7322 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7323 B.buildICmp(Pred, Dst,
Y, Zero);
7330static std::optional<unsigned>
7332 std::optional<int64_t> &Result) {
7333 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7334 Opcode == TargetOpcode::G_ASHR) &&
7335 "Expect G_SHL, G_LSHR or G_ASHR.");
7336 auto SignificantBits = 0;
7338 case TargetOpcode::G_SHL:
7342 case TargetOpcode::G_LSHR:
7346 case TargetOpcode::G_ASHR:
7355 Result = std::nullopt;
7366 Register ShiftVal =
MI.getOperand(1).getReg();
7367 Register ShiftReg =
MI.getOperand(2).getReg();
7368 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7369 auto IsShiftTooBig = [&](
const Constant *
C) {
7374 MatchInfo = std::nullopt;
7378 MI.getOpcode(), MatchInfo);
7379 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7385 unsigned LHSOpndIdx = 1;
7386 unsigned RHSOpndIdx = 2;
7387 switch (
MI.getOpcode()) {
7388 case TargetOpcode::G_UADDO:
7389 case TargetOpcode::G_SADDO:
7390 case TargetOpcode::G_UMULO:
7391 case TargetOpcode::G_SMULO:
7398 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7399 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7404 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7405 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7409 return MRI.getVRegDef(RHS)->getOpcode() !=
7410 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7417 std::optional<FPValueAndVReg> ValAndVReg;
7425 unsigned LHSOpndIdx = 1;
7426 unsigned RHSOpndIdx = 2;
7427 switch (
MI.getOpcode()) {
7428 case TargetOpcode::G_UADDO:
7429 case TargetOpcode::G_SADDO:
7430 case TargetOpcode::G_UMULO:
7431 case TargetOpcode::G_SMULO:
7438 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7439 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7440 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7441 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7445bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7447 if (SrcTy.isFixedVector())
7449 if (SrcTy.isScalar()) {
7453 return IConstant && IConstant->Value == 1;
7458bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7459 LLT SrcTy =
MRI.getType(Src);
7461 return isConstantSplatVector(Src, 0, AllowUndefs);
7466 return IConstant && IConstant->Value == 0;
7473bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7474 bool AllowUndefs)
const {
7480 for (
unsigned I = 0;
I < NumSources; ++
I) {
7481 GImplicitDef *ImplicitDef =
7483 if (ImplicitDef && AllowUndefs)
7485 if (ImplicitDef && !AllowUndefs)
7487 std::optional<ValueAndVReg> IConstant =
7489 if (IConstant && IConstant->Value == SplatValue)
7499CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7502 return IConstant->Value;
7506 return std::nullopt;
7509 std::optional<APInt>
Value = std::nullopt;
7510 for (
unsigned I = 0;
I < NumSources; ++
I) {
7511 std::optional<ValueAndVReg> IConstant =
7514 return std::nullopt;
7516 Value = IConstant->Value;
7517 else if (*
Value != IConstant->Value)
7518 return std::nullopt;
7524bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7534 for (
unsigned I = 0;
I < NumSources; ++
I) {
7535 std::optional<ValueAndVReg> IConstant =
7544bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7551 LLT CondTy =
MRI.getType(
Select->getCondReg());
7552 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7562 std::optional<ValueAndVReg> TrueOpt =
7564 std::optional<ValueAndVReg> FalseOpt =
7567 if (!TrueOpt || !FalseOpt)
7570 APInt TrueValue = TrueOpt->Value;
7571 APInt FalseValue = FalseOpt->Value;
7575 MatchInfo = [=](MachineIRBuilder &
B) {
7576 B.setInstrAndDebugLoc(*
Select);
7577 B.buildZExtOrTrunc(Dest,
Cond);
7584 MatchInfo = [=](MachineIRBuilder &
B) {
7585 B.setInstrAndDebugLoc(*
Select);
7586 B.buildSExtOrTrunc(Dest,
Cond);
7593 MatchInfo = [=](MachineIRBuilder &
B) {
7594 B.setInstrAndDebugLoc(*
Select);
7595 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7596 B.buildNot(Inner,
Cond);
7597 B.buildZExtOrTrunc(Dest, Inner);
7604 MatchInfo = [=](MachineIRBuilder &
B) {
7605 B.setInstrAndDebugLoc(*
Select);
7606 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7607 B.buildNot(Inner,
Cond);
7608 B.buildSExtOrTrunc(Dest, Inner);
7614 if (TrueValue - 1 == FalseValue) {
7615 MatchInfo = [=](MachineIRBuilder &
B) {
7616 B.setInstrAndDebugLoc(*
Select);
7617 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7618 B.buildZExtOrTrunc(Inner,
Cond);
7619 B.buildAdd(Dest, Inner, False);
7625 if (TrueValue + 1 == FalseValue) {
7626 MatchInfo = [=](MachineIRBuilder &
B) {
7627 B.setInstrAndDebugLoc(*
Select);
7628 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7629 B.buildSExtOrTrunc(Inner,
Cond);
7630 B.buildAdd(Dest, Inner, False);
7637 MatchInfo = [=](MachineIRBuilder &
B) {
7638 B.setInstrAndDebugLoc(*
Select);
7639 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7640 B.buildZExtOrTrunc(Inner,
Cond);
7643 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7644 B.buildShl(Dest, Inner, ShAmtC, Flags);
7651 MatchInfo = [=](MachineIRBuilder &
B) {
7652 B.setInstrAndDebugLoc(*
Select);
7654 B.buildNot(Not,
Cond);
7655 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7656 B.buildZExtOrTrunc(Inner, Not);
7659 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7660 B.buildShl(Dest, Inner, ShAmtC, Flags);
7667 MatchInfo = [=](MachineIRBuilder &
B) {
7668 B.setInstrAndDebugLoc(*
Select);
7669 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7670 B.buildSExtOrTrunc(Inner,
Cond);
7671 B.buildOr(Dest, Inner, False, Flags);
7678 MatchInfo = [=](MachineIRBuilder &
B) {
7679 B.setInstrAndDebugLoc(*
Select);
7681 B.buildNot(Not,
Cond);
7682 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7683 B.buildSExtOrTrunc(Inner, Not);
7684 B.buildOr(Dest, Inner, True, Flags);
7693bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7700 LLT CondTy =
MRI.getType(
Select->getCondReg());
7701 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7710 if (CondTy != TrueTy)
7715 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7716 MatchInfo = [=](MachineIRBuilder &
B) {
7717 B.setInstrAndDebugLoc(*
Select);
7718 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7719 B.buildZExtOrTrunc(Ext,
Cond);
7720 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7721 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7728 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7729 MatchInfo = [=](MachineIRBuilder &
B) {
7730 B.setInstrAndDebugLoc(*
Select);
7731 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7732 B.buildZExtOrTrunc(Ext,
Cond);
7733 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7734 B.buildAnd(DstReg, Ext, FreezeTrue);
7740 if (isOneOrOneSplat(False,
true)) {
7741 MatchInfo = [=](MachineIRBuilder &
B) {
7742 B.setInstrAndDebugLoc(*
Select);
7744 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7745 B.buildNot(Inner,
Cond);
7747 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7748 B.buildZExtOrTrunc(Ext, Inner);
7749 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7750 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7756 if (isZeroOrZeroSplat(True,
true)) {
7757 MatchInfo = [=](MachineIRBuilder &
B) {
7758 B.setInstrAndDebugLoc(*
Select);
7760 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7761 B.buildNot(Inner,
Cond);
7763 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7764 B.buildZExtOrTrunc(Ext, Inner);
7765 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7766 B.buildAnd(DstReg, Ext, FreezeFalse);
7782 LLT DstTy =
MRI.getType(DstReg);
7788 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7797 Register CmpLHS = Cmp->getLHSReg();
7798 Register CmpRHS = Cmp->getRHSReg();
7801 if (True == CmpRHS && False == CmpLHS) {
7809 if (True != CmpLHS || False != CmpRHS)
7849 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7850 Register DestReg =
MI.getOperand(0).getReg();
7851 LLT DestTy =
MRI.getType(DestReg);
7863 if (
isLegal({NewOpc, {DestTy}})) {
7865 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7877 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7880 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7890bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7892 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7893 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7897 unsigned Flags = Logic->
getFlags();
7916 std::optional<ValueAndVReg> MaybeC1 =
7920 C1 = MaybeC1->Value;
7922 std::optional<ValueAndVReg> MaybeC2 =
7926 C2 = MaybeC2->Value;
7947 std::optional<APInt> Offset1;
7948 std::optional<APInt> Offset2;
7951 std::optional<ValueAndVReg> MaybeOffset1 =
7954 R1 =
Add->getLHSReg();
7955 Offset1 = MaybeOffset1->Value;
7959 std::optional<ValueAndVReg> MaybeOffset2 =
7962 R2 =
Add->getLHSReg();
7963 Offset2 = MaybeOffset2->Value;
7982 bool CreateMask =
false;
7995 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
8008 CR->getEquivalentICmp(NewPred, NewC,
Offset);
8017 MatchInfo = [=](MachineIRBuilder &
B) {
8018 if (CreateMask &&
Offset != 0) {
8019 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8020 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8021 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8022 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
8023 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8024 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8025 B.buildZExtOrTrunc(DstReg, ICmp);
8026 }
else if (CreateMask &&
Offset == 0) {
8027 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8028 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8029 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8030 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
8031 B.buildZExtOrTrunc(DstReg, ICmp);
8032 }
else if (!CreateMask &&
Offset != 0) {
8033 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8034 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
8035 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8036 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8037 B.buildZExtOrTrunc(DstReg, ICmp);
8038 }
else if (!CreateMask &&
Offset == 0) {
8039 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8040 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
8041 B.buildZExtOrTrunc(DstReg, ICmp);
8049bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
8055 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8067 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8073 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8074 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8075 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8076 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8087 if (LHS0 == RHS1 && LHS1 == RHS0) {
8093 if (LHS0 == RHS0 && LHS1 == RHS1) {
8097 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8099 MatchInfo = [=](MachineIRBuilder &
B) {
8104 auto False =
B.buildConstant(CmpTy, 0);
8105 B.buildZExtOrTrunc(DestReg, False);
8112 B.buildZExtOrTrunc(DestReg, True);
8114 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8115 B.buildZExtOrTrunc(DestReg, Cmp);
8127 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8130 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8139 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8142 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8157 bool IsSigned =
Add->isSigned();
8158 LLT DstTy =
MRI.getType(Dst);
8159 LLT CarryTy =
MRI.getType(Carry);
8162 if (
MRI.use_nodbg_empty(Carry) &&
8165 B.buildAdd(Dst, LHS, RHS);
8166 B.buildUndef(Carry);
8172 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8175 B.buildSAddo(Dst, Carry, RHS, LHS);
8181 B.buildUAddo(Dst, Carry, RHS, LHS);
8186 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8187 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8193 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8194 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8196 B.buildConstant(Dst, Result);
8197 B.buildConstant(Carry, Overflow);
8205 B.buildCopy(Dst, LHS);
8206 B.buildConstant(Carry, 0);
8215 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8218 std::optional<APInt> MaybeAddRHS =
8219 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8222 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8223 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8227 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8228 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8234 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8235 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8260 B.buildConstant(Carry, 0);
8267 B.buildAdd(Dst, LHS, RHS);
8268 B.buildConstant(Carry, 1);
8280 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8283 B.buildConstant(Carry, 0);
8299 B.buildConstant(Carry, 0);
8306 B.buildAdd(Dst, LHS, RHS);
8307 B.buildConstant(Carry, 1);
8325 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8331 auto [Dst,
Base] =
MI.getFirst2Regs();
8332 LLT Ty =
MRI.getType(Dst);
8336 Builder.buildFConstant(Dst, 1.0);
8337 MI.removeFromParent();
8349 std::optional<SrcOp> Res;
8351 while (ExpVal > 0) {
8356 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8359 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8366 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8370 MI.eraseFromParent();
8379 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8386 LLT DstTy =
MRI.getType(Dst);
8389 auto Const =
B.buildConstant(DstTy, C1 - C2);
8390 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8402 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8409 LLT DstTy =
MRI.getType(Dst);
8412 auto Const =
B.buildConstant(DstTy, C2 - C1);
8413 B.buildSub(Dst, Const,
Add->getLHSReg());
8425 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8432 LLT DstTy =
MRI.getType(Dst);
8435 auto Const =
B.buildConstant(DstTy, C1 + C2);
8448 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8455 LLT DstTy =
MRI.getType(Dst);
8458 auto Const =
B.buildConstant(DstTy, C1 - C2);
8471 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8478 LLT DstTy =
MRI.getType(Dst);
8481 auto Const =
B.buildConstant(DstTy, C2 - C1);
8482 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8529 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8533 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8536 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8537 LLT SmallBvTy = DstTy;
8541 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8546 {TargetOpcode::G_ANYEXT,
8558 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8559 Ops.push_back(AnyExt.getReg(0));
8577 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8578 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8579 const unsigned NumDstElts = OrigMask.
size();
8580 for (
unsigned i = 0; i != NumDstElts; ++i) {
8581 int Idx = OrigMask[i];
8582 if (Idx >= (
int)NumSrcElems) {
8593 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8594 std::move(NewMask));
8601 const unsigned MaskSize = Mask.size();
8602 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8607 if (Idx < (
int)NumElems)
8608 Mask[
I] = Idx + NumElems;
8610 Mask[
I] = Idx - NumElems;
8620 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8623 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8626 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8627 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8629 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8633 const unsigned NumSrcElems = Src1Ty.getNumElements();
8635 bool TouchesSrc1 =
false;
8636 bool TouchesSrc2 =
false;
8637 const unsigned NumElems = Mask.size();
8638 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8642 if (Mask[Idx] < (
int)NumSrcElems)
8648 if (TouchesSrc1 == TouchesSrc2)
8651 Register NewSrc1 = Shuffle.getSrc1Reg();
8654 NewSrc1 = Shuffle.getSrc2Reg();
8659 auto Undef =
B.buildUndef(Src1Ty);
8660 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8674 LLT DstTy =
MRI.getType(Dst);
8675 LLT CarryTy =
MRI.getType(Carry);
8697 B.buildConstant(Carry, 0);
8704 B.buildSub(Dst, LHS, RHS);
8722 B.buildConstant(Carry, 0);
8729 B.buildSub(Dst, LHS, RHS);
8746 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8747 "Expected G_CTLZ variant");
8752 LLT Ty =
MRI.getType(Dst);
8753 LLT SrcTy =
MRI.getType(Src);
8755 if (!(Ty.isValid() && Ty.isScalar()))
8764 switch (
LI->getAction(Query).Action) {
8775 bool NeedAdd =
true;
8783 unsigned BitWidth = Ty.getScalarSizeInBits();
8794 B.buildCTLS(Dst,
X);
8798 auto Ctls =
B.buildCTLS(Ty,
X);
8799 auto One =
B.buildConstant(Ty, 1);
8801 B.buildAdd(Dst, Ctls, One);
8811 unsigned TargetOpc)
const {
8812 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8813 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8814 "Expected G_LSHR/G_ASHR");
8817 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.
bool tryCombineShuffleVector(MachineInstr &MI) const
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
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...