46#define DEBUG_TYPE "gi-combiner"
55 cl::desc(
"Force all indexed operations to be "
56 "legal for the GlobalISel combiner"));
65 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
66 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
71 return *
Builder.getMF().getSubtarget().getTargetLowering();
89 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
97 LLT Ty = MRI.getType(V);
108 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
109 return ByteWidth -
I - 1;
129static std::optional<bool>
133 unsigned Width = MemOffset2Idx.
size();
136 bool BigEndian =
true, LittleEndian =
true;
137 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
138 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
139 if (MemOffsetAndIdx == MemOffset2Idx.
end())
141 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
142 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
145 if (!BigEndian && !LittleEndian)
149 assert((BigEndian != LittleEndian) &&
150 "Pattern cannot be both big and little endian!");
157 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
185 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
186 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
193 if (
MRI.constrainRegAttrs(ToReg, FromReg))
194 MRI.replaceRegWith(FromReg, ToReg);
196 Builder.buildCopy(FromReg, ToReg);
198 Observer.finishedChangingAllUsesOfReg();
213 unsigned ToOpcode)
const {
228 MRI.setRegBank(Reg, *RegBank);
239 if (
MI.getOpcode() != TargetOpcode::COPY)
249 MI.eraseFromParent();
258 if (!
MRI.hasOneNonDBGUse(OrigOp))
277 std::optional<MachineOperand> MaybePoisonOperand;
279 if (!Operand.isReg())
285 if (!MaybePoisonOperand)
286 MaybePoisonOperand = Operand;
295 if (!MaybePoisonOperand) {
300 B.buildCopy(
DstOp, OrigOp);
305 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
306 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
313 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
324 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
325 "Invalid instruction");
335 assert(Def &&
"Operand not defined");
336 if (!
MRI.hasOneNonDBGUse(Reg))
338 switch (Def->getOpcode()) {
339 case TargetOpcode::G_BUILD_VECTOR:
344 Ops.push_back(BuildVecMO.getReg());
346 case TargetOpcode::G_IMPLICIT_DEF: {
347 LLT OpType =
MRI.getType(Reg);
354 OpType.getScalarType() &&
355 "All undefs should have the same type");
358 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
359 EltIdx != EltEnd; ++EltIdx)
360 Ops.push_back(
Undef->getOperand(0).getReg());
369 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
371 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
386 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
399 MI.eraseFromParent();
405 Register SrcVec1 = Shuffle.getSrc1Reg();
406 Register SrcVec2 = Shuffle.getSrc2Reg();
407 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
408 int Width =
MRI.getType(SrcVec1).getNumElements();
410 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
411 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
415 for (
int Val : Shuffle.getMask()) {
418 else if (Val < Width)
419 Extracts.
push_back(Unmerge1.getReg(Val));
421 Extracts.
push_back(Unmerge2.getReg(Val - Width));
423 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
424 if (Extracts.
size() == 1)
425 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
427 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
428 MI.eraseFromParent();
438 if (!ConcatMI1 || !ConcatMI2)
442 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
443 MRI.getType(ConcatMI2->getSourceReg(0)))
446 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
447 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
449 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
453 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
454 if (i + j >= Mask.size())
456 if (Mask[i + j] != -1)
460 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
463 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
464 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
465 if (i + j >= Mask.size())
467 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
473 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
475 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
476 ConcatMI1->getNumSources()));
484 {TargetOpcode::G_CONCAT_VECTORS,
485 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
496 SrcTy =
MRI.getType(Reg);
498 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
505 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
511 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
514 MI.eraseFromParent();
528 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
529 "Invalid instruction kind");
530 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
532 LLT SrcType =
MRI.getType(Src1);
534 unsigned DstNumElts = DstType.getNumElements();
535 unsigned SrcNumElts = SrcType.getNumElements();
552 if (DstNumElts < 2 * SrcNumElts)
557 if (DstNumElts % SrcNumElts != 0)
563 unsigned NumConcat = DstNumElts / SrcNumElts;
566 for (
unsigned i = 0; i != DstNumElts; ++i) {
573 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
574 (ConcatSrcs[i / SrcNumElts] >= 0 &&
575 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
578 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
585 for (
auto Src : ConcatSrcs) {
589 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
591 Ops.push_back(UndefReg);
604 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
612 MI.eraseFromParent();
621 const LLT TyForCandidate,
622 unsigned OpcodeForCandidate,
627 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
638 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
641 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
642 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
643 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
651 OpcodeForCandidate == TargetOpcode::G_ZEXT)
653 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
654 OpcodeForCandidate == TargetOpcode::G_SEXT)
655 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
664 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
675static void InsertInsnsWithoutSideEffectsBeforeUse(
687 InsertBB = PredBB->
getMBB();
692 if (InsertBB ==
DefMI.getParent()) {
694 Inserter(InsertBB, std::next(InsertPt), UseMO);
713 unsigned CandidateLoadOpc;
715 case TargetOpcode::G_ANYEXT:
716 CandidateLoadOpc = TargetOpcode::G_LOAD;
718 case TargetOpcode::G_SEXT:
719 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
721 case TargetOpcode::G_ZEXT:
722 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
727 return CandidateLoadOpc;
744 LLT LoadValueTy =
MRI.getType(LoadReg);
766 unsigned PreferredOpcode =
768 ? TargetOpcode::G_ANYEXT
770 Preferred = {
LLT(), PreferredOpcode,
nullptr};
771 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
772 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
773 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
774 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
775 const auto &MMO = LoadMI->
getMMO();
783 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
785 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
789 Preferred = ChoosePreferredUse(
MI, Preferred,
790 MRI.getType(
UseMI.getOperand(0).getReg()),
800 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
818 if (PreviouslyEmitted) {
825 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
826 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
828 EmittedInsns[InsertIntoBB] = NewMI;
834 MI.setDesc(
Builder.getTII().get(LoadOpc));
841 for (
auto *UseMO :
Uses) {
847 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
850 const LLT UseDstTy =
MRI.getType(UseDstReg);
851 if (UseDstReg != ChosenDstReg) {
852 if (Preferred.
Ty == UseDstTy) {
889 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
904 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
907 MI.getOperand(0).setReg(ChosenDstReg);
913 assert(
MI.getOpcode() == TargetOpcode::G_AND);
924 if (
MRI.getType(Dst).isVector())
932 APInt MaskVal = MaybeMask->Value;
941 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
945 LLT RegTy =
MRI.getType(LoadReg);
953 if (MaskSizeBits > LoadSizeBits.
getValue())
973 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
979 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
983 B.setInstrAndDebugLoc(*LoadMI);
984 auto &MF =
B.getMF();
986 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
987 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
996 "shouldn't consider debug uses");
1004 if (DefOrUse ==
MBB.end())
1006 return &*DefOrUse == &
DefMI;
1012 "shouldn't consider debug uses");
1015 else if (
DefMI.getParent() !=
UseMI.getParent())
1022 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1026 if (
MRI.getType(SrcReg).isVector())
1031 LoadUser = TruncSrc;
1033 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1038 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1040 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1042 if (LoadSizeBits == SizeInBits)
1049 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1050 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1051 MI.eraseFromParent();
1055 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1056 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1059 LLT RegTy =
MRI.getType(DstReg);
1067 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1070 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1075 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1078 if (NewSizeBits < 8)
1090 if (LoadDef->isSimple())
1092 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1097 {
MRI.getType(LoadDef->getDstReg()),
1098 MRI.getType(LoadDef->getPointerReg())},
1102 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1107 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1108 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1110 unsigned ScalarSizeBits;
1111 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1120 auto &MMO = LoadDef->
getMMO();
1121 Builder.setInstrAndDebugLoc(*LoadDef);
1123 auto PtrInfo = MMO.getPointerInfo();
1124 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1125 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1127 MI.eraseFromParent();
1138 auto *MF =
MI->getMF();
1145 AM.
BaseOffs = CstOff->getSExtValue();
1150 MF->getDataLayout(), AM,
1152 MF->getFunction().getContext()),
1153 MI->getMMO().getAddrSpace());
1158 case TargetOpcode::G_LOAD:
1159 return TargetOpcode::G_INDEXED_LOAD;
1160 case TargetOpcode::G_STORE:
1161 return TargetOpcode::G_INDEXED_STORE;
1162 case TargetOpcode::G_ZEXTLOAD:
1163 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1164 case TargetOpcode::G_SEXTLOAD:
1165 return TargetOpcode::G_INDEXED_SEXTLOAD;
1171bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1181 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1182 OpTys = {PtrTy, Ty, Ty};
1184 OpTys = {Ty, PtrTy};
1186 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1192 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1193 "considered for post-indexing."));
1197 bool &RematOffset)
const {
1210 if (!isIndexedLoadStoreLegal(LdSt))
1219 unsigned NumUsesChecked = 0;
1232 if (StoredValDef == &
Use)
1235 Offset = PtrAdd->getOffsetReg();
1237 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1243 RematOffset =
false;
1247 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1252 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1253 if (&BasePtrUse == PtrDef)
1259 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1261 isIndexedLoadStoreLegal(*BasePtrLdSt))
1267 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1268 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1271 if (BaseUseUse.getParent() != LdSt.
getParent())
1283 Addr = PtrAdd->getReg(0);
1284 Base = PtrAdd->getBaseReg();
1299 MRI.hasOneNonDBGUse(Addr))
1306 if (!isIndexedLoadStoreLegal(LdSt))
1310 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1315 if (
Base == St->getValueReg())
1320 if (St->getValueReg() == Addr)
1325 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1326 if (AddrUse.getParent() != LdSt.
getParent())
1331 bool RealUse =
false;
1332 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1350 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1360 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1367 if (!LoadMI->isSimple())
1379 const unsigned MaxIter = 20;
1382 if (
II->isLoadFoldBarrier())
1384 if (Iter++ == MaxIter)
1400 int Elt = CVal->getZExtValue();
1413 Register VecPtr = LoadMI->getPointerReg();
1414 LLT PtrTy =
MRI.getType(VecPtr);
1422 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1445 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1460 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1462 if (!MatchInfo.
IsPre &&
1463 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1473 unsigned Opcode =
MI.getOpcode();
1474 bool IsStore = Opcode == TargetOpcode::G_STORE;
1480 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1482 *OldCst->getOperand(1).getCImm());
1483 MatchInfo.
Offset = NewCst.getReg(0);
1486 auto MIB =
Builder.buildInstr(NewOpcode);
1488 MIB.addDef(MatchInfo.
Addr);
1489 MIB.addUse(
MI.getOperand(0).getReg());
1491 MIB.addDef(
MI.getOperand(0).getReg());
1492 MIB.addDef(MatchInfo.
Addr);
1495 MIB.addUse(MatchInfo.
Base);
1496 MIB.addUse(MatchInfo.
Offset);
1497 MIB.addImm(MatchInfo.
IsPre);
1498 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1499 MI.eraseFromParent();
1507 unsigned Opcode =
MI.getOpcode();
1508 bool IsDiv, IsSigned;
1513 case TargetOpcode::G_SDIV:
1514 case TargetOpcode::G_UDIV: {
1516 IsSigned = Opcode == TargetOpcode::G_SDIV;
1519 case TargetOpcode::G_SREM:
1520 case TargetOpcode::G_UREM: {
1522 IsSigned = Opcode == TargetOpcode::G_SREM;
1528 unsigned DivOpcode, RemOpcode, DivremOpcode;
1530 DivOpcode = TargetOpcode::G_SDIV;
1531 RemOpcode = TargetOpcode::G_SREM;
1532 DivremOpcode = TargetOpcode::G_SDIVREM;
1534 DivOpcode = TargetOpcode::G_UDIV;
1535 RemOpcode = TargetOpcode::G_UREM;
1536 DivremOpcode = TargetOpcode::G_UDIVREM;
1554 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1555 if (
MI.getParent() ==
UseMI.getParent() &&
1556 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1557 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1570 unsigned Opcode =
MI.getOpcode();
1571 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1574 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1575 DestDivReg =
MI.getOperand(0).getReg();
1579 DestRemReg =
MI.getOperand(0).getReg();
1583 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1590 Builder.setInstrAndDebugLoc(*FirstInst);
1592 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1593 : TargetOpcode::G_UDIVREM,
1594 {DestDivReg, DestRemReg},
1596 MI.eraseFromParent();
1602 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1619 if (BrIt ==
MBB->begin())
1621 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1623 BrCond = &*std::prev(BrIt);
1624 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1630 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1631 MBB->isLayoutSuccessor(BrCondTarget);
1637 Builder.setInstrAndDebugLoc(*BrCond);
1642 auto True =
Builder.buildConstant(
1648 MI.getOperand(0).setMBB(FallthroughBB);
1663 return Helper.lowerMemcpyInline(
MI) ==
1668 unsigned MaxLen)
const {
1680 switch (
MI.getOpcode()) {
1683 case TargetOpcode::G_FNEG: {
1684 Result.changeSign();
1687 case TargetOpcode::G_FABS: {
1691 case TargetOpcode::G_FCEIL:
1694 case TargetOpcode::G_FFLOOR:
1697 case TargetOpcode::G_INTRINSIC_TRUNC:
1700 case TargetOpcode::G_INTRINSIC_ROUND:
1703 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1706 case TargetOpcode::G_FRINT:
1707 case TargetOpcode::G_FNEARBYINT:
1711 case TargetOpcode::G_FPEXT:
1712 case TargetOpcode::G_FPTRUNC: {
1719 case TargetOpcode::G_FSQRT: {
1723 Result =
APFloat(sqrt(Result.convertToDouble()));
1726 case TargetOpcode::G_FLOG2: {
1746 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1747 MI.eraseFromParent();
1758 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1768 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1781 Type *AccessTy =
nullptr;
1782 auto &MF = *
MI.getMF();
1783 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1786 MF.getFunction().getContext());
1791 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1796 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1798 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1799 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1800 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1801 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1810 unsigned PtrAddFlags =
MI.getFlags();
1811 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1827 MatchInfo.
Flags = Flags;
1833 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1835 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1839 MI.getOperand(1).setReg(MatchInfo.
Base);
1840 MI.getOperand(2).setReg(NewOffset.getReg(0));
1854 unsigned Opcode =
MI.getOpcode();
1855 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1856 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1857 Opcode == TargetOpcode::G_USHLSAT) &&
1858 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1878 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1883 if (Opcode == TargetOpcode::G_USHLSAT &&
1884 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1892 unsigned Opcode =
MI.getOpcode();
1893 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1894 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1895 Opcode == TargetOpcode::G_USHLSAT) &&
1896 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1898 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1899 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1900 auto Imm = MatchInfo.
Imm;
1902 if (Imm >= ScalarSizeInBits) {
1904 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1905 Builder.buildConstant(
MI.getOperand(0), 0);
1906 MI.eraseFromParent();
1911 Imm = ScalarSizeInBits - 1;
1914 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1917 MI.getOperand(1).setReg(MatchInfo.
Reg);
1918 MI.getOperand(2).setReg(NewImm);
1934 unsigned ShiftOpcode =
MI.getOpcode();
1935 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1936 ShiftOpcode == TargetOpcode::G_ASHR ||
1937 ShiftOpcode == TargetOpcode::G_LSHR ||
1938 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1939 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1940 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1943 Register LogicDest =
MI.getOperand(1).getReg();
1944 if (!
MRI.hasOneNonDBGUse(LogicDest))
1948 unsigned LogicOpcode = LogicMI->
getOpcode();
1949 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1950 LogicOpcode != TargetOpcode::G_XOR)
1954 const Register C1 =
MI.getOperand(2).getReg();
1956 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1959 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1963 if (
MI->getOpcode() != ShiftOpcode ||
1964 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1973 ShiftVal = MaybeImmVal->Value.getSExtValue();
1984 if (matchFirstShift(LogicMIOp1, C0Val)) {
1986 MatchInfo.
Shift2 = LogicMIOp1;
1987 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1989 MatchInfo.
Shift2 = LogicMIOp2;
1993 MatchInfo.
ValSum = C0Val + C1Val;
1996 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
1999 MatchInfo.
Logic = LogicMI;
2005 unsigned Opcode =
MI.getOpcode();
2006 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2007 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2008 Opcode == TargetOpcode::G_SSHLSAT) &&
2009 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2011 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2012 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2018 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2027 Register Shift2Const =
MI.getOperand(2).getReg();
2029 .buildInstr(Opcode, {DestType},
2039 MI.eraseFromParent();
2044 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2066 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2067 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2068 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2069 LLT SrcTy =
MRI.getType(SrcReg);
2071 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2072 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2073 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2081 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2085 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2100 LLT InnerShiftTy =
MRI.getType(InnerShift);
2102 if ((N1C + N001C).ult(InnerShiftSize)) {
2108 if ((N001C + OpSizeInBits) == InnerShiftSize)
2110 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2111 MatchInfo.
Mask =
true;
2121 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2128 if (MatchInfo.
Mask ==
true) {
2136 Builder.buildTrunc(Dst, Shift);
2137 MI.eraseFromParent();
2141 unsigned &ShiftVal)
const {
2142 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2148 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2149 return (
static_cast<int32_t
>(ShiftVal) != -1);
2153 unsigned &ShiftVal)
const {
2154 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2156 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2159 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2160 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2181 auto NegCst =
B.buildConstant(Ty, -Imm);
2183 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2184 MI.getOperand(2).setReg(NegCst.getReg(0));
2186 if (Imm.isMinSignedValue())
2196 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2211 if (!MaybeShiftAmtVal)
2215 LLT SrcTy =
MRI.getType(ExtSrc);
2225 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2226 MatchData.
Reg = ExtSrc;
2227 MatchData.
Imm = ShiftAmt;
2229 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2230 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2231 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2237 int64_t ShiftAmtVal = MatchData.
Imm;
2239 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2240 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2242 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2243 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2244 MI.eraseFromParent();
2251 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2255 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2258 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2259 if (MergedValues[
I] != Unmerge->getReg(
I))
2262 MatchInfo = Unmerge->getSourceReg();
2276 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2277 "Expected an unmerge");
2286 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2287 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2289 if (SrcMergeTy != Dst0Ty && !SameSize)
2293 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2294 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2300 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2301 "Expected an unmerge");
2303 "Not enough operands to replace all defs");
2304 unsigned NumElems =
MI.getNumOperands() - 1;
2306 LLT SrcTy =
MRI.getType(Operands[0]);
2307 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2308 bool CanReuseInputDirectly = DstTy == SrcTy;
2309 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2310 Register DstReg =
MI.getOperand(Idx).getReg();
2315 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2316 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2317 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2318 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2321 if (CanReuseInputDirectly)
2324 Builder.buildCast(DstReg, SrcReg);
2326 MI.eraseFromParent();
2331 unsigned SrcIdx =
MI.getNumOperands() - 1;
2332 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2334 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2335 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2343 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2346 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2348 Val = Val.
lshr(ShiftAmt);
2356 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2357 "Expected an unmerge");
2359 "Not enough operands to replace all defs");
2360 unsigned NumElems =
MI.getNumOperands() - 1;
2362 Register SrcReg =
MI.getOperand(NumElems).getReg();
2364 if (
MRI.getType(SrcReg).isFloat()) {
2367 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2368 Register DstReg =
MI.getOperand(Idx).getReg();
2370 Builder.buildFConstant(DstReg, Val);
2373 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2374 Register DstReg =
MI.getOperand(Idx).getReg();
2375 Builder.buildConstant(DstReg, Csts[Idx]);
2379 MI.eraseFromParent();
2385 unsigned SrcIdx =
MI.getNumOperands() - 1;
2386 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2388 unsigned NumElems =
MI.getNumOperands() - 1;
2389 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2390 Register DstReg =
MI.getOperand(Idx).getReg();
2391 B.buildUndef(DstReg);
2399 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2400 "Expected an unmerge");
2401 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2402 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2405 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2406 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2414 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2415 Register Dst0Reg =
MI.getOperand(0).getReg();
2416 Builder.buildTrunc(Dst0Reg, SrcReg);
2417 MI.eraseFromParent();
2421 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2422 "Expected an unmerge");
2423 Register Dst0Reg =
MI.getOperand(0).getReg();
2424 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2430 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2431 LLT SrcTy =
MRI.getType(SrcReg);
2432 if (SrcTy.isVector())
2442 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2447 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2448 "Expected an unmerge");
2450 Register Dst0Reg =
MI.getOperand(0).getReg();
2453 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2455 "Expecting a G_ZEXT");
2458 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2459 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2462 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2465 "ZExt src doesn't fit in destination");
2470 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2472 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2475 MI.eraseFromParent();
2479 unsigned TargetShiftSize,
2480 unsigned &ShiftVal)
const {
2481 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2482 MI.getOpcode() == TargetOpcode::G_LSHR ||
2483 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2485 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2490 unsigned Size = Ty.getSizeInBits();
2491 if (
Size <= TargetShiftSize)
2499 ShiftVal = MaybeImmVal->Value.getSExtValue();
2500 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2507 LLT Ty =
MRI.getType(SrcReg);
2508 unsigned Size = Ty.getSizeInBits();
2509 unsigned HalfSize =
Size / 2;
2510 assert(ShiftVal >= HalfSize);
2514 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2515 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2517 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2518 Register Narrowed = Unmerge.getReg(1);
2525 if (NarrowShiftAmt != 0) {
2526 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2527 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2530 auto Zero =
Builder.buildConstant(HalfTy, 0);
2531 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2532 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2533 Register Narrowed = Unmerge.getReg(0);
2538 if (NarrowShiftAmt != 0) {
2539 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2540 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2543 auto Zero =
Builder.buildConstant(HalfTy, 0);
2544 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2546 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2548 HalfTy, Unmerge.getReg(1),
2549 Builder.buildConstant(HalfTy, HalfSize - 1));
2551 if (ShiftVal == HalfSize) {
2554 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2555 }
else if (ShiftVal ==
Size - 1) {
2563 HalfTy, Unmerge.getReg(1),
2564 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2572 MI.eraseFromParent();
2588 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2590 LLT DstTy =
MRI.getType(DstReg);
2598 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2600 Builder.buildCopy(DstReg, Reg);
2601 MI.eraseFromParent();
2606 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2608 Builder.buildZExtOrTrunc(DstReg, Reg);
2609 MI.eraseFromParent();
2614 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2617 LLT IntTy =
MRI.getType(LHS);
2621 PtrReg.second =
false;
2622 for (
Register SrcReg : {LHS, RHS}) {
2626 LLT PtrTy =
MRI.getType(PtrReg.first);
2631 PtrReg.second =
true;
2643 const bool DoCommute = PtrReg.second;
2648 LLT PtrTy =
MRI.getType(LHS);
2650 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2651 Builder.buildPtrToInt(Dst, PtrAdd);
2652 MI.eraseFromParent();
2656 APInt &NewCst)
const {
2658 Register LHS = PtrAdd.getBaseReg();
2659 Register RHS = PtrAdd.getOffsetReg();
2665 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2668 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2677 APInt &NewCst)
const {
2681 Builder.buildConstant(Dst, NewCst);
2682 PtrAdd.eraseFromParent();
2687 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2692 SrcReg = OriginalSrcReg;
2693 LLT DstTy =
MRI.getType(DstReg);
2701 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2704 LLT DstTy =
MRI.getType(DstReg);
2709 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2710 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2720 if (ShiftSize > 32 && TruncSize < 32)
2733 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2734 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2738 if (!
MRI.hasOneNonDBGUse(SrcReg))
2741 LLT SrcTy =
MRI.getType(SrcReg);
2742 LLT DstTy =
MRI.getType(DstReg);
2751 case TargetOpcode::G_SHL: {
2760 case TargetOpcode::G_LSHR:
2761 case TargetOpcode::G_ASHR: {
2767 for (
auto &
User :
MRI.use_instructions(DstReg))
2768 if (
User.getOpcode() == TargetOpcode::G_STORE)
2772 if (NewShiftTy == SrcTy)
2786 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2789 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2794 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2796 LLT NewShiftTy = MatchInfo.second;
2799 LLT DstTy =
MRI.getType(Dst);
2803 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2807 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2810 if (NewShiftTy == DstTy)
2813 Builder.buildTrunc(Dst, NewShift);
2820 return MO.isReg() &&
2821 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2827 return !MO.isReg() ||
2828 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2833 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2835 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2839 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2840 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2845 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2846 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2852 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2853 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2854 "Expected an insert/extract element op");
2855 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2860 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2868 unsigned &
OpIdx)
const {
2874 OpIdx = Cst->isZero() ? 3 : 2;
2919 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2946 return MO.isReg() && MO.getReg().isPhysical();
2956 return I1->isIdenticalTo(*I2);
2964 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2971 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2983 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2984 MaybeCst->getSExtValue() ==
C;
2991 std::optional<FPValueAndVReg> MaybeCst;
2995 return MaybeCst->Value.isExactlyValue(
C);
2999 unsigned OpIdx)
const {
3000 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3005 MI.eraseFromParent();
3010 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3014 MI.eraseFromParent();
3018 unsigned ConstIdx)
const {
3019 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3020 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3032 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3033 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3034 "This is not a funnel shift operation");
3036 Register ConstReg =
MI.getOperand(3).getReg();
3037 LLT ConstTy =
MRI.getType(ConstReg);
3038 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3041 assert((VRegAndVal) &&
"Value is not a constant");
3044 APInt NewConst = VRegAndVal->Value.
urem(
3049 MI.getOpcode(), {MI.getOperand(0)},
3050 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3052 MI.eraseFromParent();
3056 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3070 unsigned OpIdx)
const {
3072 return MO.
isReg() &&
3077 unsigned OpIdx)
const {
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();
3104 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3106 MI.eraseFromParent();
3110 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3112 MI.eraseFromParent();
3116 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3119 Register &NewLHS = std::get<0>(MatchInfo);
3120 Register &NewRHS = std::get<1>(MatchInfo);
3128 NewLHS = MaybeNewLHS;
3132 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3137 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3140 LLT DstTy =
MRI.getType(DstReg);
3149 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3150 TargetOpcode::G_INSERT_VECTOR_ELT)
3156 MatchInfo.
resize(NumElts);
3160 if (IntImm >= NumElts || IntImm < 0)
3162 if (!MatchInfo[IntImm])
3163 MatchInfo[IntImm] = TmpReg;
3167 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3169 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3178 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3185 auto GetUndef = [&]() {
3188 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3196 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3197 MI.eraseFromParent();
3201 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3203 std::tie(SubLHS, SubRHS) = MatchInfo;
3204 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3205 MI.eraseFromParent();
3218 unsigned InnerOpc = InnerDef->
getOpcode();
3219 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3242 if (!TryMatch(InnerLHS, InnerRHS) && !TryMatch(InnerRHS, InnerLHS))
3246 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3247 : TargetOpcode::G_ADD;
3250 MatchInfo = [=](MachineIRBuilder &
Builder) {
3251 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3252 auto NewNot =
Builder.buildNot(Ty, NewInner);
3253 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3265 unsigned RootOpc =
MI.getOpcode();
3267 LLT Ty =
MRI.getType(Dst);
3272 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3273 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3284 unsigned LogicOpcode =
MI.getOpcode();
3285 assert(LogicOpcode == TargetOpcode::G_AND ||
3286 LogicOpcode == TargetOpcode::G_OR ||
3287 LogicOpcode == TargetOpcode::G_XOR);
3294 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3300 if (!LeftHandInst || !RightHandInst)
3302 unsigned HandOpcode = LeftHandInst->
getOpcode();
3303 if (HandOpcode != RightHandInst->
getOpcode())
3317 if (!XTy.
isValid() || XTy != YTy)
3322 switch (HandOpcode) {
3325 case TargetOpcode::G_ANYEXT:
3326 case TargetOpcode::G_SEXT:
3327 case TargetOpcode::G_ZEXT: {
3331 case TargetOpcode::G_TRUNC: {
3336 LLT DstTy =
MRI.getType(Dst);
3345 case TargetOpcode::G_AND:
3346 case TargetOpcode::G_ASHR:
3347 case TargetOpcode::G_LSHR:
3348 case TargetOpcode::G_SHL: {
3353 ExtraHandOpSrcReg = ZOp.
getReg();
3364 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3375 if (ExtraHandOpSrcReg.
isValid())
3387 "Expected at least one instr to build?");
3389 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3390 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3392 for (
auto &OperandFn : InstrToBuild.OperandFns)
3395 MI.eraseFromParent();
3399 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3400 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3401 int64_t ShlCst, AshrCst;
3407 if (ShlCst != AshrCst)
3410 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3412 MatchInfo = std::make_tuple(Src, ShlCst);
3417 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3418 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3421 std::tie(Src, ShiftAmt) = MatchInfo;
3422 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3423 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3424 MI.eraseFromParent();
3431 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3434 LLT Ty =
MRI.getType(Dst);
3446 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3449 auto Zero =
B.buildConstant(Ty, 0);
3472 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3496 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3503 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3520 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3538 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3545 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3556 unsigned ExtBits =
MI.getOperand(2).getImm();
3557 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3558 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3562 int64_t Cst,
bool IsVector,
bool IsFP) {
3564 return (ScalarSizeBits == 1 && Cst == -1) ||
3586 unsigned BuildUseCount = BV.getNumSources();
3587 if (BuildUseCount % 2 != 0)
3590 unsigned NumUnmerge = BuildUseCount / 2;
3596 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3599 UnmergeSrc = Unmerge->getSourceReg();
3601 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3602 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3609 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3614 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3615 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3618 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3621 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3626 if (Unmerge->getNumDefs() != NumUnmerge)
3630 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3633 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3644 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3645 B.setInstrAndDebugLoc(
MI);
3647 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3648 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3650 MI.eraseFromParent();
3672 unsigned NumOperands =
BuildMI->getNumSources();
3682 for (
I = 0;
I < NumOperands; ++
I) {
3683 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3684 auto SrcMIOpc = SrcMI->getOpcode();
3687 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3688 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3690 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3691 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3694 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3695 if (UnmergeMI != UnmergeSrcMI)
3710 for (;
I < NumOperands; ++
I) {
3711 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3712 auto SrcMIOpc = SrcMI->getOpcode();
3714 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3720 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3727 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3728 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3736 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3739 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3751 LLT DstTy =
MRI.getType(DstReg);
3752 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3757 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3762 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3766 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3769 Builder.buildTrunc(DstReg, MidReg);
3770 MI.eraseFromParent();
3775 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3776 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3777 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3785 if (!
MRI.hasOneNonDBGUse(XorSrc))
3795 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3797 if (!
MRI.hasOneNonDBGUse(Reg))
3800 switch (Def->getOpcode()) {
3805 case TargetOpcode::G_ICMP:
3811 case TargetOpcode::G_FCMP:
3817 case TargetOpcode::G_AND:
3818 case TargetOpcode::G_OR:
3824 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3825 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3833 if (Ty.isVector()) {
3838 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3852 for (
Register Reg : RegsToNegate) {
3857 switch (Def->getOpcode()) {
3860 case TargetOpcode::G_ICMP:
3861 case TargetOpcode::G_FCMP: {
3868 case TargetOpcode::G_AND:
3869 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3871 case TargetOpcode::G_OR:
3872 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3879 MI.eraseFromParent();
3883 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3885 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3889 Register SharedReg =
MI.getOperand(2).getReg();
3903 if (!
MRI.hasOneNonDBGUse(AndReg))
3910 return Y == SharedReg;
3914 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3917 std::tie(
X,
Y) = MatchInfo;
3920 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3921 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3922 MI.getOperand(2).setReg(
Y);
3928 Register DstReg = PtrAdd.getReg(0);
3929 LLT Ty =
MRI.getType(DstReg);
3932 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3935 if (Ty.isPointer()) {
3937 return ConstVal && *ConstVal == 0;
3940 assert(Ty.isVector() &&
"Expecting a vector type");
3947 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3948 PtrAdd.eraseFromParent();
3955 Register Pow2Src1 =
MI.getOperand(2).getReg();
3956 LLT Ty =
MRI.getType(DstReg);
3959 auto NegOne =
Builder.buildConstant(Ty, -1);
3960 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3962 MI.eraseFromParent();
3966 unsigned &SelectOpNo)
const {
3976 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3977 !
MRI.hasOneNonDBGUse(LHS)) {
3978 OtherOperandReg = LHS;
3981 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3982 !
MRI.hasOneNonDBGUse(RHS))
3998 unsigned BinOpcode =
MI.getOpcode();
4003 bool CanFoldNonConst =
4004 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4009 if (CanFoldNonConst)
4030 LLT Ty =
MRI.getType(Dst);
4031 unsigned BinOpcode =
MI.getOpcode();
4038 if (SelectOperand == 1) {
4042 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4044 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4046 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4048 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4051 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4052 MI.eraseFromParent();
4055std::optional<SmallVector<Register, 8>>
4056CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4057 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4086 const unsigned MaxIter =
4088 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4097 return std::nullopt;
4113 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4114 return std::nullopt;
4126static std::optional<std::pair<GZExtLoad *, int64_t>>
4130 "Expected Reg to only have one non-debug use?");
4139 if (Shift % MemSizeInBits != 0)
4140 return std::nullopt;
4145 return std::nullopt;
4147 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4148 return std::nullopt;
4150 return std::make_pair(Load, Shift / MemSizeInBits);
4153std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4154CombinerHelper::findLoadOffsetsForLoadOrCombine(
4157 const unsigned MemSizeInBits)
const {
4160 SmallSetVector<const MachineInstr *, 8> Loads;
4166 GZExtLoad *LowestIdxLoad =
nullptr;
4169 SmallSet<int64_t, 8> SeenIdx;
4173 MachineBasicBlock *
MBB =
nullptr;
4174 const MachineMemOperand *MMO =
nullptr;
4177 GZExtLoad *EarliestLoad =
nullptr;
4180 GZExtLoad *LatestLoad =
nullptr;
4189 for (
auto Reg : RegsToVisit) {
4194 return std::nullopt;
4197 std::tie(Load, DstPos) = *LoadAndPos;
4201 MachineBasicBlock *LoadMBB =
Load->getParent();
4205 return std::nullopt;
4208 auto &LoadMMO =
Load->getMMO();
4212 return std::nullopt;
4219 LoadPtr =
Load->getOperand(1).getReg();
4224 if (!SeenIdx.
insert(Idx).second)
4225 return std::nullopt;
4232 if (BasePtr != LoadPtr)
4233 return std::nullopt;
4235 if (Idx < LowestIdx) {
4237 LowestIdxLoad =
Load;
4244 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4245 return std::nullopt;
4253 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4254 EarliestLoad =
Load;
4255 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4262 "Expected to find a load for each register?");
4263 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4264 LatestLoad &&
"Expected at least two loads?");
4273 const unsigned MaxIter = 20;
4279 if (
MI.isLoadFoldBarrier())
4280 return std::nullopt;
4281 if (Iter++ == MaxIter)
4282 return std::nullopt;
4285 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4291 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4304 LLT Ty =
MRI.getType(Dst);
4310 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4311 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4315 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4322 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4323 if (NarrowMemSizeInBits % 8 != 0)
4336 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4337 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4340 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4347 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4350 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4362 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4363 const unsigned ZeroByteOffset =
4367 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4368 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4369 ZeroOffsetIdx->second != LowestIdx)
4379 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4393 MIB.setInstrAndDebugLoc(*LatestLoad);
4394 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4395 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4397 MIB.buildBSwap(Dst, LoadDst);
4409 if (
MRI.getType(DstReg).isVector())
4413 if (!
MRI.hasOneNonDBGUse(DstReg))
4415 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4417 case TargetOpcode::G_ANYEXT:
4419 case TargetOpcode::G_ZEXT:
4420 case TargetOpcode::G_SEXT:
4427 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4434 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4436 switch (
DefMI->getOpcode()) {
4437 case TargetOpcode::G_LOAD:
4438 case TargetOpcode::G_TRUNC:
4439 case TargetOpcode::G_SEXT:
4440 case TargetOpcode::G_ZEXT:
4441 case TargetOpcode::G_ANYEXT:
4442 case TargetOpcode::G_CONSTANT:
4446 if (InSrcs.
size() > 2)
4460 LLT ExtTy =
MRI.getType(DstReg);
4467 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4468 auto SrcReg =
PHI.getIncomingValue(
I);
4469 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4470 if (!SrcMIs.
insert(SrcMI))
4474 auto *
MBB = SrcMI->getParent();
4476 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4477 InsertPt =
MBB->getFirstNonPHI();
4479 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4482 OldToNewSrcMap[SrcMI] = NewExt;
4487 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4488 NewPhi.addDef(DstReg);
4491 NewPhi.addMBB(MO.getMBB());
4494 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4495 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4503 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4507 LLT SrcTy =
MRI.getType(SrcVec);
4508 if (SrcTy.isScalableVector())
4512 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4515 unsigned VecIdx = Cst->Value.getZExtValue();
4520 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4524 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4525 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4529 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4541 LLT ScalarTy =
MRI.getType(Reg);
4543 LLT DstTy =
MRI.getType(DstReg);
4545 if (ScalarTy != DstTy) {
4547 Builder.buildTrunc(DstReg, Reg);
4548 MI.eraseFromParent();
4556 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4557 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4575 LLT DstTy =
MRI.getType(DstReg);
4580 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4585 unsigned Idx = Cst->getZExtValue();
4588 ExtractedElts.
set(Idx);
4589 SrcDstPairs.emplace_back(
4590 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4593 return ExtractedElts.
all();
4598 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4599 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4600 for (
auto &Pair : SrcDstPairs) {
4601 auto *ExtMI = Pair.second;
4603 ExtMI->eraseFromParent();
4605 MI.eraseFromParent();
4612 MI.eraseFromParent();
4622 bool AllowScalarConstants,
4624 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4627 LLT Ty =
MRI.getType(Dst);
4628 unsigned BitWidth = Ty.getScalarSizeInBits();
4630 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4631 unsigned FshOpc = 0;
4642 int64_t CstShlAmt = 0, CstLShrAmt;
4645 CstShlAmt + CstLShrAmt ==
BitWidth) {
4646 FshOpc = TargetOpcode::G_FSHR;
4652 FshOpc = TargetOpcode::G_FSHL;
4657 FshOpc = TargetOpcode::G_FSHR;
4662 LLT AmtTy =
MRI.getType(Amt);
4664 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4668 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4675 unsigned Opc =
MI.getOpcode();
4676 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4681 unsigned RotateOpc =
4682 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4687 unsigned Opc =
MI.getOpcode();
4688 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4689 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4691 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4692 : TargetOpcode::G_ROTR));
4693 MI.removeOperand(2);
4699 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4700 MI.getOpcode() == TargetOpcode::G_ROTR);
4702 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4704 bool OutOfRange =
false;
4705 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4707 OutOfRange |= CI->getValue().uge(Bitsize);
4714 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4715 MI.getOpcode() == TargetOpcode::G_ROTR);
4717 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4719 LLT AmtTy =
MRI.getType(Amt);
4720 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4721 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4723 MI.getOperand(2).setReg(Amt);
4728 int64_t &MatchInfo)
const {
4729 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4740 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4741 if (KnownRHS.isUnknown())
4744 std::optional<bool> KnownVal;
4745 if (KnownRHS.isZero()) {
4755 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4765 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4774 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4790 LLT DstTy =
MRI.getType(Dst);
4798 auto KnownLHS =
VT->getKnownBits(LHS);
4799 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4802 LLT LHSTy =
MRI.getType(LHS);
4805 unsigned Op = TargetOpcode::COPY;
4806 if (DstSize != LHSSize)
4807 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4818 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4822 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4828 int64_t AndMaskBits;
4836 if (AndMaskBits & OrMaskBits)
4842 if (
MI.getOperand(1).getReg() == AndMaskReg)
4843 MI.getOperand(2).setReg(AndMaskReg);
4844 MI.getOperand(1).setReg(Src);
4854 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4857 LLT Ty =
MRI.getType(Src);
4859 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4861 int64_t Width =
MI.getOperand(2).getImm();
4869 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4873 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4874 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4875 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4885 LLT Ty =
MRI.getType(Dst);
4889 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4892 int64_t AndImm, LSBImm;
4894 const unsigned Size = Ty.getScalarSizeInBits();
4901 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4902 if (MaybeMask & (MaybeMask + 1))
4911 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4912 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4913 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4921 const unsigned Opcode =
MI.getOpcode();
4922 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4924 const Register Dst =
MI.getOperand(0).getReg();
4926 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4927 ? TargetOpcode::G_SBFX
4928 : TargetOpcode::G_UBFX;
4931 LLT Ty =
MRI.getType(Dst);
4933 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4939 const unsigned Size = Ty.getScalarSizeInBits();
4949 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4953 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4957 const int64_t Pos = ShrAmt - ShlAmt;
4958 const int64_t Width =
Size - ShrAmt;
4961 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4962 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4963 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4971 const unsigned Opcode =
MI.getOpcode();
4972 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4974 const Register Dst =
MI.getOperand(0).getReg();
4975 LLT Ty =
MRI.getType(Dst);
4977 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4990 const unsigned Size = Ty.getScalarSizeInBits();
4991 if (ShrAmt < 0 || ShrAmt >=
Size)
4995 if (0 == (SMask >> ShrAmt)) {
4997 B.buildConstant(Dst, 0);
5003 uint64_t UMask = SMask;
5010 const int64_t Pos = ShrAmt;
5015 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5019 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5020 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5021 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5026bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5030 Register Src1Reg = PtrAdd.getBaseReg();
5035 Register Src2Reg = PtrAdd.getOffsetReg();
5037 if (
MRI.hasOneNonDBGUse(Src1Reg))
5047 const APInt &C1APIntVal = *C1;
5048 const APInt &C2APIntVal = *C2;
5049 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5051 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5054 MachineInstr *ConvUseMI = &
UseMI;
5055 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5056 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5057 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5059 if (!
MRI.hasOneNonDBGUse(DefReg))
5061 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5070 TargetLoweringBase::AddrMode AM;
5073 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5075 PtrAdd.getMF()->getFunction().getContext());
5076 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5077 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5083 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5095 Register Src1Reg =
MI.getOperand(1).getReg();
5096 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5108 unsigned PtrAddFlags =
MI.getFlags();
5109 unsigned AddFlags = RHS->getFlags();
5122 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5125 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5127 MI.getOperand(1).setReg(NewBase.getReg(0));
5128 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5132 return !reassociationCanBreakAddressingModePattern(
MI);
5142 std::optional<ValueAndVReg> LHSCstOff;
5152 unsigned PtrAddFlags =
MI.getFlags();
5153 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5155 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5157 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5171 LHSPtrAdd->moveBefore(&
MI);
5174 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5176 MI.getOperand(2).setReg(NewCst.getReg(0));
5179 Observer.changingInstr(*LHSPtrAdd);
5180 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5181 LHSPtrAdd->setFlags(Flags);
5184 return !reassociationCanBreakAddressingModePattern(
MI);
5195 Register Src2Reg =
MI.getOperand(2).getReg();
5196 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5197 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5210 unsigned PtrAddFlags =
MI.getFlags();
5211 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5224 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5226 MI.getOperand(1).setReg(LHSSrc1);
5227 MI.getOperand(2).setReg(NewCst.getReg(0));
5231 return !reassociationCanBreakAddressingModePattern(
MI);
5269 LLT OpRHSTy =
MRI.getType(OpRHS);
5288 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5289 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5297 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5298 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5311 unsigned Opc =
MI.getOpcode();
5324 APInt &MatchInfo)
const {
5325 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5329 MatchInfo = *MaybeCst;
5337 APInt &MatchInfo)
const {
5343 MatchInfo = *MaybeCst;
5355 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5361 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5362 MI.getOpcode() == TargetOpcode::G_FMAD);
5363 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5380 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5403 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5407 LLT WideTy =
MRI.getType(Dst);
5411 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5427 case TargetOpcode::G_ADD:
5428 case TargetOpcode::G_SUB:
5429 case TargetOpcode::G_MUL:
5430 case TargetOpcode::G_AND:
5431 case TargetOpcode::G_OR:
5432 case TargetOpcode::G_XOR:
5440 auto Mask = Cst->Value;
5445 unsigned NarrowWidth = Mask.countr_one();
5451 auto &MF = *
MI.getMF();
5454 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5455 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5463 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5464 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5466 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5467 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5469 MI.getOperand(1).setReg(Ext.getReg(0));
5477 unsigned Opc =
MI.getOpcode();
5478 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5485 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5486 : TargetOpcode::G_SADDO;
5487 MI.setDesc(
Builder.getTII().get(NewOpc));
5488 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5497 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5498 MI.getOpcode() == TargetOpcode::G_SMULO);
5507 B.buildConstant(Dst, 0);
5508 B.buildConstant(Carry, 0);
5517 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5518 MI.getOpcode() == TargetOpcode::G_SADDE ||
5519 MI.getOpcode() == TargetOpcode::G_USUBE ||
5520 MI.getOpcode() == TargetOpcode::G_SSUBE);
5525 switch (
MI.getOpcode()) {
5526 case TargetOpcode::G_UADDE:
5527 NewOpcode = TargetOpcode::G_UADDO;
5529 case TargetOpcode::G_SADDE:
5530 NewOpcode = TargetOpcode::G_SADDO;
5532 case TargetOpcode::G_USUBE:
5533 NewOpcode = TargetOpcode::G_USUBO;
5535 case TargetOpcode::G_SSUBE:
5536 NewOpcode = TargetOpcode::G_SSUBO;
5540 MI.setDesc(
B.getTII().get(NewOpcode));
5541 MI.removeOperand(4);
5549 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5582 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5583 B.buildSub(Dst, Zero, ReplaceReg);
5592 unsigned Opcode =
MI.getOpcode();
5593 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5595 Register Dst = UDivorRem.getReg(0);
5596 Register LHS = UDivorRem.getReg(1);
5597 Register RHS = UDivorRem.getReg(2);
5598 LLT Ty =
MRI.getType(Dst);
5606 bool UseSRL =
false;
5611 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5613 if (IsSplat && !Factors.
empty()) {
5620 APInt Divisor = CI->getValue();
5629 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5630 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5640 if (Ty.isVector()) {
5641 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5642 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5645 Factor = Factors[0];
5653 return MIB.buildMul(Ty, Res, Factor);
5656 unsigned KnownLeadingZeros =
5657 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5659 bool UseNPQ =
false;
5661 auto BuildUDIVPattern = [&](
const Constant *
C) {
5663 const APInt &Divisor = CI->getValue();
5665 bool SelNPQ =
false;
5667 unsigned PreShift = 0, PostShift = 0;
5672 if (!Divisor.
isOne()) {
5678 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5680 Magic = std::move(magics.
Magic);
5683 "We shouldn't generate an undefined shift!");
5685 "We shouldn't generate an undefined shift!");
5689 SelNPQ = magics.
IsAdd;
5693 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5694 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5696 MIB.buildConstant(ScalarTy,
5701 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5709 assert(Matched &&
"Expected unary predicate match to succeed");
5711 Register PreShift, PostShift, MagicFactor, NPQFactor;
5714 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5715 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5716 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5717 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5720 "Non-build_vector operation should have been a scalar");
5721 PreShift = PreShifts[0];
5722 MagicFactor = MagicFactors[0];
5723 PostShift = PostShifts[0];
5727 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5730 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5733 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5738 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5740 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5742 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5745 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5746 auto One = MIB.buildConstant(Ty, 1);
5747 auto IsOne = MIB.buildICmp(
5749 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5750 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5752 if (Opcode == TargetOpcode::G_UREM) {
5753 auto Prod = MIB.buildMul(Ty, ret, RHS);
5754 return MIB.buildSub(Ty, LHS, Prod);
5760 unsigned Opcode =
MI.getOpcode();
5761 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5764 LLT DstTy =
MRI.getType(Dst);
5766 auto &MF = *
MI.getMF();
5767 AttributeList Attr = MF.getFunction().getAttributes();
5776 if (MF.getFunction().hasMinSize())
5779 if (Opcode == TargetOpcode::G_UDIV &&
5782 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5785 auto *RHSDef =
MRI.getVRegDef(RHS);
5796 {TargetOpcode::G_ICMP,
5800 if (Opcode == TargetOpcode::G_UREM &&
5806 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5815 unsigned Opcode =
MI.getOpcode();
5816 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5819 LLT DstTy =
MRI.getType(Dst);
5823 auto &MF = *
MI.getMF();
5824 AttributeList Attr = MF.getFunction().getAttributes();
5833 if (MF.getFunction().hasMinSize())
5837 if (Opcode == TargetOpcode::G_SDIV &&
5840 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5843 auto *RHSDef =
MRI.getVRegDef(RHS);
5851 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5854 if (Opcode == TargetOpcode::G_SREM &&
5860 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5869 unsigned Opcode =
MI.getOpcode();
5870 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5871 Opcode == TargetOpcode::G_SREM);
5873 Register Dst = SDivorRem.getReg(0);
5874 Register LHS = SDivorRem.getReg(1);
5875 Register RHS = SDivorRem.getReg(2);
5876 LLT Ty =
MRI.getType(Dst);
5883 bool UseSRA =
false;
5889 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5891 if (IsSplat && !ExactFactors.
empty()) {
5893 ExactFactors.
push_back(ExactFactors[0]);
5898 APInt Divisor = CI->getValue();
5908 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5909 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5917 assert(Matched &&
"Expected unary predicate match to succeed");
5920 if (Ty.isVector()) {
5921 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5922 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5924 Shift = ExactShifts[0];
5925 Factor = ExactFactors[0];
5933 return MIB.buildMul(Ty, Res, Factor);
5938 auto BuildSDIVPattern = [&](
const Constant *
C) {
5940 const APInt &Divisor = CI->getValue();
5944 int NumeratorFactor = 0;
5955 NumeratorFactor = 1;
5958 NumeratorFactor = -1;
5961 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5962 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5964 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5965 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5973 assert(Matched &&
"Expected unary predicate match to succeed");
5975 Register MagicFactor, Factor, Shift, ShiftMask;
5978 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5979 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5980 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5981 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5984 "Non-build_vector operation should have been a scalar");
5985 MagicFactor = MagicFactors[0];
5986 Factor = Factors[0];
5988 ShiftMask = ShiftMasks[0];
5992 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5995 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5996 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5999 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6002 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6003 auto T = MIB.buildLShr(Ty, Q, SignShift);
6004 T = MIB.buildAnd(Ty,
T, ShiftMask);
6005 auto ret = MIB.buildAdd(Ty, Q,
T);
6007 if (Opcode == TargetOpcode::G_SREM) {
6008 auto Prod = MIB.buildMul(Ty, ret, RHS);
6009 return MIB.buildSub(Ty, LHS, Prod);
6015 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6016 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6017 "Expected SDIV or UDIV");
6020 auto MatchPow2 = [&](
const Constant *
C) {
6022 return CI && (CI->getValue().isPowerOf2() ||
6023 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6029 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6034 LLT Ty =
MRI.getType(Dst);
6054 unsigned BitWidth = Ty.getScalarSizeInBits();
6055 auto Zero =
Builder.buildConstant(Ty, 0);
6058 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6059 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6061 auto Sign =
Builder.buildAShr(
6065 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6071 auto One =
Builder.buildConstant(Ty, 1);
6072 auto MinusOne =
Builder.buildConstant(Ty, -1);
6076 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6077 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6081 auto Neg =
Builder.buildNeg(Ty, AShr);
6083 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6084 MI.eraseFromParent();
6088 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6093 LLT Ty =
MRI.getType(Dst);
6096 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6097 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6098 MI.eraseFromParent();
6102 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6105 LLT Ty =
MRI.getType(Dst);
6106 LLT RHSTy =
MRI.getType(RHS);
6108 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6110 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6125 LLT Ty =
MRI.getType(Dst);
6131 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6132 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6133 Builder.buildLShr(Dst, LHS, Trunc);
6134 MI.eraseFromParent();
6141 LLT DstTy =
MRI.getType(Dst);
6142 LLT SrcTy =
MRI.getType(Src);
6144 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6145 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6148 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6166 Builder.buildTruncSSatS(Dst, MatchInfo);
6167 MI.eraseFromParent();
6174 LLT DstTy =
MRI.getType(Dst);
6175 LLT SrcTy =
MRI.getType(Src);
6177 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6178 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6181 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6199 Builder.buildTruncSSatU(Dst, MatchInfo);
6200 MI.eraseFromParent();
6207 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6208 LLT SrcTy =
MRI.getType(Val);
6210 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6211 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6214 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6223 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6232 unsigned Opc =
MI.getOpcode();
6233 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6234 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6235 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6247 Opc = TargetOpcode::G_FSUB;
6252 Opc = TargetOpcode::G_FADD;
6258 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6259 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6268 MI.setDesc(
B.getTII().get(
Opc));
6269 MI.getOperand(1).setReg(
X);
6270 MI.getOperand(2).setReg(
Y);
6278 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6281 MatchInfo =
MI.getOperand(2).getReg();
6282 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6284 const auto LHSCst = Ty.isVector()
6291 if (LHSCst->Value.isNegZero())
6295 if (LHSCst->Value.isPosZero())
6305 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6312 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6326 bool &AllowFusionGlobally,
6328 bool CanReassociate)
const {
6330 auto *MF =
MI.getMF();
6331 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6333 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6341 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6344 if (!HasFMAD && !HasFMA)
6352 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6359 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6361 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6369 unsigned PreferredFusedOpcode =
6370 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6384 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6385 {LHS.MI->getOperand(1).getReg(),
6386 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6395 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6396 {RHS.MI->getOperand(1).getReg(),
6397 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6408 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6410 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6414 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6419 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6421 unsigned PreferredFusedOpcode =
6422 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6436 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6441 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6442 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6451 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6456 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6457 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6468 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6470 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6478 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6480 unsigned PreferredFusedOpcode =
6481 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6494 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6495 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6496 TargetOpcode::G_FMUL) &&
6497 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6498 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6503 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6504 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6505 TargetOpcode::G_FMUL) &&
6506 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6507 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6514 Register X = FMA->getOperand(1).getReg();
6515 Register Y = FMA->getOperand(2).getReg();
6520 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6521 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6522 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6534 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6536 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6543 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6544 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6550 unsigned PreferredFusedOpcode =
6551 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6564 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6565 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6567 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6569 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6576 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6580 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6585 LHS.MI->getOperand(1).getReg(),
6586 LHS.MI->getOperand(2).getReg(),
B);
6597 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6600 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6605 X =
B.buildFPExt(DstType,
X).getReg(0);
6606 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6617 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6621 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6626 RHS.MI->getOperand(1).getReg(),
6627 RHS.MI->getOperand(2).getReg(),
B);
6638 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6641 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6646 X =
B.buildFPExt(DstType,
X).getReg(0);
6647 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6661 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6663 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6671 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6675 int FirstMulHasFewerUses =
true;
6679 FirstMulHasFewerUses =
false;
6681 unsigned PreferredFusedOpcode =
6682 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6685 if (FirstMulHasFewerUses &&
6689 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6690 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6691 {LHS.MI->getOperand(1).getReg(),
6692 LHS.MI->getOperand(2).getReg(), NegZ});
6701 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6702 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6703 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6714 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6716 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6722 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6724 unsigned PreferredFusedOpcode =
6725 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6736 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6737 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6749 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6762 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6764 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6770 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6772 unsigned PreferredFusedOpcode =
6773 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6785 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6786 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6787 {FpExtX, FpExtY, NegZ});
6799 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6802 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6803 {NegY, FpExtZ, LHSReg});
6814 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6816 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6820 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6821 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6825 unsigned PreferredFusedOpcode =
6826 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6830 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6831 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6832 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6843 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6846 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6849 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6859 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6872 unsigned &IdxToPropagate)
const {
6874 switch (
MI.getOpcode()) {
6877 case TargetOpcode::G_FMINNUM:
6878 case TargetOpcode::G_FMAXNUM:
6879 PropagateNaN =
false;
6881 case TargetOpcode::G_FMINIMUM:
6882 case TargetOpcode::G_FMAXIMUM:
6883 PropagateNaN =
true;
6887 auto MatchNaN = [&](
unsigned Idx) {
6888 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6892 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6896 return MatchNaN(1) || MatchNaN(2);
6904 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6914 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6927 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6928 if (&U == &
MI || U.getParent() !=
MI.getParent())
6930 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6931 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6944 return MatchInfo.
size() >= MinUses;
6952 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6953 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6954 MatchInfo[0]->getOperand(2).getReg(),
6955 MatchInfo[0]->getFlags());
6960 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6961 Div->getOperand(0).getReg(),
MI->getFlags());
6962 MI->eraseFromParent();
6967 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6977 Reg == MaybeSameReg;
6979 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7000 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7009 return MRI.getType(MatchInfo) == DstVecTy;
7012 std::optional<ValueAndVReg> ShiftAmount;
7021 return MRI.getType(MatchInfo) == DstVecTy;
7036 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7043 std::optional<ValueAndVReg> ShiftAmt;
7049 LLT MatchTy =
MRI.getType(MatchInfo);
7050 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
7051 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7054unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7056 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7057 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7058 "Expected a NaN behaviour?");
7068 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7069 return TargetOpcode::G_FMAXNUM;
7070 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7071 return TargetOpcode::G_FMAXIMUM;
7072 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7073 return TargetOpcode::G_FMAXNUM;
7074 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7075 return TargetOpcode::G_FMAXIMUM;
7081 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7082 return TargetOpcode::G_FMINNUM;
7083 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7084 return TargetOpcode::G_FMINIMUM;
7085 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7086 return TargetOpcode::G_FMINNUM;
7087 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7089 return TargetOpcode::G_FMINIMUM;
7093CombinerHelper::SelectPatternNaNBehaviour
7095 bool IsOrderedComparison)
const {
7099 if (!LHSSafe && !RHSSafe)
7100 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7101 if (LHSSafe && RHSSafe)
7102 return SelectPatternNaNBehaviour::RETURNS_ANY;
7105 if (IsOrderedComparison)
7106 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7107 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7110 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7111 : SelectPatternNaNBehaviour::RETURNS_NAN;
7120 LLT DstTy =
MRI.getType(Dst);
7133 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7135 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7137 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7140 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7141 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7142 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7143 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7145 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7148 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7153 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7158 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7160 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7164 MatchInfo = [=](MachineIRBuilder &
B) {
7165 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7173 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7180 Register TrueVal =
MI.getOperand(2).getReg();
7181 Register FalseVal =
MI.getOperand(3).getReg();
7182 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7187 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7200 if (MatchedSub &&
X != OpLHS)
7208 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7211 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7212 B.buildICmp(Pred, Dst,
Y, Zero);
7219static std::optional<unsigned>
7221 std::optional<int64_t> &Result) {
7222 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7223 Opcode == TargetOpcode::G_ASHR) &&
7224 "Expect G_SHL, G_LSHR or G_ASHR.");
7225 auto SignificantBits = 0;
7227 case TargetOpcode::G_SHL:
7231 case TargetOpcode::G_LSHR:
7235 case TargetOpcode::G_ASHR:
7244 Result = std::nullopt;
7255 Register ShiftVal =
MI.getOperand(1).getReg();
7256 Register ShiftReg =
MI.getOperand(2).getReg();
7257 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7258 auto IsShiftTooBig = [&](
const Constant *
C) {
7263 MatchInfo = std::nullopt;
7267 MI.getOpcode(), MatchInfo);
7268 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7274 unsigned LHSOpndIdx = 1;
7275 unsigned RHSOpndIdx = 2;
7276 switch (
MI.getOpcode()) {
7277 case TargetOpcode::G_UADDO:
7278 case TargetOpcode::G_SADDO:
7279 case TargetOpcode::G_UMULO:
7280 case TargetOpcode::G_SMULO:
7287 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7288 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7293 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7294 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7298 return MRI.getVRegDef(RHS)->getOpcode() !=
7299 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7306 std::optional<FPValueAndVReg> ValAndVReg;
7314 unsigned LHSOpndIdx = 1;
7315 unsigned RHSOpndIdx = 2;
7316 switch (
MI.getOpcode()) {
7317 case TargetOpcode::G_UADDO:
7318 case TargetOpcode::G_SADDO:
7319 case TargetOpcode::G_UMULO:
7320 case TargetOpcode::G_SMULO:
7327 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7328 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7329 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7330 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7334bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7336 if (SrcTy.isFixedVector())
7337 return isConstantSplatVector(Src, 1, AllowUndefs);
7338 if (SrcTy.isScalar()) {
7342 return IConstant && IConstant->Value == 1;
7347bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7348 LLT SrcTy =
MRI.getType(Src);
7350 return isConstantSplatVector(Src, 0, AllowUndefs);
7355 return IConstant && IConstant->Value == 0;
7362bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7363 bool AllowUndefs)
const {
7369 for (
unsigned I = 0;
I < NumSources; ++
I) {
7370 GImplicitDef *ImplicitDef =
7372 if (ImplicitDef && AllowUndefs)
7374 if (ImplicitDef && !AllowUndefs)
7376 std::optional<ValueAndVReg> IConstant =
7378 if (IConstant && IConstant->Value == SplatValue)
7388CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7391 return IConstant->Value;
7395 return std::nullopt;
7398 std::optional<APInt>
Value = std::nullopt;
7399 for (
unsigned I = 0;
I < NumSources; ++
I) {
7400 std::optional<ValueAndVReg> IConstant =
7403 return std::nullopt;
7405 Value = IConstant->Value;
7406 else if (*
Value != IConstant->Value)
7407 return std::nullopt;
7413bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7423 for (
unsigned I = 0;
I < NumSources; ++
I) {
7424 std::optional<ValueAndVReg> IConstant =
7433bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7440 LLT CondTy =
MRI.getType(
Select->getCondReg());
7441 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7451 std::optional<ValueAndVReg> TrueOpt =
7453 std::optional<ValueAndVReg> FalseOpt =
7456 if (!TrueOpt || !FalseOpt)
7459 APInt TrueValue = TrueOpt->Value;
7460 APInt FalseValue = FalseOpt->Value;
7464 MatchInfo = [=](MachineIRBuilder &
B) {
7465 B.setInstrAndDebugLoc(*
Select);
7466 B.buildZExtOrTrunc(Dest,
Cond);
7473 MatchInfo = [=](MachineIRBuilder &
B) {
7474 B.setInstrAndDebugLoc(*
Select);
7475 B.buildSExtOrTrunc(Dest,
Cond);
7482 MatchInfo = [=](MachineIRBuilder &
B) {
7483 B.setInstrAndDebugLoc(*
Select);
7484 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7485 B.buildNot(Inner,
Cond);
7486 B.buildZExtOrTrunc(Dest, Inner);
7493 MatchInfo = [=](MachineIRBuilder &
B) {
7494 B.setInstrAndDebugLoc(*
Select);
7495 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7496 B.buildNot(Inner,
Cond);
7497 B.buildSExtOrTrunc(Dest, Inner);
7503 if (TrueValue - 1 == FalseValue) {
7504 MatchInfo = [=](MachineIRBuilder &
B) {
7505 B.setInstrAndDebugLoc(*
Select);
7506 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7507 B.buildZExtOrTrunc(Inner,
Cond);
7508 B.buildAdd(Dest, Inner, False);
7514 if (TrueValue + 1 == FalseValue) {
7515 MatchInfo = [=](MachineIRBuilder &
B) {
7516 B.setInstrAndDebugLoc(*
Select);
7517 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7518 B.buildSExtOrTrunc(Inner,
Cond);
7519 B.buildAdd(Dest, Inner, False);
7526 MatchInfo = [=](MachineIRBuilder &
B) {
7527 B.setInstrAndDebugLoc(*
Select);
7528 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7529 B.buildZExtOrTrunc(Inner,
Cond);
7532 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7533 B.buildShl(Dest, Inner, ShAmtC, Flags);
7540 MatchInfo = [=](MachineIRBuilder &
B) {
7541 B.setInstrAndDebugLoc(*
Select);
7543 B.buildNot(Not,
Cond);
7544 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7545 B.buildZExtOrTrunc(Inner, Not);
7548 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7549 B.buildShl(Dest, Inner, ShAmtC, Flags);
7556 MatchInfo = [=](MachineIRBuilder &
B) {
7557 B.setInstrAndDebugLoc(*
Select);
7558 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7559 B.buildSExtOrTrunc(Inner,
Cond);
7560 B.buildOr(Dest, Inner, False, Flags);
7567 MatchInfo = [=](MachineIRBuilder &
B) {
7568 B.setInstrAndDebugLoc(*
Select);
7570 B.buildNot(Not,
Cond);
7571 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7572 B.buildSExtOrTrunc(Inner, Not);
7573 B.buildOr(Dest, Inner, True, Flags);
7582bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7589 LLT CondTy =
MRI.getType(
Select->getCondReg());
7590 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7599 if (CondTy != TrueTy)
7604 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7605 MatchInfo = [=](MachineIRBuilder &
B) {
7606 B.setInstrAndDebugLoc(*
Select);
7607 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7608 B.buildZExtOrTrunc(Ext,
Cond);
7609 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7610 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7617 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7618 MatchInfo = [=](MachineIRBuilder &
B) {
7619 B.setInstrAndDebugLoc(*
Select);
7620 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7621 B.buildZExtOrTrunc(Ext,
Cond);
7622 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7623 B.buildAnd(DstReg, Ext, FreezeTrue);
7629 if (isOneOrOneSplat(False,
true)) {
7630 MatchInfo = [=](MachineIRBuilder &
B) {
7631 B.setInstrAndDebugLoc(*
Select);
7633 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7634 B.buildNot(Inner,
Cond);
7636 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7637 B.buildZExtOrTrunc(Ext, Inner);
7638 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7639 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7645 if (isZeroOrZeroSplat(True,
true)) {
7646 MatchInfo = [=](MachineIRBuilder &
B) {
7647 B.setInstrAndDebugLoc(*
Select);
7649 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7650 B.buildNot(Inner,
Cond);
7652 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7653 B.buildZExtOrTrunc(Ext, Inner);
7654 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7655 B.buildAnd(DstReg, Ext, FreezeFalse);
7671 LLT DstTy =
MRI.getType(DstReg);
7677 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7686 Register CmpLHS = Cmp->getLHSReg();
7687 Register CmpRHS = Cmp->getRHSReg();
7690 if (True == CmpRHS && False == CmpLHS) {
7698 if (True != CmpLHS || False != CmpRHS)
7738 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7739 Register DestReg =
MI.getOperand(0).getReg();
7740 LLT DestTy =
MRI.getType(DestReg);
7752 if (
isLegal({NewOpc, {DestTy}})) {
7754 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7766 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7769 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7779bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7781 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7782 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7786 unsigned Flags = Logic->
getFlags();
7805 std::optional<ValueAndVReg> MaybeC1 =
7809 C1 = MaybeC1->Value;
7811 std::optional<ValueAndVReg> MaybeC2 =
7815 C2 = MaybeC2->Value;
7836 std::optional<APInt> Offset1;
7837 std::optional<APInt> Offset2;
7840 std::optional<ValueAndVReg> MaybeOffset1 =
7843 R1 =
Add->getLHSReg();
7844 Offset1 = MaybeOffset1->Value;
7848 std::optional<ValueAndVReg> MaybeOffset2 =
7851 R2 =
Add->getLHSReg();
7852 Offset2 = MaybeOffset2->Value;
7871 bool CreateMask =
false;
7884 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7897 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7906 MatchInfo = [=](MachineIRBuilder &
B) {
7907 if (CreateMask &&
Offset != 0) {
7908 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7909 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7910 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7911 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7912 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7913 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7914 B.buildZExtOrTrunc(DstReg, ICmp);
7915 }
else if (CreateMask &&
Offset == 0) {
7916 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7917 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7918 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7919 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7920 B.buildZExtOrTrunc(DstReg, ICmp);
7921 }
else if (!CreateMask &&
Offset != 0) {
7922 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7923 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7924 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7925 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7926 B.buildZExtOrTrunc(DstReg, ICmp);
7927 }
else if (!CreateMask &&
Offset == 0) {
7928 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7929 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7930 B.buildZExtOrTrunc(DstReg, ICmp);
7938bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7944 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7956 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7962 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7963 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7964 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7965 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7976 if (LHS0 == RHS1 && LHS1 == RHS0) {
7982 if (LHS0 == RHS0 && LHS1 == RHS1) {
7986 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7988 MatchInfo = [=](MachineIRBuilder &
B) {
7993 auto False =
B.buildConstant(CmpTy, 0);
7994 B.buildZExtOrTrunc(DestReg, False);
8001 B.buildZExtOrTrunc(DestReg, True);
8003 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8004 B.buildZExtOrTrunc(DestReg, Cmp);
8016 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8019 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8028 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8031 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8046 bool IsSigned =
Add->isSigned();
8047 LLT DstTy =
MRI.getType(Dst);
8048 LLT CarryTy =
MRI.getType(Carry);
8051 if (
MRI.use_nodbg_empty(Carry) &&
8054 B.buildAdd(Dst, LHS, RHS);
8055 B.buildUndef(Carry);
8061 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8064 B.buildSAddo(Dst, Carry, RHS, LHS);
8070 B.buildUAddo(Dst, Carry, RHS, LHS);
8075 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8076 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8082 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8083 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8085 B.buildConstant(Dst, Result);
8086 B.buildConstant(Carry, Overflow);
8094 B.buildCopy(Dst, LHS);
8095 B.buildConstant(Carry, 0);
8104 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8107 std::optional<APInt> MaybeAddRHS =
8108 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8111 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8112 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8116 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8117 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8123 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8124 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8149 B.buildConstant(Carry, 0);
8156 B.buildAdd(Dst, LHS, RHS);
8157 B.buildConstant(Carry, 1);
8169 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8172 B.buildConstant(Carry, 0);
8188 B.buildConstant(Carry, 0);
8195 B.buildAdd(Dst, LHS, RHS);
8196 B.buildConstant(Carry, 1);
8214 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8220 auto [Dst,
Base] =
MI.getFirst2Regs();
8221 LLT Ty =
MRI.getType(Dst);
8225 Builder.buildFConstant(Dst, 1.0);
8226 MI.removeFromParent();
8238 std::optional<SrcOp> Res;
8240 while (ExpVal > 0) {
8245 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8248 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8255 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8259 MI.eraseFromParent();
8268 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8275 LLT DstTy =
MRI.getType(Dst);
8278 auto Const =
B.buildConstant(DstTy, C1 - C2);
8279 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8291 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8298 LLT DstTy =
MRI.getType(Dst);
8301 auto Const =
B.buildConstant(DstTy, C2 - C1);
8302 B.buildSub(Dst, Const,
Add->getLHSReg());
8314 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8321 LLT DstTy =
MRI.getType(Dst);
8324 auto Const =
B.buildConstant(DstTy, C1 + C2);
8337 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8344 LLT DstTy =
MRI.getType(Dst);
8347 auto Const =
B.buildConstant(DstTy, C1 - C2);
8360 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8367 LLT DstTy =
MRI.getType(Dst);
8370 auto Const =
B.buildConstant(DstTy, C2 - C1);
8371 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8418 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8422 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8425 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8426 LLT SmallBvTy = DstTy;
8430 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8435 {TargetOpcode::G_ANYEXT,
8447 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8448 Ops.push_back(AnyExt.getReg(0));
8466 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8467 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8468 const unsigned NumDstElts = OrigMask.
size();
8469 for (
unsigned i = 0; i != NumDstElts; ++i) {
8470 int Idx = OrigMask[i];
8471 if (Idx >= (
int)NumSrcElems) {
8482 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8483 std::move(NewMask));
8490 const unsigned MaskSize = Mask.size();
8491 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8496 if (Idx < (
int)NumElems)
8497 Mask[
I] = Idx + NumElems;
8499 Mask[
I] = Idx - NumElems;
8509 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8512 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8515 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8516 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8518 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8522 const unsigned NumSrcElems = Src1Ty.getNumElements();
8524 bool TouchesSrc1 =
false;
8525 bool TouchesSrc2 =
false;
8526 const unsigned NumElems = Mask.size();
8527 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8531 if (Mask[Idx] < (
int)NumSrcElems)
8537 if (TouchesSrc1 == TouchesSrc2)
8540 Register NewSrc1 = Shuffle.getSrc1Reg();
8543 NewSrc1 = Shuffle.getSrc2Reg();
8548 auto Undef =
B.buildUndef(Src1Ty);
8549 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8563 LLT DstTy =
MRI.getType(Dst);
8564 LLT CarryTy =
MRI.getType(Carry);
8586 B.buildConstant(Carry, 0);
8593 B.buildSub(Dst, LHS, RHS);
8611 B.buildConstant(Carry, 0);
8618 B.buildSub(Dst, LHS, RHS);
8635 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8636 "Expected G_CTLZ variant");
8641 LLT Ty =
MRI.getType(Dst);
8642 LLT SrcTy =
MRI.getType(Src);
8644 if (!(Ty.isValid() && Ty.isScalar()))
8653 switch (
LI->getAction(Query).Action) {
8664 bool NeedAdd =
true;
8672 unsigned BitWidth = Ty.getScalarSizeInBits();
8683 B.buildCTLS(Dst,
X);
8687 auto Ctls =
B.buildCTLS(Ty,
X);
8688 auto One =
B.buildConstant(Ty, 1);
8690 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...
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 convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM)
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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - 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
}
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 matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is known to be a power of 2.
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.
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 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
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
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
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.
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()
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
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)
static constexpr roundingMode rmTowardZero
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 bool isKnownNeverNaN(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if the floating-point scalar value is not a NaN or if the floating-point vector value has...
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 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...