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();
406 Register SrcVec1 = Shuffle.getSrc1Reg();
407 Register SrcVec2 = Shuffle.getSrc2Reg();
408 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
409 int Width =
MRI.getType(SrcVec1).getNumElements();
411 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
412 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
416 for (
int Val : Shuffle.getMask()) {
419 else if (Val < Width)
420 Extracts.
push_back(Unmerge1.getReg(Val));
422 Extracts.
push_back(Unmerge2.getReg(Val - Width));
424 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
425 if (Extracts.
size() == 1)
426 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
428 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
429 MI.eraseFromParent();
439 if (!ConcatMI1 || !ConcatMI2)
443 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
444 MRI.getType(ConcatMI2->getSourceReg(0)))
447 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
448 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
450 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
454 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
455 if (i + j >= Mask.size())
457 if (Mask[i + j] != -1)
461 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
464 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
465 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
466 if (i + j >= Mask.size())
468 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
474 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
476 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
477 ConcatMI1->getNumSources()));
485 {TargetOpcode::G_CONCAT_VECTORS,
486 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
497 SrcTy =
MRI.getType(Reg);
499 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
506 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
512 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
515 MI.eraseFromParent();
529 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
530 "Invalid instruction kind");
531 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
533 LLT SrcType =
MRI.getType(Src1);
535 unsigned DstNumElts = DstType.getNumElements();
536 unsigned SrcNumElts = SrcType.getNumElements();
553 if (DstNumElts < 2 * SrcNumElts)
558 if (DstNumElts % SrcNumElts != 0)
564 unsigned NumConcat = DstNumElts / SrcNumElts;
567 for (
unsigned i = 0; i != DstNumElts; ++i) {
574 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
575 (ConcatSrcs[i / SrcNumElts] >= 0 &&
576 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
579 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
586 for (
auto Src : ConcatSrcs) {
590 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
592 Ops.push_back(UndefReg);
605 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
613 MI.eraseFromParent();
622 const LLT TyForCandidate,
623 unsigned OpcodeForCandidate,
628 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
639 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
642 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
643 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
644 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
652 OpcodeForCandidate == TargetOpcode::G_ZEXT)
654 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
655 OpcodeForCandidate == TargetOpcode::G_SEXT)
656 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
665 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
676static void InsertInsnsWithoutSideEffectsBeforeUse(
688 InsertBB = PredBB->
getMBB();
693 if (InsertBB ==
DefMI.getParent()) {
695 Inserter(InsertBB, std::next(InsertPt), UseMO);
714 unsigned CandidateLoadOpc;
716 case TargetOpcode::G_ANYEXT:
717 CandidateLoadOpc = TargetOpcode::G_LOAD;
719 case TargetOpcode::G_SEXT:
720 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
722 case TargetOpcode::G_ZEXT:
723 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
728 return CandidateLoadOpc;
745 LLT LoadValueTy =
MRI.getType(LoadReg);
767 unsigned PreferredOpcode =
769 ? TargetOpcode::G_ANYEXT
771 Preferred = {
LLT(), PreferredOpcode,
nullptr};
772 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
773 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
774 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
775 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
776 const auto &MMO = LoadMI->
getMMO();
784 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
786 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
790 Preferred = ChoosePreferredUse(
MI, Preferred,
791 MRI.getType(
UseMI.getOperand(0).getReg()),
801 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
819 if (PreviouslyEmitted) {
826 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
827 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
829 EmittedInsns[InsertIntoBB] = NewMI;
835 MI.setDesc(
Builder.getTII().get(LoadOpc));
842 for (
auto *UseMO :
Uses) {
848 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
851 const LLT UseDstTy =
MRI.getType(UseDstReg);
852 if (UseDstReg != ChosenDstReg) {
853 if (Preferred.
Ty == UseDstTy) {
890 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
905 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
908 MI.getOperand(0).setReg(ChosenDstReg);
914 assert(
MI.getOpcode() == TargetOpcode::G_AND);
925 if (
MRI.getType(Dst).isVector())
933 APInt MaskVal = MaybeMask->Value;
942 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
946 LLT RegTy =
MRI.getType(LoadReg);
954 if (MaskSizeBits > LoadSizeBits.
getValue())
974 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
980 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
984 B.setInstrAndDebugLoc(*LoadMI);
985 auto &MF =
B.getMF();
987 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
988 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
997 "shouldn't consider debug uses");
1005 if (DefOrUse ==
MBB.end())
1007 return &*DefOrUse == &
DefMI;
1013 "shouldn't consider debug uses");
1016 else if (
DefMI.getParent() !=
UseMI.getParent())
1023 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1027 if (
MRI.getType(SrcReg).isVector())
1032 LoadUser = TruncSrc;
1034 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1039 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1041 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1043 if (LoadSizeBits == SizeInBits)
1050 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1051 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1052 MI.eraseFromParent();
1056 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1057 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1060 LLT RegTy =
MRI.getType(DstReg);
1068 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1071 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1076 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1079 if (NewSizeBits < 8)
1091 if (LoadDef->isSimple())
1093 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1098 {
MRI.getType(LoadDef->getDstReg()),
1099 MRI.getType(LoadDef->getPointerReg())},
1103 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1108 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1109 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1111 unsigned ScalarSizeBits;
1112 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1121 auto &MMO = LoadDef->
getMMO();
1122 Builder.setInstrAndDebugLoc(*LoadDef);
1124 auto PtrInfo = MMO.getPointerInfo();
1125 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1126 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1128 MI.eraseFromParent();
1139 auto *MF =
MI->getMF();
1146 AM.
BaseOffs = CstOff->getSExtValue();
1151 MF->getDataLayout(), AM,
1153 MF->getFunction().getContext()),
1154 MI->getMMO().getAddrSpace());
1159 case TargetOpcode::G_LOAD:
1160 return TargetOpcode::G_INDEXED_LOAD;
1161 case TargetOpcode::G_STORE:
1162 return TargetOpcode::G_INDEXED_STORE;
1163 case TargetOpcode::G_ZEXTLOAD:
1164 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1165 case TargetOpcode::G_SEXTLOAD:
1166 return TargetOpcode::G_INDEXED_SEXTLOAD;
1172bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1182 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1183 OpTys = {PtrTy, Ty, Ty};
1185 OpTys = {Ty, PtrTy};
1187 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1193 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1194 "considered for post-indexing."));
1198 bool &RematOffset)
const {
1211 if (!isIndexedLoadStoreLegal(LdSt))
1220 unsigned NumUsesChecked = 0;
1233 if (StoredValDef == &
Use)
1236 Offset = PtrAdd->getOffsetReg();
1238 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1244 RematOffset =
false;
1248 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1253 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1254 if (&BasePtrUse == PtrDef)
1260 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1262 isIndexedLoadStoreLegal(*BasePtrLdSt))
1268 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1269 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1272 if (BaseUseUse.getParent() != LdSt.
getParent())
1284 Addr = PtrAdd->getReg(0);
1285 Base = PtrAdd->getBaseReg();
1300 MRI.hasOneNonDBGUse(Addr))
1307 if (!isIndexedLoadStoreLegal(LdSt))
1311 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1316 if (
Base == St->getValueReg())
1321 if (St->getValueReg() == Addr)
1326 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1327 if (AddrUse.getParent() != LdSt.
getParent())
1332 bool RealUse =
false;
1333 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1351 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1361 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1368 if (!LoadMI->isSimple())
1380 const unsigned MaxIter = 20;
1383 if (
II->isLoadFoldBarrier())
1385 if (Iter++ == MaxIter)
1401 int Elt = CVal->getZExtValue();
1414 Register VecPtr = LoadMI->getPointerReg();
1415 LLT PtrTy =
MRI.getType(VecPtr);
1423 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1446 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1461 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1463 if (!MatchInfo.
IsPre &&
1464 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1474 unsigned Opcode =
MI.getOpcode();
1475 bool IsStore = Opcode == TargetOpcode::G_STORE;
1481 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1483 *OldCst->getOperand(1).getCImm());
1484 MatchInfo.
Offset = NewCst.getReg(0);
1487 auto MIB =
Builder.buildInstr(NewOpcode);
1489 MIB.addDef(MatchInfo.
Addr);
1490 MIB.addUse(
MI.getOperand(0).getReg());
1492 MIB.addDef(
MI.getOperand(0).getReg());
1493 MIB.addDef(MatchInfo.
Addr);
1496 MIB.addUse(MatchInfo.
Base);
1497 MIB.addUse(MatchInfo.
Offset);
1498 MIB.addImm(MatchInfo.
IsPre);
1499 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1500 MI.eraseFromParent();
1508 unsigned Opcode =
MI.getOpcode();
1509 bool IsDiv, IsSigned;
1514 case TargetOpcode::G_SDIV:
1515 case TargetOpcode::G_UDIV: {
1517 IsSigned = Opcode == TargetOpcode::G_SDIV;
1520 case TargetOpcode::G_SREM:
1521 case TargetOpcode::G_UREM: {
1523 IsSigned = Opcode == TargetOpcode::G_SREM;
1529 unsigned DivOpcode, RemOpcode, DivremOpcode;
1531 DivOpcode = TargetOpcode::G_SDIV;
1532 RemOpcode = TargetOpcode::G_SREM;
1533 DivremOpcode = TargetOpcode::G_SDIVREM;
1535 DivOpcode = TargetOpcode::G_UDIV;
1536 RemOpcode = TargetOpcode::G_UREM;
1537 DivremOpcode = TargetOpcode::G_UDIVREM;
1555 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1556 if (
MI.getParent() ==
UseMI.getParent() &&
1557 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1558 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1571 unsigned Opcode =
MI.getOpcode();
1572 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1575 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1576 DestDivReg =
MI.getOperand(0).getReg();
1580 DestRemReg =
MI.getOperand(0).getReg();
1584 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1591 Builder.setInstrAndDebugLoc(*FirstInst);
1593 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1594 : TargetOpcode::G_UDIVREM,
1595 {DestDivReg, DestRemReg},
1597 MI.eraseFromParent();
1603 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1620 if (BrIt ==
MBB->begin())
1622 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1624 BrCond = &*std::prev(BrIt);
1625 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1631 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1632 MBB->isLayoutSuccessor(BrCondTarget);
1638 Builder.setInstrAndDebugLoc(*BrCond);
1643 auto True =
Builder.buildConstant(
1649 MI.getOperand(0).setMBB(FallthroughBB);
1664 return Helper.lowerMemcpyInline(
MI) ==
1669 unsigned MaxLen)
const {
1681 switch (
MI.getOpcode()) {
1684 case TargetOpcode::G_FNEG: {
1685 Result.changeSign();
1688 case TargetOpcode::G_FABS: {
1692 case TargetOpcode::G_FCEIL:
1695 case TargetOpcode::G_FFLOOR:
1698 case TargetOpcode::G_INTRINSIC_TRUNC:
1701 case TargetOpcode::G_INTRINSIC_ROUND:
1704 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1707 case TargetOpcode::G_FRINT:
1708 case TargetOpcode::G_FNEARBYINT:
1712 case TargetOpcode::G_FPEXT:
1713 case TargetOpcode::G_FPTRUNC: {
1720 case TargetOpcode::G_FSQRT: {
1724 Result =
APFloat(sqrt(Result.convertToDouble()));
1727 case TargetOpcode::G_FLOG2: {
1747 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1748 MI.eraseFromParent();
1759 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1769 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1782 Type *AccessTy =
nullptr;
1783 auto &MF = *
MI.getMF();
1784 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1787 MF.getFunction().getContext());
1792 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1797 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1799 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1800 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1801 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1802 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1811 unsigned PtrAddFlags =
MI.getFlags();
1812 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1828 MatchInfo.
Flags = Flags;
1834 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1836 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1840 MI.getOperand(1).setReg(MatchInfo.
Base);
1841 MI.getOperand(2).setReg(NewOffset.getReg(0));
1855 unsigned Opcode =
MI.getOpcode();
1856 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1857 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1858 Opcode == TargetOpcode::G_USHLSAT) &&
1859 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1879 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1884 if (Opcode == TargetOpcode::G_USHLSAT &&
1885 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1893 unsigned Opcode =
MI.getOpcode();
1894 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1895 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1896 Opcode == TargetOpcode::G_USHLSAT) &&
1897 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1899 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1900 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1901 auto Imm = MatchInfo.
Imm;
1903 if (Imm >= ScalarSizeInBits) {
1905 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1906 Builder.buildConstant(
MI.getOperand(0), 0);
1907 MI.eraseFromParent();
1912 Imm = ScalarSizeInBits - 1;
1915 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1918 MI.getOperand(1).setReg(MatchInfo.
Reg);
1919 MI.getOperand(2).setReg(NewImm);
1935 unsigned ShiftOpcode =
MI.getOpcode();
1936 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1937 ShiftOpcode == TargetOpcode::G_ASHR ||
1938 ShiftOpcode == TargetOpcode::G_LSHR ||
1939 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1940 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1941 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1944 Register LogicDest =
MI.getOperand(1).getReg();
1945 if (!
MRI.hasOneNonDBGUse(LogicDest))
1949 unsigned LogicOpcode = LogicMI->
getOpcode();
1950 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1951 LogicOpcode != TargetOpcode::G_XOR)
1955 const Register C1 =
MI.getOperand(2).getReg();
1957 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1960 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1964 if (
MI->getOpcode() != ShiftOpcode ||
1965 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1974 ShiftVal = MaybeImmVal->Value.getSExtValue();
1985 if (matchFirstShift(LogicMIOp1, C0Val)) {
1987 MatchInfo.
Shift2 = LogicMIOp1;
1988 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1990 MatchInfo.
Shift2 = LogicMIOp2;
1994 MatchInfo.
ValSum = C0Val + C1Val;
1997 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2000 MatchInfo.
Logic = LogicMI;
2006 unsigned Opcode =
MI.getOpcode();
2007 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2008 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2009 Opcode == TargetOpcode::G_SSHLSAT) &&
2010 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2012 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2013 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2019 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2028 Register Shift2Const =
MI.getOperand(2).getReg();
2030 .buildInstr(Opcode, {DestType},
2040 MI.eraseFromParent();
2045 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2067 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2068 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2069 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2070 LLT SrcTy =
MRI.getType(SrcReg);
2072 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2073 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2074 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2082 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2086 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2101 LLT InnerShiftTy =
MRI.getType(InnerShift);
2103 if ((N1C + N001C).ult(InnerShiftSize)) {
2109 if ((N001C + OpSizeInBits) == InnerShiftSize)
2111 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2112 MatchInfo.
Mask =
true;
2122 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2129 if (MatchInfo.
Mask ==
true) {
2137 Builder.buildTrunc(Dst, Shift);
2138 MI.eraseFromParent();
2142 unsigned &ShiftVal)
const {
2143 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2149 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2150 return (
static_cast<int32_t
>(ShiftVal) != -1);
2154 unsigned &ShiftVal)
const {
2155 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2157 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2160 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2161 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2182 auto NegCst =
B.buildConstant(Ty, -Imm);
2184 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2185 MI.getOperand(2).setReg(NegCst.getReg(0));
2187 if (Imm.isMinSignedValue())
2197 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2212 if (!MaybeShiftAmtVal)
2216 LLT SrcTy =
MRI.getType(ExtSrc);
2226 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2227 MatchData.
Reg = ExtSrc;
2228 MatchData.
Imm = ShiftAmt;
2230 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2231 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2232 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2238 int64_t ShiftAmtVal = MatchData.
Imm;
2240 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2241 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2243 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2244 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2245 MI.eraseFromParent();
2252 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2256 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2259 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2260 if (MergedValues[
I] != Unmerge->getReg(
I))
2263 MatchInfo = Unmerge->getSourceReg();
2277 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2278 "Expected an unmerge");
2287 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2288 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2290 if (SrcMergeTy != Dst0Ty && !SameSize)
2294 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2295 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2301 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2302 "Expected an unmerge");
2304 "Not enough operands to replace all defs");
2305 unsigned NumElems =
MI.getNumOperands() - 1;
2307 LLT SrcTy =
MRI.getType(Operands[0]);
2308 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2309 bool CanReuseInputDirectly = DstTy == SrcTy;
2310 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2311 Register DstReg =
MI.getOperand(Idx).getReg();
2316 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2317 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2318 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2319 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2322 if (CanReuseInputDirectly)
2325 Builder.buildCast(DstReg, SrcReg);
2327 MI.eraseFromParent();
2332 unsigned SrcIdx =
MI.getNumOperands() - 1;
2333 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2335 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2336 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2344 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2347 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2349 Val = Val.
lshr(ShiftAmt);
2357 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2358 "Expected an unmerge");
2360 "Not enough operands to replace all defs");
2361 unsigned NumElems =
MI.getNumOperands() - 1;
2362 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2363 Register DstReg =
MI.getOperand(Idx).getReg();
2364 Builder.buildConstant(DstReg, Csts[Idx]);
2367 MI.eraseFromParent();
2373 unsigned SrcIdx =
MI.getNumOperands() - 1;
2374 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2376 unsigned NumElems =
MI.getNumOperands() - 1;
2377 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2378 Register DstReg =
MI.getOperand(Idx).getReg();
2379 B.buildUndef(DstReg);
2387 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2388 "Expected an unmerge");
2389 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2390 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2393 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2394 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2402 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2403 Register Dst0Reg =
MI.getOperand(0).getReg();
2404 Builder.buildTrunc(Dst0Reg, SrcReg);
2405 MI.eraseFromParent();
2409 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2410 "Expected an unmerge");
2411 Register Dst0Reg =
MI.getOperand(0).getReg();
2412 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2418 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2419 LLT SrcTy =
MRI.getType(SrcReg);
2420 if (SrcTy.isVector())
2430 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2435 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2436 "Expected an unmerge");
2438 Register Dst0Reg =
MI.getOperand(0).getReg();
2441 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2443 "Expecting a G_ZEXT");
2446 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2447 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2450 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2453 "ZExt src doesn't fit in destination");
2458 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2460 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2463 MI.eraseFromParent();
2467 unsigned TargetShiftSize,
2468 unsigned &ShiftVal)
const {
2469 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2470 MI.getOpcode() == TargetOpcode::G_LSHR ||
2471 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2473 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2478 unsigned Size = Ty.getSizeInBits();
2479 if (
Size <= TargetShiftSize)
2487 ShiftVal = MaybeImmVal->Value.getSExtValue();
2488 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2495 LLT Ty =
MRI.getType(SrcReg);
2496 unsigned Size = Ty.getSizeInBits();
2497 unsigned HalfSize =
Size / 2;
2498 assert(ShiftVal >= HalfSize);
2502 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2503 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2505 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2506 Register Narrowed = Unmerge.getReg(1);
2513 if (NarrowShiftAmt != 0) {
2514 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2515 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2518 auto Zero =
Builder.buildConstant(HalfTy, 0);
2519 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2520 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2521 Register Narrowed = Unmerge.getReg(0);
2526 if (NarrowShiftAmt != 0) {
2527 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2528 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2531 auto Zero =
Builder.buildConstant(HalfTy, 0);
2532 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2534 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2536 HalfTy, Unmerge.getReg(1),
2537 Builder.buildConstant(HalfTy, HalfSize - 1));
2539 if (ShiftVal == HalfSize) {
2542 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2543 }
else if (ShiftVal ==
Size - 1) {
2551 HalfTy, Unmerge.getReg(1),
2552 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2560 MI.eraseFromParent();
2576 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2578 LLT DstTy =
MRI.getType(DstReg);
2586 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2588 Builder.buildCopy(DstReg, Reg);
2589 MI.eraseFromParent();
2594 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2596 Builder.buildZExtOrTrunc(DstReg, Reg);
2597 MI.eraseFromParent();
2602 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2605 LLT IntTy =
MRI.getType(LHS);
2609 PtrReg.second =
false;
2610 for (
Register SrcReg : {LHS, RHS}) {
2614 LLT PtrTy =
MRI.getType(PtrReg.first);
2619 PtrReg.second =
true;
2631 const bool DoCommute = PtrReg.second;
2636 LLT PtrTy =
MRI.getType(LHS);
2638 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2639 Builder.buildPtrToInt(Dst, PtrAdd);
2640 MI.eraseFromParent();
2644 APInt &NewCst)
const {
2646 Register LHS = PtrAdd.getBaseReg();
2647 Register RHS = PtrAdd.getOffsetReg();
2653 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2656 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2665 APInt &NewCst)
const {
2669 Builder.buildConstant(Dst, NewCst);
2670 PtrAdd.eraseFromParent();
2675 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2680 SrcReg = OriginalSrcReg;
2681 LLT DstTy =
MRI.getType(DstReg);
2689 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2692 LLT DstTy =
MRI.getType(DstReg);
2697 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2698 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2708 if (ShiftSize > 32 && TruncSize < 32)
2721 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2722 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2726 if (!
MRI.hasOneNonDBGUse(SrcReg))
2729 LLT SrcTy =
MRI.getType(SrcReg);
2730 LLT DstTy =
MRI.getType(DstReg);
2739 case TargetOpcode::G_SHL: {
2748 case TargetOpcode::G_LSHR:
2749 case TargetOpcode::G_ASHR: {
2755 for (
auto &
User :
MRI.use_instructions(DstReg))
2756 if (
User.getOpcode() == TargetOpcode::G_STORE)
2760 if (NewShiftTy == SrcTy)
2774 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2777 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2782 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2784 LLT NewShiftTy = MatchInfo.second;
2787 LLT DstTy =
MRI.getType(Dst);
2791 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2795 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2798 if (NewShiftTy == DstTy)
2801 Builder.buildTrunc(Dst, NewShift);
2808 return MO.isReg() &&
2809 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2815 return !MO.isReg() ||
2816 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2821 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2823 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2827 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2828 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2833 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2834 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2840 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2841 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2842 "Expected an insert/extract element op");
2843 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2848 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2856 unsigned &
OpIdx)
const {
2862 OpIdx = Cst->isZero() ? 3 : 2;
2907 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2934 return MO.isReg() && MO.getReg().isPhysical();
2944 return I1->isIdenticalTo(*I2);
2952 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2959 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2971 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2972 MaybeCst->getSExtValue() ==
C;
2979 std::optional<FPValueAndVReg> MaybeCst;
2983 return MaybeCst->Value.isExactlyValue(
C);
2987 unsigned OpIdx)
const {
2988 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2993 MI.eraseFromParent();
2998 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3002 MI.eraseFromParent();
3006 unsigned ConstIdx)
const {
3007 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3008 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3020 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3021 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3022 "This is not a funnel shift operation");
3024 Register ConstReg =
MI.getOperand(3).getReg();
3025 LLT ConstTy =
MRI.getType(ConstReg);
3026 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3029 assert((VRegAndVal) &&
"Value is not a constant");
3032 APInt NewConst = VRegAndVal->Value.
urem(
3037 MI.getOpcode(), {MI.getOperand(0)},
3038 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3040 MI.eraseFromParent();
3044 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3058 unsigned OpIdx)
const {
3060 return MO.
isReg() &&
3071 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3073 MI.eraseFromParent();
3078 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3080 MI.eraseFromParent();
3084 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3086 MI.eraseFromParent();
3091 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3093 MI.eraseFromParent();
3097 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3099 MI.eraseFromParent();
3103 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3106 Register &NewLHS = std::get<0>(MatchInfo);
3107 Register &NewRHS = std::get<1>(MatchInfo);
3115 NewLHS = MaybeNewLHS;
3119 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3124 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3127 LLT DstTy =
MRI.getType(DstReg);
3136 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3137 TargetOpcode::G_INSERT_VECTOR_ELT)
3143 MatchInfo.
resize(NumElts);
3147 if (IntImm >= NumElts || IntImm < 0)
3149 if (!MatchInfo[IntImm])
3150 MatchInfo[IntImm] = TmpReg;
3154 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3156 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3165 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3172 auto GetUndef = [&]() {
3175 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3183 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3184 MI.eraseFromParent();
3188 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3190 std::tie(SubLHS, SubRHS) = MatchInfo;
3191 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3192 MI.eraseFromParent();
3205 unsigned InnerOpc = InnerDef->
getOpcode();
3206 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3229 if (!TryMatch(InnerLHS, InnerRHS) && !TryMatch(InnerRHS, InnerLHS))
3233 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3234 : TargetOpcode::G_ADD;
3237 MatchInfo = [=](MachineIRBuilder &
Builder) {
3238 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3239 auto NewNot =
Builder.buildNot(Ty, NewInner);
3240 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3252 unsigned RootOpc =
MI.getOpcode();
3254 LLT Ty =
MRI.getType(Dst);
3259 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3260 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3271 unsigned LogicOpcode =
MI.getOpcode();
3272 assert(LogicOpcode == TargetOpcode::G_AND ||
3273 LogicOpcode == TargetOpcode::G_OR ||
3274 LogicOpcode == TargetOpcode::G_XOR);
3281 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3287 if (!LeftHandInst || !RightHandInst)
3289 unsigned HandOpcode = LeftHandInst->
getOpcode();
3290 if (HandOpcode != RightHandInst->
getOpcode())
3304 if (!XTy.
isValid() || XTy != YTy)
3309 switch (HandOpcode) {
3312 case TargetOpcode::G_ANYEXT:
3313 case TargetOpcode::G_SEXT:
3314 case TargetOpcode::G_ZEXT: {
3318 case TargetOpcode::G_TRUNC: {
3323 LLT DstTy =
MRI.getType(Dst);
3332 case TargetOpcode::G_AND:
3333 case TargetOpcode::G_ASHR:
3334 case TargetOpcode::G_LSHR:
3335 case TargetOpcode::G_SHL: {
3340 ExtraHandOpSrcReg = ZOp.
getReg();
3351 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3362 if (ExtraHandOpSrcReg.
isValid())
3374 "Expected at least one instr to build?");
3376 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3377 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3379 for (
auto &OperandFn : InstrToBuild.OperandFns)
3382 MI.eraseFromParent();
3386 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3387 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3388 int64_t ShlCst, AshrCst;
3394 if (ShlCst != AshrCst)
3397 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3399 MatchInfo = std::make_tuple(Src, ShlCst);
3404 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3405 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3408 std::tie(Src, ShiftAmt) = MatchInfo;
3409 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3410 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3411 MI.eraseFromParent();
3418 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3421 LLT Ty =
MRI.getType(Dst);
3433 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3436 auto Zero =
B.buildConstant(Ty, 0);
3459 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3483 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3490 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3507 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3525 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3532 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3543 unsigned ExtBits =
MI.getOperand(2).getImm();
3544 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3545 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3549 int64_t Cst,
bool IsVector,
bool IsFP) {
3551 return (ScalarSizeBits == 1 && Cst == -1) ||
3573 unsigned BuildUseCount = BV.getNumSources();
3574 if (BuildUseCount % 2 != 0)
3577 unsigned NumUnmerge = BuildUseCount / 2;
3583 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3586 UnmergeSrc = Unmerge->getSourceReg();
3588 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3589 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3596 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3601 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3602 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3605 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3608 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3613 if (Unmerge->getNumDefs() != NumUnmerge)
3617 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3620 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3631 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3632 B.setInstrAndDebugLoc(
MI);
3634 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3635 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3637 MI.eraseFromParent();
3659 unsigned NumOperands =
BuildMI->getNumSources();
3669 for (
I = 0;
I < NumOperands; ++
I) {
3670 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3671 auto SrcMIOpc = SrcMI->getOpcode();
3674 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3675 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3677 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3678 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3681 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3682 if (UnmergeMI != UnmergeSrcMI)
3697 for (;
I < NumOperands; ++
I) {
3698 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3699 auto SrcMIOpc = SrcMI->getOpcode();
3701 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3707 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3714 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3715 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3723 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3726 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3738 LLT DstTy =
MRI.getType(DstReg);
3739 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3744 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3749 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3753 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3756 Builder.buildTrunc(DstReg, MidReg);
3757 MI.eraseFromParent();
3762 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3763 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3764 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3772 if (!
MRI.hasOneNonDBGUse(XorSrc))
3782 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3784 if (!
MRI.hasOneNonDBGUse(Reg))
3787 switch (Def->getOpcode()) {
3792 case TargetOpcode::G_ICMP:
3798 case TargetOpcode::G_FCMP:
3804 case TargetOpcode::G_AND:
3805 case TargetOpcode::G_OR:
3811 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3812 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3820 if (Ty.isVector()) {
3825 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3839 for (
Register Reg : RegsToNegate) {
3844 switch (Def->getOpcode()) {
3847 case TargetOpcode::G_ICMP:
3848 case TargetOpcode::G_FCMP: {
3855 case TargetOpcode::G_AND:
3856 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3858 case TargetOpcode::G_OR:
3859 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3866 MI.eraseFromParent();
3870 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3872 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3876 Register SharedReg =
MI.getOperand(2).getReg();
3890 if (!
MRI.hasOneNonDBGUse(AndReg))
3897 return Y == SharedReg;
3901 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3904 std::tie(
X,
Y) = MatchInfo;
3907 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3908 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3909 MI.getOperand(2).setReg(
Y);
3915 Register DstReg = PtrAdd.getReg(0);
3916 LLT Ty =
MRI.getType(DstReg);
3919 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3922 if (Ty.isPointer()) {
3924 return ConstVal && *ConstVal == 0;
3927 assert(Ty.isVector() &&
"Expecting a vector type");
3934 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3935 PtrAdd.eraseFromParent();
3942 Register Pow2Src1 =
MI.getOperand(2).getReg();
3943 LLT Ty =
MRI.getType(DstReg);
3946 auto NegOne =
Builder.buildConstant(Ty, -1);
3947 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3949 MI.eraseFromParent();
3953 unsigned &SelectOpNo)
const {
3963 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3964 !
MRI.hasOneNonDBGUse(LHS)) {
3965 OtherOperandReg = LHS;
3968 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3969 !
MRI.hasOneNonDBGUse(RHS))
3985 unsigned BinOpcode =
MI.getOpcode();
3990 bool CanFoldNonConst =
3991 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3996 if (CanFoldNonConst)
4017 LLT Ty =
MRI.getType(Dst);
4018 unsigned BinOpcode =
MI.getOpcode();
4025 if (SelectOperand == 1) {
4029 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4031 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4033 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4035 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4038 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4039 MI.eraseFromParent();
4042std::optional<SmallVector<Register, 8>>
4043CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4044 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4073 const unsigned MaxIter =
4075 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4084 return std::nullopt;
4100 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4101 return std::nullopt;
4113static std::optional<std::pair<GZExtLoad *, int64_t>>
4117 "Expected Reg to only have one non-debug use?");
4126 if (Shift % MemSizeInBits != 0)
4127 return std::nullopt;
4132 return std::nullopt;
4134 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4135 return std::nullopt;
4137 return std::make_pair(Load, Shift / MemSizeInBits);
4140std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4141CombinerHelper::findLoadOffsetsForLoadOrCombine(
4144 const unsigned MemSizeInBits)
const {
4147 SmallSetVector<const MachineInstr *, 8> Loads;
4153 GZExtLoad *LowestIdxLoad =
nullptr;
4156 SmallSet<int64_t, 8> SeenIdx;
4160 MachineBasicBlock *
MBB =
nullptr;
4161 const MachineMemOperand *MMO =
nullptr;
4164 GZExtLoad *EarliestLoad =
nullptr;
4167 GZExtLoad *LatestLoad =
nullptr;
4176 for (
auto Reg : RegsToVisit) {
4181 return std::nullopt;
4184 std::tie(Load, DstPos) = *LoadAndPos;
4188 MachineBasicBlock *LoadMBB =
Load->getParent();
4192 return std::nullopt;
4195 auto &LoadMMO =
Load->getMMO();
4199 return std::nullopt;
4206 LoadPtr =
Load->getOperand(1).getReg();
4211 if (!SeenIdx.
insert(Idx).second)
4212 return std::nullopt;
4219 if (BasePtr != LoadPtr)
4220 return std::nullopt;
4222 if (Idx < LowestIdx) {
4224 LowestIdxLoad =
Load;
4231 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4232 return std::nullopt;
4240 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4241 EarliestLoad =
Load;
4242 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4249 "Expected to find a load for each register?");
4250 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4251 LatestLoad &&
"Expected at least two loads?");
4260 const unsigned MaxIter = 20;
4266 if (
MI.isLoadFoldBarrier())
4267 return std::nullopt;
4268 if (Iter++ == MaxIter)
4269 return std::nullopt;
4272 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4278 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4291 LLT Ty =
MRI.getType(Dst);
4297 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4298 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4302 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4309 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4310 if (NarrowMemSizeInBits % 8 != 0)
4323 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4324 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4327 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4334 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4337 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4349 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4350 const unsigned ZeroByteOffset =
4354 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4355 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4356 ZeroOffsetIdx->second != LowestIdx)
4366 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4380 MIB.setInstrAndDebugLoc(*LatestLoad);
4381 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4382 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4384 MIB.buildBSwap(Dst, LoadDst);
4396 if (
MRI.getType(DstReg).isVector())
4400 if (!
MRI.hasOneNonDBGUse(DstReg))
4402 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4404 case TargetOpcode::G_ANYEXT:
4406 case TargetOpcode::G_ZEXT:
4407 case TargetOpcode::G_SEXT:
4414 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4421 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4423 switch (
DefMI->getOpcode()) {
4424 case TargetOpcode::G_LOAD:
4425 case TargetOpcode::G_TRUNC:
4426 case TargetOpcode::G_SEXT:
4427 case TargetOpcode::G_ZEXT:
4428 case TargetOpcode::G_ANYEXT:
4429 case TargetOpcode::G_CONSTANT:
4433 if (InSrcs.
size() > 2)
4447 LLT ExtTy =
MRI.getType(DstReg);
4454 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4455 auto SrcReg =
PHI.getIncomingValue(
I);
4456 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4457 if (!SrcMIs.
insert(SrcMI))
4461 auto *
MBB = SrcMI->getParent();
4463 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4464 InsertPt =
MBB->getFirstNonPHI();
4466 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4469 OldToNewSrcMap[SrcMI] = NewExt;
4474 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4475 NewPhi.addDef(DstReg);
4478 NewPhi.addMBB(MO.getMBB());
4481 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4482 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4490 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4494 LLT SrcTy =
MRI.getType(SrcVec);
4495 if (SrcTy.isScalableVector())
4499 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4502 unsigned VecIdx = Cst->Value.getZExtValue();
4507 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4511 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4512 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4516 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4528 LLT ScalarTy =
MRI.getType(Reg);
4530 LLT DstTy =
MRI.getType(DstReg);
4532 if (ScalarTy != DstTy) {
4534 Builder.buildTrunc(DstReg, Reg);
4535 MI.eraseFromParent();
4543 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4544 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4562 LLT DstTy =
MRI.getType(DstReg);
4567 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4572 unsigned Idx = Cst->getZExtValue();
4575 ExtractedElts.
set(Idx);
4576 SrcDstPairs.emplace_back(
4577 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4580 return ExtractedElts.
all();
4585 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4586 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4587 for (
auto &Pair : SrcDstPairs) {
4588 auto *ExtMI = Pair.second;
4590 ExtMI->eraseFromParent();
4592 MI.eraseFromParent();
4599 MI.eraseFromParent();
4609 bool AllowScalarConstants,
4611 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4614 LLT Ty =
MRI.getType(Dst);
4615 unsigned BitWidth = Ty.getScalarSizeInBits();
4617 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4618 unsigned FshOpc = 0;
4629 int64_t CstShlAmt = 0, CstLShrAmt;
4632 CstShlAmt + CstLShrAmt ==
BitWidth) {
4633 FshOpc = TargetOpcode::G_FSHR;
4639 FshOpc = TargetOpcode::G_FSHL;
4644 FshOpc = TargetOpcode::G_FSHR;
4649 LLT AmtTy =
MRI.getType(Amt);
4651 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4655 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4662 unsigned Opc =
MI.getOpcode();
4663 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4668 unsigned RotateOpc =
4669 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4674 unsigned Opc =
MI.getOpcode();
4675 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4676 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4678 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4679 : TargetOpcode::G_ROTR));
4680 MI.removeOperand(2);
4686 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4687 MI.getOpcode() == TargetOpcode::G_ROTR);
4689 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4691 bool OutOfRange =
false;
4692 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4694 OutOfRange |= CI->getValue().uge(Bitsize);
4701 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4702 MI.getOpcode() == TargetOpcode::G_ROTR);
4704 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4706 LLT AmtTy =
MRI.getType(Amt);
4707 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4708 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4710 MI.getOperand(2).setReg(Amt);
4715 int64_t &MatchInfo)
const {
4716 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4727 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4728 if (KnownRHS.isUnknown())
4731 std::optional<bool> KnownVal;
4732 if (KnownRHS.isZero()) {
4742 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4752 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4761 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4777 LLT DstTy =
MRI.getType(Dst);
4785 auto KnownLHS =
VT->getKnownBits(LHS);
4786 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4789 LLT LHSTy =
MRI.getType(LHS);
4792 unsigned Op = TargetOpcode::COPY;
4793 if (DstSize != LHSSize)
4794 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4805 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4809 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4815 int64_t AndMaskBits;
4823 if (AndMaskBits & OrMaskBits)
4829 if (
MI.getOperand(1).getReg() == AndMaskReg)
4830 MI.getOperand(2).setReg(AndMaskReg);
4831 MI.getOperand(1).setReg(Src);
4841 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4844 LLT Ty =
MRI.getType(Src);
4846 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4848 int64_t Width =
MI.getOperand(2).getImm();
4856 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4860 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4861 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4862 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4872 LLT Ty =
MRI.getType(Dst);
4876 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4879 int64_t AndImm, LSBImm;
4881 const unsigned Size = Ty.getScalarSizeInBits();
4888 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4889 if (MaybeMask & (MaybeMask + 1))
4898 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4899 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4900 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4908 const unsigned Opcode =
MI.getOpcode();
4909 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4911 const Register Dst =
MI.getOperand(0).getReg();
4913 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4914 ? TargetOpcode::G_SBFX
4915 : TargetOpcode::G_UBFX;
4918 LLT Ty =
MRI.getType(Dst);
4920 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4926 const unsigned Size = Ty.getScalarSizeInBits();
4936 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4940 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4944 const int64_t Pos = ShrAmt - ShlAmt;
4945 const int64_t Width =
Size - ShrAmt;
4948 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4949 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4950 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4958 const unsigned Opcode =
MI.getOpcode();
4959 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4961 const Register Dst =
MI.getOperand(0).getReg();
4962 LLT Ty =
MRI.getType(Dst);
4964 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4977 const unsigned Size = Ty.getScalarSizeInBits();
4978 if (ShrAmt < 0 || ShrAmt >=
Size)
4982 if (0 == (SMask >> ShrAmt)) {
4984 B.buildConstant(Dst, 0);
4990 uint64_t UMask = SMask;
4997 const int64_t Pos = ShrAmt;
5002 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5006 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5007 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5008 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5013bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5017 Register Src1Reg = PtrAdd.getBaseReg();
5022 Register Src2Reg = PtrAdd.getOffsetReg();
5024 if (
MRI.hasOneNonDBGUse(Src1Reg))
5034 const APInt &C1APIntVal = *C1;
5035 const APInt &C2APIntVal = *C2;
5036 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5038 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5041 MachineInstr *ConvUseMI = &
UseMI;
5042 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5043 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5044 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5046 if (!
MRI.hasOneNonDBGUse(DefReg))
5048 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5057 TargetLoweringBase::AddrMode AM;
5060 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5062 PtrAdd.getMF()->getFunction().getContext());
5063 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5064 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5070 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5082 Register Src1Reg =
MI.getOperand(1).getReg();
5083 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5095 unsigned PtrAddFlags =
MI.getFlags();
5096 unsigned AddFlags = RHS->getFlags();
5109 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5112 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5114 MI.getOperand(1).setReg(NewBase.getReg(0));
5115 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5119 return !reassociationCanBreakAddressingModePattern(
MI);
5129 std::optional<ValueAndVReg> LHSCstOff;
5139 unsigned PtrAddFlags =
MI.getFlags();
5140 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5142 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5144 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5158 LHSPtrAdd->moveBefore(&
MI);
5161 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5163 MI.getOperand(2).setReg(NewCst.getReg(0));
5166 Observer.changingInstr(*LHSPtrAdd);
5167 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5168 LHSPtrAdd->setFlags(Flags);
5171 return !reassociationCanBreakAddressingModePattern(
MI);
5182 Register Src2Reg =
MI.getOperand(2).getReg();
5183 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5184 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5197 unsigned PtrAddFlags =
MI.getFlags();
5198 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5211 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5213 MI.getOperand(1).setReg(LHSSrc1);
5214 MI.getOperand(2).setReg(NewCst.getReg(0));
5218 return !reassociationCanBreakAddressingModePattern(
MI);
5256 LLT OpRHSTy =
MRI.getType(OpRHS);
5275 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5276 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5284 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5285 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5298 unsigned Opc =
MI.getOpcode();
5311 APInt &MatchInfo)
const {
5312 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5316 MatchInfo = *MaybeCst;
5327 MI.getOperand(1).getReg(),
MRI);
5332 if (Csts.size() == 1)
5333 B.buildConstant(Dst, Csts[0]);
5335 B.buildBuildVectorConstant(Dst, Csts);
5341 APInt &MatchInfo)
const {
5347 MatchInfo = *MaybeCst;
5359 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5365 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5366 MI.getOpcode() == TargetOpcode::G_FMAD);
5367 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5384 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5407 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5411 LLT WideTy =
MRI.getType(Dst);
5415 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5431 case TargetOpcode::G_ADD:
5432 case TargetOpcode::G_SUB:
5433 case TargetOpcode::G_MUL:
5434 case TargetOpcode::G_AND:
5435 case TargetOpcode::G_OR:
5436 case TargetOpcode::G_XOR:
5444 auto Mask = Cst->Value;
5449 unsigned NarrowWidth = Mask.countr_one();
5455 auto &MF = *
MI.getMF();
5458 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5459 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5467 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5468 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5470 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5471 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5473 MI.getOperand(1).setReg(Ext.getReg(0));
5481 unsigned Opc =
MI.getOpcode();
5482 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5489 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5490 : TargetOpcode::G_SADDO;
5491 MI.setDesc(
Builder.getTII().get(NewOpc));
5492 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5501 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5502 MI.getOpcode() == TargetOpcode::G_SMULO);
5511 B.buildConstant(Dst, 0);
5512 B.buildConstant(Carry, 0);
5521 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5522 MI.getOpcode() == TargetOpcode::G_SADDE ||
5523 MI.getOpcode() == TargetOpcode::G_USUBE ||
5524 MI.getOpcode() == TargetOpcode::G_SSUBE);
5529 switch (
MI.getOpcode()) {
5530 case TargetOpcode::G_UADDE:
5531 NewOpcode = TargetOpcode::G_UADDO;
5533 case TargetOpcode::G_SADDE:
5534 NewOpcode = TargetOpcode::G_SADDO;
5536 case TargetOpcode::G_USUBE:
5537 NewOpcode = TargetOpcode::G_USUBO;
5539 case TargetOpcode::G_SSUBE:
5540 NewOpcode = TargetOpcode::G_SSUBO;
5544 MI.setDesc(
B.getTII().get(NewOpcode));
5545 MI.removeOperand(4);
5553 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5586 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5587 B.buildSub(Dst, Zero, ReplaceReg);
5596 unsigned Opcode =
MI.getOpcode();
5597 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5599 Register Dst = UDivorRem.getReg(0);
5600 Register LHS = UDivorRem.getReg(1);
5601 Register RHS = UDivorRem.getReg(2);
5602 LLT Ty =
MRI.getType(Dst);
5610 bool UseSRL =
false;
5615 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5617 if (IsSplat && !Factors.
empty()) {
5624 APInt Divisor = CI->getValue();
5633 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5634 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5644 if (Ty.isVector()) {
5645 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5646 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5649 Factor = Factors[0];
5657 return MIB.buildMul(Ty, Res, Factor);
5660 unsigned KnownLeadingZeros =
5661 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5663 bool UseNPQ =
false;
5665 auto BuildUDIVPattern = [&](
const Constant *
C) {
5667 const APInt &Divisor = CI->getValue();
5669 bool SelNPQ =
false;
5671 unsigned PreShift = 0, PostShift = 0;
5676 if (!Divisor.
isOne()) {
5682 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5684 Magic = std::move(magics.
Magic);
5687 "We shouldn't generate an undefined shift!");
5689 "We shouldn't generate an undefined shift!");
5693 SelNPQ = magics.
IsAdd;
5697 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5698 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5700 MIB.buildConstant(ScalarTy,
5705 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5713 assert(Matched &&
"Expected unary predicate match to succeed");
5715 Register PreShift, PostShift, MagicFactor, NPQFactor;
5718 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5719 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5720 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5721 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5724 "Non-build_vector operation should have been a scalar");
5725 PreShift = PreShifts[0];
5726 MagicFactor = MagicFactors[0];
5727 PostShift = PostShifts[0];
5731 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5734 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5737 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5742 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5744 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5746 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5749 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5750 auto One = MIB.buildConstant(Ty, 1);
5751 auto IsOne = MIB.buildICmp(
5755 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5757 if (Opcode == TargetOpcode::G_UREM) {
5758 auto Prod = MIB.buildMul(Ty, ret, RHS);
5759 return MIB.buildSub(Ty, LHS, Prod);
5765 unsigned Opcode =
MI.getOpcode();
5766 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5769 LLT DstTy =
MRI.getType(Dst);
5771 auto &MF = *
MI.getMF();
5772 AttributeList Attr = MF.getFunction().getAttributes();
5781 if (MF.getFunction().hasMinSize())
5784 if (Opcode == TargetOpcode::G_UDIV &&
5787 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5790 auto *RHSDef =
MRI.getVRegDef(RHS);
5801 {TargetOpcode::G_ICMP,
5805 if (Opcode == TargetOpcode::G_UREM &&
5811 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5820 unsigned Opcode =
MI.getOpcode();
5821 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5824 LLT DstTy =
MRI.getType(Dst);
5828 auto &MF = *
MI.getMF();
5829 AttributeList Attr = MF.getFunction().getAttributes();
5838 if (MF.getFunction().hasMinSize())
5842 if (Opcode == TargetOpcode::G_SDIV &&
5845 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5848 auto *RHSDef =
MRI.getVRegDef(RHS);
5856 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5859 if (Opcode == TargetOpcode::G_SREM &&
5865 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5874 unsigned Opcode =
MI.getOpcode();
5875 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5876 Opcode == TargetOpcode::G_SREM);
5878 Register Dst = SDivorRem.getReg(0);
5879 Register LHS = SDivorRem.getReg(1);
5880 Register RHS = SDivorRem.getReg(2);
5881 LLT Ty =
MRI.getType(Dst);
5888 bool UseSRA =
false;
5894 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5896 if (IsSplat && !ExactFactors.
empty()) {
5898 ExactFactors.
push_back(ExactFactors[0]);
5903 APInt Divisor = CI->getValue();
5913 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5914 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5922 assert(Matched &&
"Expected unary predicate match to succeed");
5925 if (Ty.isVector()) {
5926 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5927 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5929 Shift = ExactShifts[0];
5930 Factor = ExactFactors[0];
5938 return MIB.buildMul(Ty, Res, Factor);
5943 auto BuildSDIVPattern = [&](
const Constant *
C) {
5945 const APInt &Divisor = CI->getValue();
5949 int NumeratorFactor = 0;
5960 NumeratorFactor = 1;
5963 NumeratorFactor = -1;
5966 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5967 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5969 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5970 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5978 assert(Matched &&
"Expected unary predicate match to succeed");
5980 Register MagicFactor, Factor, Shift, ShiftMask;
5983 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5984 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5985 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5986 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5989 "Non-build_vector operation should have been a scalar");
5990 MagicFactor = MagicFactors[0];
5991 Factor = Factors[0];
5993 ShiftMask = ShiftMasks[0];
5997 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6000 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6001 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6004 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6007 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6008 auto T = MIB.buildLShr(Ty, Q, SignShift);
6009 T = MIB.buildAnd(Ty,
T, ShiftMask);
6010 auto ret = MIB.buildAdd(Ty, Q,
T);
6012 if (Opcode == TargetOpcode::G_SREM) {
6013 auto Prod = MIB.buildMul(Ty, ret, RHS);
6014 return MIB.buildSub(Ty, LHS, Prod);
6020 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6021 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6022 "Expected SDIV or UDIV");
6025 auto MatchPow2 = [&](
const Constant *
C) {
6027 return CI && (CI->getValue().isPowerOf2() ||
6028 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6034 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6039 LLT Ty =
MRI.getType(Dst);
6059 unsigned BitWidth = Ty.getScalarSizeInBits();
6060 auto Zero =
Builder.buildConstant(Ty, 0);
6063 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6064 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6066 auto Sign =
Builder.buildAShr(
6070 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6076 auto One =
Builder.buildConstant(Ty, 1);
6077 auto MinusOne =
Builder.buildConstant(Ty, -1);
6081 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6082 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6086 auto Neg =
Builder.buildNeg(Ty, AShr);
6088 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6089 MI.eraseFromParent();
6093 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6098 LLT Ty =
MRI.getType(Dst);
6101 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6102 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6103 MI.eraseFromParent();
6107 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6112 LLT Ty =
MRI.getType(Dst);
6131 unsigned BitWidth = Ty.getScalarSizeInBits();
6132 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6133 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6135 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6136 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6137 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6140 MI.eraseFromParent();
6144 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6147 LLT Ty =
MRI.getType(Dst);
6148 LLT RHSTy =
MRI.getType(RHS);
6150 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6152 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6167 LLT Ty =
MRI.getType(Dst);
6173 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6174 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6175 Builder.buildLShr(Dst, LHS, Trunc);
6176 MI.eraseFromParent();
6183 LLT DstTy =
MRI.getType(Dst);
6184 LLT SrcTy =
MRI.getType(Src);
6186 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6187 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6190 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6208 Builder.buildTruncSSatS(Dst, MatchInfo);
6209 MI.eraseFromParent();
6216 LLT DstTy =
MRI.getType(Dst);
6217 LLT SrcTy =
MRI.getType(Src);
6219 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6220 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6223 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6241 Builder.buildTruncSSatU(Dst, MatchInfo);
6242 MI.eraseFromParent();
6249 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6250 LLT SrcTy =
MRI.getType(Val);
6252 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6253 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6256 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6265 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6274 unsigned Opc =
MI.getOpcode();
6275 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6276 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6277 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6289 Opc = TargetOpcode::G_FSUB;
6294 Opc = TargetOpcode::G_FADD;
6300 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6301 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6310 MI.setDesc(
B.getTII().get(
Opc));
6311 MI.getOperand(1).setReg(
X);
6312 MI.getOperand(2).setReg(
Y);
6320 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6323 MatchInfo =
MI.getOperand(2).getReg();
6324 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6326 const auto LHSCst = Ty.isVector()
6333 if (LHSCst->Value.isNegZero())
6337 if (LHSCst->Value.isPosZero())
6347 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6354 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6368 bool &AllowFusionGlobally,
6370 bool CanReassociate)
const {
6372 auto *MF =
MI.getMF();
6373 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6375 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6383 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6386 if (!HasFMAD && !HasFMA)
6394 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6401 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6403 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6411 unsigned PreferredFusedOpcode =
6412 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6426 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6427 {LHS.MI->getOperand(1).getReg(),
6428 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6437 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6438 {RHS.MI->getOperand(1).getReg(),
6439 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6450 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6452 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6456 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6461 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6463 unsigned PreferredFusedOpcode =
6464 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6478 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6483 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6484 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6493 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6498 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6499 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6510 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6512 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6520 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6522 unsigned PreferredFusedOpcode =
6523 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6536 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6537 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6538 TargetOpcode::G_FMUL) &&
6539 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6540 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6545 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6546 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6547 TargetOpcode::G_FMUL) &&
6548 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6549 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6556 Register X = FMA->getOperand(1).getReg();
6557 Register Y = FMA->getOperand(2).getReg();
6562 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6563 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6564 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6576 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6578 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6585 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6586 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6592 unsigned PreferredFusedOpcode =
6593 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6606 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6607 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6609 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6611 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6618 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6622 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6627 LHS.MI->getOperand(1).getReg(),
6628 LHS.MI->getOperand(2).getReg(),
B);
6639 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6642 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6647 X =
B.buildFPExt(DstType,
X).getReg(0);
6648 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6659 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6663 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6668 RHS.MI->getOperand(1).getReg(),
6669 RHS.MI->getOperand(2).getReg(),
B);
6680 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6683 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6688 X =
B.buildFPExt(DstType,
X).getReg(0);
6689 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6703 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6705 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6713 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6717 int FirstMulHasFewerUses =
true;
6721 FirstMulHasFewerUses =
false;
6723 unsigned PreferredFusedOpcode =
6724 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6727 if (FirstMulHasFewerUses &&
6731 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6732 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6733 {LHS.MI->getOperand(1).getReg(),
6734 LHS.MI->getOperand(2).getReg(), NegZ});
6743 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6744 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6745 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6756 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6758 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6764 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6766 unsigned PreferredFusedOpcode =
6767 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6778 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6779 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6791 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6804 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6806 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6812 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6814 unsigned PreferredFusedOpcode =
6815 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6827 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6828 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6829 {FpExtX, FpExtY, NegZ});
6841 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6844 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6845 {NegY, FpExtZ, LHSReg});
6856 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6858 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6862 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6863 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6867 unsigned PreferredFusedOpcode =
6868 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6872 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6873 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6874 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6885 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6888 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6891 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6901 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6914 unsigned &IdxToPropagate)
const {
6916 switch (
MI.getOpcode()) {
6919 case TargetOpcode::G_FMINNUM:
6920 case TargetOpcode::G_FMAXNUM:
6921 PropagateNaN =
false;
6923 case TargetOpcode::G_FMINIMUM:
6924 case TargetOpcode::G_FMAXIMUM:
6925 PropagateNaN =
true;
6929 auto MatchNaN = [&](
unsigned Idx) {
6930 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6934 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6938 return MatchNaN(1) || MatchNaN(2);
6946 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6956 return N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0));
6973 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6974 if (&U == &
MI || U.getParent() !=
MI.getParent())
6976 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6977 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
6978 !IsOne(U.getOperand(1).getReg())) {
6991 return MatchInfo.
size() >= MinUses;
6999 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7000 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7001 MatchInfo[0]->getOperand(2).getReg(),
7002 MatchInfo[0]->getFlags());
7007 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7008 Div->getOperand(0).getReg(),
MI->getFlags());
7009 MI->eraseFromParent();
7014 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7024 Reg == MaybeSameReg;
7026 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7047 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7056 return MRI.getType(MatchInfo) == DstVecTy;
7059 std::optional<ValueAndVReg> ShiftAmount;
7068 return MRI.getType(MatchInfo) == DstVecTy;
7083 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7090 std::optional<ValueAndVReg> ShiftAmt;
7096 LLT MatchTy =
MRI.getType(MatchInfo);
7097 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7098 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7101unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7103 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7104 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7105 "Expected a NaN behaviour?");
7115 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7116 return TargetOpcode::G_FMAXNUM;
7117 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7118 return TargetOpcode::G_FMAXIMUM;
7119 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7120 return TargetOpcode::G_FMAXNUM;
7121 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7122 return TargetOpcode::G_FMAXIMUM;
7128 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7129 return TargetOpcode::G_FMINNUM;
7130 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7131 return TargetOpcode::G_FMINIMUM;
7132 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7133 return TargetOpcode::G_FMINNUM;
7134 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7136 return TargetOpcode::G_FMINIMUM;
7140CombinerHelper::SelectPatternNaNBehaviour
7142 bool IsOrderedComparison)
const {
7143 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7144 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7146 if (!LHSSafe && !RHSSafe)
7147 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7148 if (LHSSafe && RHSSafe)
7149 return SelectPatternNaNBehaviour::RETURNS_ANY;
7152 if (IsOrderedComparison)
7153 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7154 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7157 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7158 : SelectPatternNaNBehaviour::RETURNS_NAN;
7167 LLT DstTy =
MRI.getType(Dst);
7180 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7182 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7184 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7187 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7188 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7189 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7190 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7192 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7195 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7200 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7205 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7207 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7211 MatchInfo = [=](MachineIRBuilder &
B) {
7212 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7220 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7227 Register TrueVal =
MI.getOperand(2).getReg();
7228 Register FalseVal =
MI.getOperand(3).getReg();
7229 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7234 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7247 if (MatchedSub &&
X != OpLHS)
7255 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7258 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7259 B.buildICmp(Pred, Dst,
Y, Zero);
7266static std::optional<unsigned>
7268 std::optional<int64_t> &Result) {
7269 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7270 Opcode == TargetOpcode::G_ASHR) &&
7271 "Expect G_SHL, G_LSHR or G_ASHR.");
7272 auto SignificantBits = 0;
7274 case TargetOpcode::G_SHL:
7278 case TargetOpcode::G_LSHR:
7282 case TargetOpcode::G_ASHR:
7291 Result = std::nullopt;
7302 Register ShiftVal =
MI.getOperand(1).getReg();
7303 Register ShiftReg =
MI.getOperand(2).getReg();
7304 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7305 auto IsShiftTooBig = [&](
const Constant *
C) {
7310 MatchInfo = std::nullopt;
7314 MI.getOpcode(), MatchInfo);
7315 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7321 unsigned LHSOpndIdx = 1;
7322 unsigned RHSOpndIdx = 2;
7323 switch (
MI.getOpcode()) {
7324 case TargetOpcode::G_UADDO:
7325 case TargetOpcode::G_SADDO:
7326 case TargetOpcode::G_UMULO:
7327 case TargetOpcode::G_SMULO:
7334 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7335 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7340 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7341 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7345 return MRI.getVRegDef(RHS)->getOpcode() !=
7346 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7353 std::optional<FPValueAndVReg> ValAndVReg;
7361 unsigned LHSOpndIdx = 1;
7362 unsigned RHSOpndIdx = 2;
7363 switch (
MI.getOpcode()) {
7364 case TargetOpcode::G_UADDO:
7365 case TargetOpcode::G_SADDO:
7366 case TargetOpcode::G_UMULO:
7367 case TargetOpcode::G_SMULO:
7374 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7375 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7376 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7377 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7381bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7383 if (SrcTy.isFixedVector())
7385 if (SrcTy.isScalar()) {
7389 return IConstant && IConstant->Value == 1;
7394bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7395 LLT SrcTy =
MRI.getType(Src);
7397 return isConstantSplatVector(Src, 0, AllowUndefs);
7402 return IConstant && IConstant->Value == 0;
7409bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7410 bool AllowUndefs)
const {
7416 for (
unsigned I = 0;
I < NumSources; ++
I) {
7417 GImplicitDef *ImplicitDef =
7419 if (ImplicitDef && AllowUndefs)
7421 if (ImplicitDef && !AllowUndefs)
7423 std::optional<ValueAndVReg> IConstant =
7425 if (IConstant && IConstant->Value == SplatValue)
7435CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7438 return IConstant->Value;
7442 return std::nullopt;
7445 std::optional<APInt>
Value = std::nullopt;
7446 for (
unsigned I = 0;
I < NumSources; ++
I) {
7447 std::optional<ValueAndVReg> IConstant =
7450 return std::nullopt;
7452 Value = IConstant->Value;
7453 else if (*
Value != IConstant->Value)
7454 return std::nullopt;
7460bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7470 for (
unsigned I = 0;
I < NumSources; ++
I) {
7471 std::optional<ValueAndVReg> IConstant =
7480bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7487 LLT CondTy =
MRI.getType(
Select->getCondReg());
7488 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7498 std::optional<ValueAndVReg> TrueOpt =
7500 std::optional<ValueAndVReg> FalseOpt =
7503 if (!TrueOpt || !FalseOpt)
7506 APInt TrueValue = TrueOpt->Value;
7507 APInt FalseValue = FalseOpt->Value;
7511 MatchInfo = [=](MachineIRBuilder &
B) {
7512 B.setInstrAndDebugLoc(*
Select);
7513 B.buildZExtOrTrunc(Dest,
Cond);
7520 MatchInfo = [=](MachineIRBuilder &
B) {
7521 B.setInstrAndDebugLoc(*
Select);
7522 B.buildSExtOrTrunc(Dest,
Cond);
7529 MatchInfo = [=](MachineIRBuilder &
B) {
7530 B.setInstrAndDebugLoc(*
Select);
7531 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7532 B.buildNot(Inner,
Cond);
7533 B.buildZExtOrTrunc(Dest, Inner);
7540 MatchInfo = [=](MachineIRBuilder &
B) {
7541 B.setInstrAndDebugLoc(*
Select);
7542 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7543 B.buildNot(Inner,
Cond);
7544 B.buildSExtOrTrunc(Dest, Inner);
7550 if (TrueValue - 1 == FalseValue) {
7551 MatchInfo = [=](MachineIRBuilder &
B) {
7552 B.setInstrAndDebugLoc(*
Select);
7553 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7554 B.buildZExtOrTrunc(Inner,
Cond);
7555 B.buildAdd(Dest, Inner, False);
7561 if (TrueValue + 1 == FalseValue) {
7562 MatchInfo = [=](MachineIRBuilder &
B) {
7563 B.setInstrAndDebugLoc(*
Select);
7564 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7565 B.buildSExtOrTrunc(Inner,
Cond);
7566 B.buildAdd(Dest, Inner, False);
7573 MatchInfo = [=](MachineIRBuilder &
B) {
7574 B.setInstrAndDebugLoc(*
Select);
7575 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7576 B.buildZExtOrTrunc(Inner,
Cond);
7579 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7580 B.buildShl(Dest, Inner, ShAmtC, Flags);
7587 MatchInfo = [=](MachineIRBuilder &
B) {
7588 B.setInstrAndDebugLoc(*
Select);
7590 B.buildNot(Not,
Cond);
7591 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7592 B.buildZExtOrTrunc(Inner, Not);
7595 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7596 B.buildShl(Dest, Inner, ShAmtC, Flags);
7603 MatchInfo = [=](MachineIRBuilder &
B) {
7604 B.setInstrAndDebugLoc(*
Select);
7605 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7606 B.buildSExtOrTrunc(Inner,
Cond);
7607 B.buildOr(Dest, Inner, False, Flags);
7614 MatchInfo = [=](MachineIRBuilder &
B) {
7615 B.setInstrAndDebugLoc(*
Select);
7617 B.buildNot(Not,
Cond);
7618 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7619 B.buildSExtOrTrunc(Inner, Not);
7620 B.buildOr(Dest, Inner, True, Flags);
7629bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7636 LLT CondTy =
MRI.getType(
Select->getCondReg());
7637 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7646 if (CondTy != TrueTy)
7651 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7652 MatchInfo = [=](MachineIRBuilder &
B) {
7653 B.setInstrAndDebugLoc(*
Select);
7654 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7655 B.buildZExtOrTrunc(Ext,
Cond);
7656 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7657 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7664 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7665 MatchInfo = [=](MachineIRBuilder &
B) {
7666 B.setInstrAndDebugLoc(*
Select);
7667 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7668 B.buildZExtOrTrunc(Ext,
Cond);
7669 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7670 B.buildAnd(DstReg, Ext, FreezeTrue);
7676 if (isOneOrOneSplat(False,
true)) {
7677 MatchInfo = [=](MachineIRBuilder &
B) {
7678 B.setInstrAndDebugLoc(*
Select);
7680 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7681 B.buildNot(Inner,
Cond);
7683 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7684 B.buildZExtOrTrunc(Ext, Inner);
7685 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7686 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7692 if (isZeroOrZeroSplat(True,
true)) {
7693 MatchInfo = [=](MachineIRBuilder &
B) {
7694 B.setInstrAndDebugLoc(*
Select);
7696 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7697 B.buildNot(Inner,
Cond);
7699 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7700 B.buildZExtOrTrunc(Ext, Inner);
7701 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7702 B.buildAnd(DstReg, Ext, FreezeFalse);
7718 LLT DstTy =
MRI.getType(DstReg);
7724 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7733 Register CmpLHS = Cmp->getLHSReg();
7734 Register CmpRHS = Cmp->getRHSReg();
7737 if (True == CmpRHS && False == CmpLHS) {
7745 if (True != CmpLHS || False != CmpRHS)
7785 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7786 Register DestReg =
MI.getOperand(0).getReg();
7787 LLT DestTy =
MRI.getType(DestReg);
7799 if (
isLegal({NewOpc, {DestTy}})) {
7801 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7813 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7816 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7826bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7828 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7829 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7833 unsigned Flags = Logic->
getFlags();
7852 std::optional<ValueAndVReg> MaybeC1 =
7856 C1 = MaybeC1->Value;
7858 std::optional<ValueAndVReg> MaybeC2 =
7862 C2 = MaybeC2->Value;
7883 std::optional<APInt> Offset1;
7884 std::optional<APInt> Offset2;
7887 std::optional<ValueAndVReg> MaybeOffset1 =
7890 R1 =
Add->getLHSReg();
7891 Offset1 = MaybeOffset1->Value;
7895 std::optional<ValueAndVReg> MaybeOffset2 =
7898 R2 =
Add->getLHSReg();
7899 Offset2 = MaybeOffset2->Value;
7918 bool CreateMask =
false;
7931 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7944 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7953 MatchInfo = [=](MachineIRBuilder &
B) {
7954 if (CreateMask &&
Offset != 0) {
7955 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7956 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7957 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7958 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7959 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7960 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7961 B.buildZExtOrTrunc(DstReg, ICmp);
7962 }
else if (CreateMask &&
Offset == 0) {
7963 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7964 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7965 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7966 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7967 B.buildZExtOrTrunc(DstReg, ICmp);
7968 }
else if (!CreateMask &&
Offset != 0) {
7969 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7970 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7971 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7972 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7973 B.buildZExtOrTrunc(DstReg, ICmp);
7974 }
else if (!CreateMask &&
Offset == 0) {
7975 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7976 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7977 B.buildZExtOrTrunc(DstReg, ICmp);
7985bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7991 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8003 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8009 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8010 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8011 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8012 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8023 if (LHS0 == RHS1 && LHS1 == RHS0) {
8029 if (LHS0 == RHS0 && LHS1 == RHS1) {
8033 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8035 MatchInfo = [=](MachineIRBuilder &
B) {
8040 auto False =
B.buildConstant(CmpTy, 0);
8041 B.buildZExtOrTrunc(DestReg, False);
8048 B.buildZExtOrTrunc(DestReg, True);
8050 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8051 B.buildZExtOrTrunc(DestReg, Cmp);
8063 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8066 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8075 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8078 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8093 bool IsSigned =
Add->isSigned();
8094 LLT DstTy =
MRI.getType(Dst);
8095 LLT CarryTy =
MRI.getType(Carry);
8098 if (
MRI.use_nodbg_empty(Carry) &&
8101 B.buildAdd(Dst, LHS, RHS);
8102 B.buildUndef(Carry);
8108 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8111 B.buildSAddo(Dst, Carry, RHS, LHS);
8117 B.buildUAddo(Dst, Carry, RHS, LHS);
8122 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8123 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8129 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8130 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8132 B.buildConstant(Dst, Result);
8133 B.buildConstant(Carry, Overflow);
8141 B.buildCopy(Dst, LHS);
8142 B.buildConstant(Carry, 0);
8151 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8154 std::optional<APInt> MaybeAddRHS =
8155 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8158 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8159 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8163 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8164 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8170 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8171 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8196 B.buildConstant(Carry, 0);
8203 B.buildAdd(Dst, LHS, RHS);
8204 B.buildConstant(Carry, 1);
8216 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8219 B.buildConstant(Carry, 0);
8235 B.buildConstant(Carry, 0);
8242 B.buildAdd(Dst, LHS, RHS);
8243 B.buildConstant(Carry, 1);
8261 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8267 auto [Dst,
Base] =
MI.getFirst2Regs();
8268 LLT Ty =
MRI.getType(Dst);
8272 Builder.buildFConstant(Dst, 1.0);
8273 MI.removeFromParent();
8285 std::optional<SrcOp> Res;
8287 while (ExpVal > 0) {
8292 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8295 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8302 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8306 MI.eraseFromParent();
8315 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8322 LLT DstTy =
MRI.getType(Dst);
8325 auto Const =
B.buildConstant(DstTy, C1 - C2);
8326 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8338 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8345 LLT DstTy =
MRI.getType(Dst);
8348 auto Const =
B.buildConstant(DstTy, C2 - C1);
8349 B.buildSub(Dst, Const,
Add->getLHSReg());
8361 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8368 LLT DstTy =
MRI.getType(Dst);
8371 auto Const =
B.buildConstant(DstTy, C1 + C2);
8384 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8391 LLT DstTy =
MRI.getType(Dst);
8394 auto Const =
B.buildConstant(DstTy, C1 - C2);
8407 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8414 LLT DstTy =
MRI.getType(Dst);
8417 auto Const =
B.buildConstant(DstTy, C2 - C1);
8418 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8465 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8469 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8472 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8473 LLT SmallBvTy = DstTy;
8477 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8482 {TargetOpcode::G_ANYEXT,
8494 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8495 Ops.push_back(AnyExt.getReg(0));
8513 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8514 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8515 const unsigned NumDstElts = OrigMask.
size();
8516 for (
unsigned i = 0; i != NumDstElts; ++i) {
8517 int Idx = OrigMask[i];
8518 if (Idx >= (
int)NumSrcElems) {
8529 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8530 std::move(NewMask));
8537 const unsigned MaskSize = Mask.size();
8538 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8543 if (Idx < (
int)NumElems)
8544 Mask[
I] = Idx + NumElems;
8546 Mask[
I] = Idx - NumElems;
8556 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8559 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8562 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8563 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8565 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8569 const unsigned NumSrcElems = Src1Ty.getNumElements();
8571 bool TouchesSrc1 =
false;
8572 bool TouchesSrc2 =
false;
8573 const unsigned NumElems = Mask.size();
8574 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8578 if (Mask[Idx] < (
int)NumSrcElems)
8584 if (TouchesSrc1 == TouchesSrc2)
8587 Register NewSrc1 = Shuffle.getSrc1Reg();
8590 NewSrc1 = Shuffle.getSrc2Reg();
8595 auto Undef =
B.buildUndef(Src1Ty);
8596 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8610 LLT DstTy =
MRI.getType(Dst);
8611 LLT CarryTy =
MRI.getType(Carry);
8633 B.buildConstant(Carry, 0);
8640 B.buildSub(Dst, LHS, RHS);
8658 B.buildConstant(Carry, 0);
8665 B.buildSub(Dst, LHS, RHS);
8682 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8683 "Expected G_CTLZ variant");
8688 LLT Ty =
MRI.getType(Dst);
8689 LLT SrcTy =
MRI.getType(Src);
8691 if (!(Ty.isValid() && Ty.isScalar()))
8700 switch (
LI->getAction(Query).Action) {
8711 bool NeedAdd =
true;
8719 unsigned BitWidth = Ty.getScalarSizeInBits();
8730 B.buildCTLS(Dst,
X);
8734 auto Ctls =
B.buildCTLS(Ty,
X);
8735 auto One =
B.buildConstant(Ty, 1);
8737 B.buildAdd(Dst, Ctls, One);
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 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 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 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
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...