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;
2361 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2362 Register DstReg =
MI.getOperand(Idx).getReg();
2363 Builder.buildConstant(DstReg, Csts[Idx]);
2366 MI.eraseFromParent();
2372 unsigned SrcIdx =
MI.getNumOperands() - 1;
2373 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2375 unsigned NumElems =
MI.getNumOperands() - 1;
2376 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2377 Register DstReg =
MI.getOperand(Idx).getReg();
2378 B.buildUndef(DstReg);
2386 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2387 "Expected an unmerge");
2388 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2389 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2392 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2393 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2401 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2402 Register Dst0Reg =
MI.getOperand(0).getReg();
2403 Builder.buildTrunc(Dst0Reg, SrcReg);
2404 MI.eraseFromParent();
2408 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2409 "Expected an unmerge");
2410 Register Dst0Reg =
MI.getOperand(0).getReg();
2411 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2417 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2418 LLT SrcTy =
MRI.getType(SrcReg);
2419 if (SrcTy.isVector())
2429 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2434 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2435 "Expected an unmerge");
2437 Register Dst0Reg =
MI.getOperand(0).getReg();
2440 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2442 "Expecting a G_ZEXT");
2445 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2446 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2449 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2452 "ZExt src doesn't fit in destination");
2457 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2459 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2462 MI.eraseFromParent();
2466 unsigned TargetShiftSize,
2467 unsigned &ShiftVal)
const {
2468 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2469 MI.getOpcode() == TargetOpcode::G_LSHR ||
2470 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2472 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2477 unsigned Size = Ty.getSizeInBits();
2478 if (
Size <= TargetShiftSize)
2486 ShiftVal = MaybeImmVal->Value.getSExtValue();
2487 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2494 LLT Ty =
MRI.getType(SrcReg);
2495 unsigned Size = Ty.getSizeInBits();
2496 unsigned HalfSize =
Size / 2;
2497 assert(ShiftVal >= HalfSize);
2501 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2502 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2504 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2505 Register Narrowed = Unmerge.getReg(1);
2512 if (NarrowShiftAmt != 0) {
2513 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2514 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2517 auto Zero =
Builder.buildConstant(HalfTy, 0);
2518 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2519 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2520 Register Narrowed = Unmerge.getReg(0);
2525 if (NarrowShiftAmt != 0) {
2526 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2527 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2530 auto Zero =
Builder.buildConstant(HalfTy, 0);
2531 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2533 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2535 HalfTy, Unmerge.getReg(1),
2536 Builder.buildConstant(HalfTy, HalfSize - 1));
2538 if (ShiftVal == HalfSize) {
2541 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2542 }
else if (ShiftVal ==
Size - 1) {
2550 HalfTy, Unmerge.getReg(1),
2551 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2559 MI.eraseFromParent();
2575 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2577 LLT DstTy =
MRI.getType(DstReg);
2585 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2587 Builder.buildCopy(DstReg, Reg);
2588 MI.eraseFromParent();
2593 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2595 Builder.buildZExtOrTrunc(DstReg, Reg);
2596 MI.eraseFromParent();
2601 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2604 LLT IntTy =
MRI.getType(LHS);
2608 PtrReg.second =
false;
2609 for (
Register SrcReg : {LHS, RHS}) {
2613 LLT PtrTy =
MRI.getType(PtrReg.first);
2618 PtrReg.second =
true;
2630 const bool DoCommute = PtrReg.second;
2635 LLT PtrTy =
MRI.getType(LHS);
2637 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2638 Builder.buildPtrToInt(Dst, PtrAdd);
2639 MI.eraseFromParent();
2643 APInt &NewCst)
const {
2645 Register LHS = PtrAdd.getBaseReg();
2646 Register RHS = PtrAdd.getOffsetReg();
2652 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2655 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2664 APInt &NewCst)
const {
2668 Builder.buildConstant(Dst, NewCst);
2669 PtrAdd.eraseFromParent();
2674 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2679 SrcReg = OriginalSrcReg;
2680 LLT DstTy =
MRI.getType(DstReg);
2688 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2691 LLT DstTy =
MRI.getType(DstReg);
2696 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2697 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2707 if (ShiftSize > 32 && TruncSize < 32)
2720 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2721 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2725 if (!
MRI.hasOneNonDBGUse(SrcReg))
2728 LLT SrcTy =
MRI.getType(SrcReg);
2729 LLT DstTy =
MRI.getType(DstReg);
2738 case TargetOpcode::G_SHL: {
2747 case TargetOpcode::G_LSHR:
2748 case TargetOpcode::G_ASHR: {
2754 for (
auto &
User :
MRI.use_instructions(DstReg))
2755 if (
User.getOpcode() == TargetOpcode::G_STORE)
2759 if (NewShiftTy == SrcTy)
2773 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2776 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2781 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2783 LLT NewShiftTy = MatchInfo.second;
2786 LLT DstTy =
MRI.getType(Dst);
2790 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2794 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2797 if (NewShiftTy == DstTy)
2800 Builder.buildTrunc(Dst, NewShift);
2807 return MO.isReg() &&
2808 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2814 return !MO.isReg() ||
2815 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2820 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2822 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2826 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2827 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2832 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2833 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2839 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2840 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2841 "Expected an insert/extract element op");
2842 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2847 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2855 unsigned &
OpIdx)
const {
2861 OpIdx = Cst->isZero() ? 3 : 2;
2906 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2933 return MO.isReg() && MO.getReg().isPhysical();
2943 return I1->isIdenticalTo(*I2);
2951 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2958 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2970 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2971 MaybeCst->getSExtValue() ==
C;
2978 std::optional<FPValueAndVReg> MaybeCst;
2982 return MaybeCst->Value.isExactlyValue(
C);
2986 unsigned OpIdx)
const {
2987 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2992 MI.eraseFromParent();
2997 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3001 MI.eraseFromParent();
3005 unsigned ConstIdx)
const {
3006 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3007 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3019 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3020 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3021 "This is not a funnel shift operation");
3023 Register ConstReg =
MI.getOperand(3).getReg();
3024 LLT ConstTy =
MRI.getType(ConstReg);
3025 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3028 assert((VRegAndVal) &&
"Value is not a constant");
3031 APInt NewConst = VRegAndVal->Value.
urem(
3036 MI.getOpcode(), {MI.getOperand(0)},
3037 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3039 MI.eraseFromParent();
3043 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3057 unsigned OpIdx)
const {
3059 return MO.
isReg() &&
3064 unsigned OpIdx)
const {
3071 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3073 MI.eraseFromParent();
3078 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3080 MI.eraseFromParent();
3084 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3086 MI.eraseFromParent();
3091 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3093 MI.eraseFromParent();
3097 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3099 MI.eraseFromParent();
3103 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3106 Register &NewLHS = std::get<0>(MatchInfo);
3107 Register &NewRHS = std::get<1>(MatchInfo);
3115 NewLHS = MaybeNewLHS;
3119 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3124 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3127 LLT DstTy =
MRI.getType(DstReg);
3136 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3137 TargetOpcode::G_INSERT_VECTOR_ELT)
3143 MatchInfo.
resize(NumElts);
3147 if (IntImm >= NumElts || IntImm < 0)
3149 if (!MatchInfo[IntImm])
3150 MatchInfo[IntImm] = TmpReg;
3154 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3156 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3165 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3172 auto GetUndef = [&]() {
3175 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3183 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3184 MI.eraseFromParent();
3188 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3190 std::tie(SubLHS, SubRHS) = MatchInfo;
3191 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3192 MI.eraseFromParent();
3203 unsigned LogicOpcode =
MI.getOpcode();
3204 assert(LogicOpcode == TargetOpcode::G_AND ||
3205 LogicOpcode == TargetOpcode::G_OR ||
3206 LogicOpcode == TargetOpcode::G_XOR);
3213 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3219 if (!LeftHandInst || !RightHandInst)
3221 unsigned HandOpcode = LeftHandInst->
getOpcode();
3222 if (HandOpcode != RightHandInst->
getOpcode())
3236 if (!XTy.
isValid() || XTy != YTy)
3241 switch (HandOpcode) {
3244 case TargetOpcode::G_ANYEXT:
3245 case TargetOpcode::G_SEXT:
3246 case TargetOpcode::G_ZEXT: {
3250 case TargetOpcode::G_TRUNC: {
3255 LLT DstTy =
MRI.getType(Dst);
3264 case TargetOpcode::G_AND:
3265 case TargetOpcode::G_ASHR:
3266 case TargetOpcode::G_LSHR:
3267 case TargetOpcode::G_SHL: {
3272 ExtraHandOpSrcReg = ZOp.
getReg();
3283 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3294 if (ExtraHandOpSrcReg.
isValid())
3306 "Expected at least one instr to build?");
3308 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3309 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3311 for (
auto &OperandFn : InstrToBuild.OperandFns)
3314 MI.eraseFromParent();
3318 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3319 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3320 int64_t ShlCst, AshrCst;
3326 if (ShlCst != AshrCst)
3329 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3331 MatchInfo = std::make_tuple(Src, ShlCst);
3336 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3337 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3340 std::tie(Src, ShiftAmt) = MatchInfo;
3341 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3342 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3343 MI.eraseFromParent();
3350 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3353 LLT Ty =
MRI.getType(Dst);
3365 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3368 auto Zero =
B.buildConstant(Ty, 0);
3391 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3415 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3422 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3439 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3457 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3464 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3475 unsigned ExtBits =
MI.getOperand(2).getImm();
3476 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3477 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3481 int64_t Cst,
bool IsVector,
bool IsFP) {
3483 return (ScalarSizeBits == 1 && Cst == -1) ||
3505 unsigned BuildUseCount = BV.getNumSources();
3506 if (BuildUseCount % 2 != 0)
3509 unsigned NumUnmerge = BuildUseCount / 2;
3515 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3518 UnmergeSrc = Unmerge->getSourceReg();
3520 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3521 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3528 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3533 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3534 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3537 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3540 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3545 if (Unmerge->getNumDefs() != NumUnmerge)
3549 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3552 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3563 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3564 B.setInstrAndDebugLoc(
MI);
3566 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3567 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3569 MI.eraseFromParent();
3591 unsigned NumOperands =
BuildMI->getNumSources();
3601 for (
I = 0;
I < NumOperands; ++
I) {
3602 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3603 auto SrcMIOpc = SrcMI->getOpcode();
3606 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3607 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3609 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3610 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3613 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3614 if (UnmergeMI != UnmergeSrcMI)
3629 for (;
I < NumOperands; ++
I) {
3630 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3631 auto SrcMIOpc = SrcMI->getOpcode();
3633 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3639 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3646 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3647 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3655 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3658 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3670 LLT DstTy =
MRI.getType(DstReg);
3671 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3676 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3681 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3685 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3688 Builder.buildTrunc(DstReg, MidReg);
3689 MI.eraseFromParent();
3694 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3695 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3696 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3704 if (!
MRI.hasOneNonDBGUse(XorSrc))
3714 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3716 if (!
MRI.hasOneNonDBGUse(Reg))
3719 switch (Def->getOpcode()) {
3724 case TargetOpcode::G_ICMP:
3730 case TargetOpcode::G_FCMP:
3736 case TargetOpcode::G_AND:
3737 case TargetOpcode::G_OR:
3743 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3744 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3752 if (Ty.isVector()) {
3757 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3771 for (
Register Reg : RegsToNegate) {
3776 switch (Def->getOpcode()) {
3779 case TargetOpcode::G_ICMP:
3780 case TargetOpcode::G_FCMP: {
3787 case TargetOpcode::G_AND:
3788 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3790 case TargetOpcode::G_OR:
3791 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3798 MI.eraseFromParent();
3802 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3804 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3808 Register SharedReg =
MI.getOperand(2).getReg();
3822 if (!
MRI.hasOneNonDBGUse(AndReg))
3829 return Y == SharedReg;
3833 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3836 std::tie(
X,
Y) = MatchInfo;
3839 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3840 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3841 MI.getOperand(2).setReg(
Y);
3847 Register DstReg = PtrAdd.getReg(0);
3848 LLT Ty =
MRI.getType(DstReg);
3851 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3854 if (Ty.isPointer()) {
3856 return ConstVal && *ConstVal == 0;
3859 assert(Ty.isVector() &&
"Expecting a vector type");
3866 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3867 PtrAdd.eraseFromParent();
3874 Register Pow2Src1 =
MI.getOperand(2).getReg();
3875 LLT Ty =
MRI.getType(DstReg);
3878 auto NegOne =
Builder.buildConstant(Ty, -1);
3879 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3881 MI.eraseFromParent();
3885 unsigned &SelectOpNo)
const {
3895 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3896 !
MRI.hasOneNonDBGUse(LHS)) {
3897 OtherOperandReg = LHS;
3900 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3901 !
MRI.hasOneNonDBGUse(RHS))
3917 unsigned BinOpcode =
MI.getOpcode();
3922 bool CanFoldNonConst =
3923 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3928 if (CanFoldNonConst)
3949 LLT Ty =
MRI.getType(Dst);
3950 unsigned BinOpcode =
MI.getOpcode();
3957 if (SelectOperand == 1) {
3961 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3963 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3965 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3967 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3970 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3971 MI.eraseFromParent();
3974std::optional<SmallVector<Register, 8>>
3975CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3976 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4005 const unsigned MaxIter =
4007 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4016 return std::nullopt;
4032 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4033 return std::nullopt;
4045static std::optional<std::pair<GZExtLoad *, int64_t>>
4049 "Expected Reg to only have one non-debug use?");
4058 if (Shift % MemSizeInBits != 0)
4059 return std::nullopt;
4064 return std::nullopt;
4066 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4067 return std::nullopt;
4069 return std::make_pair(Load, Shift / MemSizeInBits);
4072std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4073CombinerHelper::findLoadOffsetsForLoadOrCombine(
4076 const unsigned MemSizeInBits)
const {
4079 SmallSetVector<const MachineInstr *, 8> Loads;
4085 GZExtLoad *LowestIdxLoad =
nullptr;
4088 SmallSet<int64_t, 8> SeenIdx;
4092 MachineBasicBlock *
MBB =
nullptr;
4093 const MachineMemOperand *MMO =
nullptr;
4096 GZExtLoad *EarliestLoad =
nullptr;
4099 GZExtLoad *LatestLoad =
nullptr;
4108 for (
auto Reg : RegsToVisit) {
4113 return std::nullopt;
4116 std::tie(Load, DstPos) = *LoadAndPos;
4120 MachineBasicBlock *LoadMBB =
Load->getParent();
4124 return std::nullopt;
4127 auto &LoadMMO =
Load->getMMO();
4131 return std::nullopt;
4138 LoadPtr =
Load->getOperand(1).getReg();
4143 if (!SeenIdx.
insert(Idx).second)
4144 return std::nullopt;
4151 if (BasePtr != LoadPtr)
4152 return std::nullopt;
4154 if (Idx < LowestIdx) {
4156 LowestIdxLoad =
Load;
4163 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4164 return std::nullopt;
4172 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4173 EarliestLoad =
Load;
4174 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4181 "Expected to find a load for each register?");
4182 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4183 LatestLoad &&
"Expected at least two loads?");
4192 const unsigned MaxIter = 20;
4198 if (
MI.isLoadFoldBarrier())
4199 return std::nullopt;
4200 if (Iter++ == MaxIter)
4201 return std::nullopt;
4204 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4210 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4223 LLT Ty =
MRI.getType(Dst);
4229 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4230 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4234 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4241 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4242 if (NarrowMemSizeInBits % 8 != 0)
4255 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4256 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4259 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4266 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4269 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4281 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4282 const unsigned ZeroByteOffset =
4286 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4287 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4288 ZeroOffsetIdx->second != LowestIdx)
4298 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4312 MIB.setInstrAndDebugLoc(*LatestLoad);
4313 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4314 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4316 MIB.buildBSwap(Dst, LoadDst);
4328 if (
MRI.getType(DstReg).isVector())
4332 if (!
MRI.hasOneNonDBGUse(DstReg))
4334 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4336 case TargetOpcode::G_ANYEXT:
4338 case TargetOpcode::G_ZEXT:
4339 case TargetOpcode::G_SEXT:
4346 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4353 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4355 switch (
DefMI->getOpcode()) {
4356 case TargetOpcode::G_LOAD:
4357 case TargetOpcode::G_TRUNC:
4358 case TargetOpcode::G_SEXT:
4359 case TargetOpcode::G_ZEXT:
4360 case TargetOpcode::G_ANYEXT:
4361 case TargetOpcode::G_CONSTANT:
4365 if (InSrcs.
size() > 2)
4379 LLT ExtTy =
MRI.getType(DstReg);
4386 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4387 auto SrcReg =
PHI.getIncomingValue(
I);
4388 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4389 if (!SrcMIs.
insert(SrcMI))
4393 auto *
MBB = SrcMI->getParent();
4395 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4396 InsertPt =
MBB->getFirstNonPHI();
4398 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4401 OldToNewSrcMap[SrcMI] = NewExt;
4406 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4407 NewPhi.addDef(DstReg);
4410 NewPhi.addMBB(MO.getMBB());
4413 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4414 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4422 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4426 LLT SrcTy =
MRI.getType(SrcVec);
4427 if (SrcTy.isScalableVector())
4431 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4434 unsigned VecIdx = Cst->Value.getZExtValue();
4439 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4443 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4444 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4448 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4460 LLT ScalarTy =
MRI.getType(Reg);
4462 LLT DstTy =
MRI.getType(DstReg);
4464 if (ScalarTy != DstTy) {
4466 Builder.buildTrunc(DstReg, Reg);
4467 MI.eraseFromParent();
4475 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4476 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4494 LLT DstTy =
MRI.getType(DstReg);
4499 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4504 unsigned Idx = Cst->getZExtValue();
4507 ExtractedElts.
set(Idx);
4508 SrcDstPairs.emplace_back(
4509 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4512 return ExtractedElts.
all();
4517 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4518 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4519 for (
auto &Pair : SrcDstPairs) {
4520 auto *ExtMI = Pair.second;
4522 ExtMI->eraseFromParent();
4524 MI.eraseFromParent();
4531 MI.eraseFromParent();
4541 bool AllowScalarConstants,
4543 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4546 LLT Ty =
MRI.getType(Dst);
4547 unsigned BitWidth = Ty.getScalarSizeInBits();
4549 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4550 unsigned FshOpc = 0;
4561 int64_t CstShlAmt = 0, CstLShrAmt;
4564 CstShlAmt + CstLShrAmt ==
BitWidth) {
4565 FshOpc = TargetOpcode::G_FSHR;
4571 FshOpc = TargetOpcode::G_FSHL;
4576 FshOpc = TargetOpcode::G_FSHR;
4581 LLT AmtTy =
MRI.getType(Amt);
4583 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4587 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4594 unsigned Opc =
MI.getOpcode();
4595 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4600 unsigned RotateOpc =
4601 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4606 unsigned Opc =
MI.getOpcode();
4607 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4608 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4610 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4611 : TargetOpcode::G_ROTR));
4612 MI.removeOperand(2);
4618 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4619 MI.getOpcode() == TargetOpcode::G_ROTR);
4621 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4623 bool OutOfRange =
false;
4624 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4626 OutOfRange |= CI->getValue().uge(Bitsize);
4633 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4634 MI.getOpcode() == TargetOpcode::G_ROTR);
4636 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4638 LLT AmtTy =
MRI.getType(Amt);
4639 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4640 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4642 MI.getOperand(2).setReg(Amt);
4647 int64_t &MatchInfo)
const {
4648 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4659 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4660 if (KnownRHS.isUnknown())
4663 std::optional<bool> KnownVal;
4664 if (KnownRHS.isZero()) {
4674 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4684 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4693 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4709 LLT DstTy =
MRI.getType(Dst);
4717 auto KnownLHS =
VT->getKnownBits(LHS);
4718 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4721 LLT LHSTy =
MRI.getType(LHS);
4724 unsigned Op = TargetOpcode::COPY;
4725 if (DstSize != LHSSize)
4726 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4737 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4741 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4747 int64_t AndMaskBits;
4755 if (AndMaskBits & OrMaskBits)
4761 if (
MI.getOperand(1).getReg() == AndMaskReg)
4762 MI.getOperand(2).setReg(AndMaskReg);
4763 MI.getOperand(1).setReg(Src);
4773 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4776 LLT Ty =
MRI.getType(Src);
4778 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4780 int64_t Width =
MI.getOperand(2).getImm();
4788 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4792 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4793 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4794 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4804 LLT Ty =
MRI.getType(Dst);
4808 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4811 int64_t AndImm, LSBImm;
4813 const unsigned Size = Ty.getScalarSizeInBits();
4820 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4821 if (MaybeMask & (MaybeMask + 1))
4830 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4831 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4832 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4840 const unsigned Opcode =
MI.getOpcode();
4841 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4843 const Register Dst =
MI.getOperand(0).getReg();
4845 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4846 ? TargetOpcode::G_SBFX
4847 : TargetOpcode::G_UBFX;
4850 LLT Ty =
MRI.getType(Dst);
4852 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4858 const unsigned Size = Ty.getScalarSizeInBits();
4868 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4872 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4876 const int64_t Pos = ShrAmt - ShlAmt;
4877 const int64_t Width =
Size - ShrAmt;
4880 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4881 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4882 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4890 const unsigned Opcode =
MI.getOpcode();
4891 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4893 const Register Dst =
MI.getOperand(0).getReg();
4894 LLT Ty =
MRI.getType(Dst);
4896 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4909 const unsigned Size = Ty.getScalarSizeInBits();
4910 if (ShrAmt < 0 || ShrAmt >=
Size)
4914 if (0 == (SMask >> ShrAmt)) {
4916 B.buildConstant(Dst, 0);
4922 uint64_t UMask = SMask;
4929 const int64_t Pos = ShrAmt;
4934 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4938 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4939 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4940 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4945bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4949 Register Src1Reg = PtrAdd.getBaseReg();
4954 Register Src2Reg = PtrAdd.getOffsetReg();
4956 if (
MRI.hasOneNonDBGUse(Src1Reg))
4966 const APInt &C1APIntVal = *C1;
4967 const APInt &C2APIntVal = *C2;
4968 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4970 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4973 MachineInstr *ConvUseMI = &
UseMI;
4974 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4975 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4976 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4978 if (!
MRI.hasOneNonDBGUse(DefReg))
4980 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4989 TargetLoweringBase::AddrMode AM;
4992 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4994 PtrAdd.getMF()->getFunction().getContext());
4995 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4996 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5002 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5014 Register Src1Reg =
MI.getOperand(1).getReg();
5015 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5027 unsigned PtrAddFlags =
MI.getFlags();
5028 unsigned AddFlags = RHS->getFlags();
5041 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5044 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5046 MI.getOperand(1).setReg(NewBase.getReg(0));
5047 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5051 return !reassociationCanBreakAddressingModePattern(
MI);
5061 std::optional<ValueAndVReg> LHSCstOff;
5071 unsigned PtrAddFlags =
MI.getFlags();
5072 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5074 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5076 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5090 LHSPtrAdd->moveBefore(&
MI);
5093 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5095 MI.getOperand(2).setReg(NewCst.getReg(0));
5098 Observer.changingInstr(*LHSPtrAdd);
5099 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5100 LHSPtrAdd->setFlags(Flags);
5103 return !reassociationCanBreakAddressingModePattern(
MI);
5114 Register Src2Reg =
MI.getOperand(2).getReg();
5115 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5116 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5129 unsigned PtrAddFlags =
MI.getFlags();
5130 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5143 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5145 MI.getOperand(1).setReg(LHSSrc1);
5146 MI.getOperand(2).setReg(NewCst.getReg(0));
5150 return !reassociationCanBreakAddressingModePattern(
MI);
5188 LLT OpRHSTy =
MRI.getType(OpRHS);
5207 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5208 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5216 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5217 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5230 unsigned Opc =
MI.getOpcode();
5243 APInt &MatchInfo)
const {
5244 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5248 MatchInfo = *MaybeCst;
5256 APInt &MatchInfo)
const {
5262 MatchInfo = *MaybeCst;
5274 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5280 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5281 MI.getOpcode() == TargetOpcode::G_FMAD);
5282 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5299 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5322 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5326 LLT WideTy =
MRI.getType(Dst);
5330 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5346 case TargetOpcode::G_ADD:
5347 case TargetOpcode::G_SUB:
5348 case TargetOpcode::G_MUL:
5349 case TargetOpcode::G_AND:
5350 case TargetOpcode::G_OR:
5351 case TargetOpcode::G_XOR:
5359 auto Mask = Cst->Value;
5364 unsigned NarrowWidth = Mask.countr_one();
5370 auto &MF = *
MI.getMF();
5373 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5374 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5382 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5383 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5385 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5386 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5388 MI.getOperand(1).setReg(Ext.getReg(0));
5396 unsigned Opc =
MI.getOpcode();
5397 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5404 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5405 : TargetOpcode::G_SADDO;
5406 MI.setDesc(
Builder.getTII().get(NewOpc));
5407 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5416 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5417 MI.getOpcode() == TargetOpcode::G_SMULO);
5426 B.buildConstant(Dst, 0);
5427 B.buildConstant(Carry, 0);
5436 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5437 MI.getOpcode() == TargetOpcode::G_SADDE ||
5438 MI.getOpcode() == TargetOpcode::G_USUBE ||
5439 MI.getOpcode() == TargetOpcode::G_SSUBE);
5444 switch (
MI.getOpcode()) {
5445 case TargetOpcode::G_UADDE:
5446 NewOpcode = TargetOpcode::G_UADDO;
5448 case TargetOpcode::G_SADDE:
5449 NewOpcode = TargetOpcode::G_SADDO;
5451 case TargetOpcode::G_USUBE:
5452 NewOpcode = TargetOpcode::G_USUBO;
5454 case TargetOpcode::G_SSUBE:
5455 NewOpcode = TargetOpcode::G_SSUBO;
5459 MI.setDesc(
B.getTII().get(NewOpcode));
5460 MI.removeOperand(4);
5468 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5501 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5502 B.buildSub(Dst, Zero, ReplaceReg);
5511 unsigned Opcode =
MI.getOpcode();
5512 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5514 Register Dst = UDivorRem.getReg(0);
5515 Register LHS = UDivorRem.getReg(1);
5516 Register RHS = UDivorRem.getReg(2);
5517 LLT Ty =
MRI.getType(Dst);
5525 bool UseSRL =
false;
5530 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5532 if (IsSplat && !Factors.
empty()) {
5539 APInt Divisor = CI->getValue();
5548 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5549 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5559 if (Ty.isVector()) {
5560 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5561 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5564 Factor = Factors[0];
5572 return MIB.buildMul(Ty, Res, Factor);
5575 unsigned KnownLeadingZeros =
5576 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5578 bool UseNPQ =
false;
5580 auto BuildUDIVPattern = [&](
const Constant *
C) {
5582 const APInt &Divisor = CI->getValue();
5584 bool SelNPQ =
false;
5586 unsigned PreShift = 0, PostShift = 0;
5591 if (!Divisor.
isOne()) {
5597 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5599 Magic = std::move(magics.
Magic);
5602 "We shouldn't generate an undefined shift!");
5604 "We shouldn't generate an undefined shift!");
5608 SelNPQ = magics.
IsAdd;
5612 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5613 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5615 MIB.buildConstant(ScalarTy,
5620 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5628 assert(Matched &&
"Expected unary predicate match to succeed");
5630 Register PreShift, PostShift, MagicFactor, NPQFactor;
5633 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5634 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5635 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5636 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5639 "Non-build_vector operation should have been a scalar");
5640 PreShift = PreShifts[0];
5641 MagicFactor = MagicFactors[0];
5642 PostShift = PostShifts[0];
5646 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5649 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5652 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5657 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5659 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5661 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5664 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5665 auto One = MIB.buildConstant(Ty, 1);
5666 auto IsOne = MIB.buildICmp(
5668 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5669 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5671 if (Opcode == TargetOpcode::G_UREM) {
5672 auto Prod = MIB.buildMul(Ty, ret, RHS);
5673 return MIB.buildSub(Ty, LHS, Prod);
5679 unsigned Opcode =
MI.getOpcode();
5680 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5683 LLT DstTy =
MRI.getType(Dst);
5685 auto &MF = *
MI.getMF();
5686 AttributeList Attr = MF.getFunction().getAttributes();
5695 if (MF.getFunction().hasMinSize())
5698 if (Opcode == TargetOpcode::G_UDIV &&
5701 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5704 auto *RHSDef =
MRI.getVRegDef(RHS);
5715 {TargetOpcode::G_ICMP,
5719 if (Opcode == TargetOpcode::G_UREM &&
5725 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5734 unsigned Opcode =
MI.getOpcode();
5735 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5738 LLT DstTy =
MRI.getType(Dst);
5742 auto &MF = *
MI.getMF();
5743 AttributeList Attr = MF.getFunction().getAttributes();
5752 if (MF.getFunction().hasMinSize())
5756 if (Opcode == TargetOpcode::G_SDIV &&
5759 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5762 auto *RHSDef =
MRI.getVRegDef(RHS);
5770 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5773 if (Opcode == TargetOpcode::G_SREM &&
5779 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5788 unsigned Opcode =
MI.getOpcode();
5789 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5790 Opcode == TargetOpcode::G_SREM);
5792 Register Dst = SDivorRem.getReg(0);
5793 Register LHS = SDivorRem.getReg(1);
5794 Register RHS = SDivorRem.getReg(2);
5795 LLT Ty =
MRI.getType(Dst);
5802 bool UseSRA =
false;
5808 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5810 if (IsSplat && !ExactFactors.
empty()) {
5812 ExactFactors.
push_back(ExactFactors[0]);
5817 APInt Divisor = CI->getValue();
5827 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5828 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5836 assert(Matched &&
"Expected unary predicate match to succeed");
5839 if (Ty.isVector()) {
5840 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5841 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5843 Shift = ExactShifts[0];
5844 Factor = ExactFactors[0];
5852 return MIB.buildMul(Ty, Res, Factor);
5857 auto BuildSDIVPattern = [&](
const Constant *
C) {
5859 const APInt &Divisor = CI->getValue();
5863 int NumeratorFactor = 0;
5874 NumeratorFactor = 1;
5877 NumeratorFactor = -1;
5880 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5881 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5883 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5884 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5892 assert(Matched &&
"Expected unary predicate match to succeed");
5894 Register MagicFactor, Factor, Shift, ShiftMask;
5897 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5898 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5899 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5900 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5903 "Non-build_vector operation should have been a scalar");
5904 MagicFactor = MagicFactors[0];
5905 Factor = Factors[0];
5907 ShiftMask = ShiftMasks[0];
5911 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5914 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5915 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5918 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5921 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5922 auto T = MIB.buildLShr(Ty, Q, SignShift);
5923 T = MIB.buildAnd(Ty,
T, ShiftMask);
5924 auto ret = MIB.buildAdd(Ty, Q,
T);
5926 if (Opcode == TargetOpcode::G_SREM) {
5927 auto Prod = MIB.buildMul(Ty, ret, RHS);
5928 return MIB.buildSub(Ty, LHS, Prod);
5934 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5935 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5936 "Expected SDIV or UDIV");
5939 auto MatchPow2 = [&](
const Constant *
C) {
5941 return CI && (CI->getValue().isPowerOf2() ||
5942 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5948 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5953 LLT Ty =
MRI.getType(Dst);
5973 unsigned BitWidth = Ty.getScalarSizeInBits();
5974 auto Zero =
Builder.buildConstant(Ty, 0);
5977 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5978 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5980 auto Sign =
Builder.buildAShr(
5984 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5990 auto One =
Builder.buildConstant(Ty, 1);
5991 auto MinusOne =
Builder.buildConstant(Ty, -1);
5995 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5996 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6000 auto Neg =
Builder.buildNeg(Ty, AShr);
6002 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6003 MI.eraseFromParent();
6007 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6012 LLT Ty =
MRI.getType(Dst);
6015 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6016 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6017 MI.eraseFromParent();
6021 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6024 LLT Ty =
MRI.getType(Dst);
6025 LLT RHSTy =
MRI.getType(RHS);
6027 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6029 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6044 LLT Ty =
MRI.getType(Dst);
6050 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6051 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6052 Builder.buildLShr(Dst, LHS, Trunc);
6053 MI.eraseFromParent();
6060 LLT DstTy =
MRI.getType(Dst);
6061 LLT SrcTy =
MRI.getType(Src);
6063 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6064 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6067 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6085 Builder.buildTruncSSatS(Dst, MatchInfo);
6086 MI.eraseFromParent();
6093 LLT DstTy =
MRI.getType(Dst);
6094 LLT SrcTy =
MRI.getType(Src);
6096 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6097 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6100 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6118 Builder.buildTruncSSatU(Dst, MatchInfo);
6119 MI.eraseFromParent();
6126 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6127 LLT SrcTy =
MRI.getType(Val);
6129 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6130 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6133 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6142 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6151 unsigned Opc =
MI.getOpcode();
6152 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6153 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6154 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6166 Opc = TargetOpcode::G_FSUB;
6171 Opc = TargetOpcode::G_FADD;
6177 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6178 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6187 MI.setDesc(
B.getTII().get(
Opc));
6188 MI.getOperand(1).setReg(
X);
6189 MI.getOperand(2).setReg(
Y);
6197 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6200 MatchInfo =
MI.getOperand(2).getReg();
6201 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6203 const auto LHSCst = Ty.isVector()
6210 if (LHSCst->Value.isNegZero())
6214 if (LHSCst->Value.isPosZero())
6224 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6231 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6245 bool &AllowFusionGlobally,
6247 bool CanReassociate)
const {
6249 auto *MF =
MI.getMF();
6250 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6252 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6260 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6263 if (!HasFMAD && !HasFMA)
6271 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6278 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6280 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6288 unsigned PreferredFusedOpcode =
6289 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6303 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6304 {LHS.MI->getOperand(1).getReg(),
6305 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6314 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6315 {RHS.MI->getOperand(1).getReg(),
6316 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6327 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6329 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6333 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6338 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6340 unsigned PreferredFusedOpcode =
6341 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6355 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6360 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6361 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6370 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6375 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6376 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6387 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6389 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6397 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6399 unsigned PreferredFusedOpcode =
6400 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6413 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6414 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6415 TargetOpcode::G_FMUL) &&
6416 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6417 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6422 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6423 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6424 TargetOpcode::G_FMUL) &&
6425 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6426 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6433 Register X = FMA->getOperand(1).getReg();
6434 Register Y = FMA->getOperand(2).getReg();
6439 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6440 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6441 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6453 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6455 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6462 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6463 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6469 unsigned PreferredFusedOpcode =
6470 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6483 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6484 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6486 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6488 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6495 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6499 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6504 LHS.MI->getOperand(1).getReg(),
6505 LHS.MI->getOperand(2).getReg(),
B);
6516 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6519 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6524 X =
B.buildFPExt(DstType,
X).getReg(0);
6525 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6536 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6540 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6545 RHS.MI->getOperand(1).getReg(),
6546 RHS.MI->getOperand(2).getReg(),
B);
6557 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6560 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6565 X =
B.buildFPExt(DstType,
X).getReg(0);
6566 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6580 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6582 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6590 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6594 int FirstMulHasFewerUses =
true;
6598 FirstMulHasFewerUses =
false;
6600 unsigned PreferredFusedOpcode =
6601 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6604 if (FirstMulHasFewerUses &&
6608 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6609 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6610 {LHS.MI->getOperand(1).getReg(),
6611 LHS.MI->getOperand(2).getReg(), NegZ});
6620 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6621 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6622 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6633 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6635 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6641 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6643 unsigned PreferredFusedOpcode =
6644 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6655 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6656 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6668 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6681 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6683 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6689 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6691 unsigned PreferredFusedOpcode =
6692 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6704 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6705 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6706 {FpExtX, FpExtY, NegZ});
6718 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6721 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6722 {NegY, FpExtZ, LHSReg});
6733 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6735 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6739 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6740 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6744 unsigned PreferredFusedOpcode =
6745 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6749 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6750 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6751 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6762 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6765 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6768 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6778 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6791 unsigned &IdxToPropagate)
const {
6793 switch (
MI.getOpcode()) {
6796 case TargetOpcode::G_FMINNUM:
6797 case TargetOpcode::G_FMAXNUM:
6798 PropagateNaN =
false;
6800 case TargetOpcode::G_FMINIMUM:
6801 case TargetOpcode::G_FMAXIMUM:
6802 PropagateNaN =
true;
6806 auto MatchNaN = [&](
unsigned Idx) {
6807 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6811 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6815 return MatchNaN(1) || MatchNaN(2);
6823 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6833 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6846 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6847 if (&U == &
MI || U.getParent() !=
MI.getParent())
6849 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6850 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6863 return MatchInfo.
size() >= MinUses;
6871 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6872 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6873 MatchInfo[0]->getOperand(2).getReg(),
6874 MatchInfo[0]->getFlags());
6879 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6880 Div->getOperand(0).getReg(),
MI->getFlags());
6881 MI->eraseFromParent();
6886 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6896 Reg == MaybeSameReg;
6898 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6919 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6928 return MRI.getType(MatchInfo) == DstVecTy;
6931 std::optional<ValueAndVReg> ShiftAmount;
6940 return MRI.getType(MatchInfo) == DstVecTy;
6955 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6962 std::optional<ValueAndVReg> ShiftAmt;
6968 LLT MatchTy =
MRI.getType(MatchInfo);
6969 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6970 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6973unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6975 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6976 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6977 "Expected a NaN behaviour?");
6987 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6988 return TargetOpcode::G_FMAXNUM;
6989 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6990 return TargetOpcode::G_FMAXIMUM;
6991 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6992 return TargetOpcode::G_FMAXNUM;
6993 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6994 return TargetOpcode::G_FMAXIMUM;
7000 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7001 return TargetOpcode::G_FMINNUM;
7002 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7003 return TargetOpcode::G_FMINIMUM;
7004 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7005 return TargetOpcode::G_FMINNUM;
7006 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7008 return TargetOpcode::G_FMINIMUM;
7012CombinerHelper::SelectPatternNaNBehaviour
7014 bool IsOrderedComparison)
const {
7018 if (!LHSSafe && !RHSSafe)
7019 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7020 if (LHSSafe && RHSSafe)
7021 return SelectPatternNaNBehaviour::RETURNS_ANY;
7024 if (IsOrderedComparison)
7025 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7026 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7029 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7030 : SelectPatternNaNBehaviour::RETURNS_NAN;
7039 LLT DstTy =
MRI.getType(Dst);
7052 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7054 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7056 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7059 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7060 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7061 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7062 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7064 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7067 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7072 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7077 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7079 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7083 MatchInfo = [=](MachineIRBuilder &
B) {
7084 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7092 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7099 Register TrueVal =
MI.getOperand(2).getReg();
7100 Register FalseVal =
MI.getOperand(3).getReg();
7101 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7106 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7119 if (MatchedSub &&
X != OpLHS)
7127 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7130 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7131 B.buildICmp(Pred, Dst,
Y, Zero);
7138static std::optional<unsigned>
7140 std::optional<int64_t> &Result) {
7141 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7142 Opcode == TargetOpcode::G_ASHR) &&
7143 "Expect G_SHL, G_LSHR or G_ASHR.");
7144 auto SignificantBits = 0;
7146 case TargetOpcode::G_SHL:
7150 case TargetOpcode::G_LSHR:
7154 case TargetOpcode::G_ASHR:
7163 Result = std::nullopt;
7174 Register ShiftVal =
MI.getOperand(1).getReg();
7175 Register ShiftReg =
MI.getOperand(2).getReg();
7176 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7177 auto IsShiftTooBig = [&](
const Constant *
C) {
7182 MatchInfo = std::nullopt;
7186 MI.getOpcode(), MatchInfo);
7187 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7193 unsigned LHSOpndIdx = 1;
7194 unsigned RHSOpndIdx = 2;
7195 switch (
MI.getOpcode()) {
7196 case TargetOpcode::G_UADDO:
7197 case TargetOpcode::G_SADDO:
7198 case TargetOpcode::G_UMULO:
7199 case TargetOpcode::G_SMULO:
7206 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7207 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7212 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7213 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7217 return MRI.getVRegDef(RHS)->getOpcode() !=
7218 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7225 std::optional<FPValueAndVReg> ValAndVReg;
7233 unsigned LHSOpndIdx = 1;
7234 unsigned RHSOpndIdx = 2;
7235 switch (
MI.getOpcode()) {
7236 case TargetOpcode::G_UADDO:
7237 case TargetOpcode::G_SADDO:
7238 case TargetOpcode::G_UMULO:
7239 case TargetOpcode::G_SMULO:
7246 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7247 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7248 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7249 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7253bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7255 if (SrcTy.isFixedVector())
7256 return isConstantSplatVector(Src, 1, AllowUndefs);
7257 if (SrcTy.isScalar()) {
7261 return IConstant && IConstant->Value == 1;
7266bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7267 LLT SrcTy =
MRI.getType(Src);
7269 return isConstantSplatVector(Src, 0, AllowUndefs);
7274 return IConstant && IConstant->Value == 0;
7281bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7282 bool AllowUndefs)
const {
7288 for (
unsigned I = 0;
I < NumSources; ++
I) {
7289 GImplicitDef *ImplicitDef =
7291 if (ImplicitDef && AllowUndefs)
7293 if (ImplicitDef && !AllowUndefs)
7295 std::optional<ValueAndVReg> IConstant =
7297 if (IConstant && IConstant->Value == SplatValue)
7307CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7310 return IConstant->Value;
7314 return std::nullopt;
7317 std::optional<APInt>
Value = std::nullopt;
7318 for (
unsigned I = 0;
I < NumSources; ++
I) {
7319 std::optional<ValueAndVReg> IConstant =
7322 return std::nullopt;
7324 Value = IConstant->Value;
7325 else if (*
Value != IConstant->Value)
7326 return std::nullopt;
7332bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7342 for (
unsigned I = 0;
I < NumSources; ++
I) {
7343 std::optional<ValueAndVReg> IConstant =
7352bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7359 LLT CondTy =
MRI.getType(
Select->getCondReg());
7360 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7370 std::optional<ValueAndVReg> TrueOpt =
7372 std::optional<ValueAndVReg> FalseOpt =
7375 if (!TrueOpt || !FalseOpt)
7378 APInt TrueValue = TrueOpt->Value;
7379 APInt FalseValue = FalseOpt->Value;
7383 MatchInfo = [=](MachineIRBuilder &
B) {
7384 B.setInstrAndDebugLoc(*
Select);
7385 B.buildZExtOrTrunc(Dest,
Cond);
7392 MatchInfo = [=](MachineIRBuilder &
B) {
7393 B.setInstrAndDebugLoc(*
Select);
7394 B.buildSExtOrTrunc(Dest,
Cond);
7401 MatchInfo = [=](MachineIRBuilder &
B) {
7402 B.setInstrAndDebugLoc(*
Select);
7403 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7404 B.buildNot(Inner,
Cond);
7405 B.buildZExtOrTrunc(Dest, Inner);
7412 MatchInfo = [=](MachineIRBuilder &
B) {
7413 B.setInstrAndDebugLoc(*
Select);
7414 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7415 B.buildNot(Inner,
Cond);
7416 B.buildSExtOrTrunc(Dest, Inner);
7422 if (TrueValue - 1 == FalseValue) {
7423 MatchInfo = [=](MachineIRBuilder &
B) {
7424 B.setInstrAndDebugLoc(*
Select);
7425 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7426 B.buildZExtOrTrunc(Inner,
Cond);
7427 B.buildAdd(Dest, Inner, False);
7433 if (TrueValue + 1 == FalseValue) {
7434 MatchInfo = [=](MachineIRBuilder &
B) {
7435 B.setInstrAndDebugLoc(*
Select);
7436 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7437 B.buildSExtOrTrunc(Inner,
Cond);
7438 B.buildAdd(Dest, Inner, False);
7445 MatchInfo = [=](MachineIRBuilder &
B) {
7446 B.setInstrAndDebugLoc(*
Select);
7447 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7448 B.buildZExtOrTrunc(Inner,
Cond);
7451 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7452 B.buildShl(Dest, Inner, ShAmtC, Flags);
7459 MatchInfo = [=](MachineIRBuilder &
B) {
7460 B.setInstrAndDebugLoc(*
Select);
7462 B.buildNot(Not,
Cond);
7463 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7464 B.buildZExtOrTrunc(Inner, Not);
7467 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7468 B.buildShl(Dest, Inner, ShAmtC, Flags);
7475 MatchInfo = [=](MachineIRBuilder &
B) {
7476 B.setInstrAndDebugLoc(*
Select);
7477 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7478 B.buildSExtOrTrunc(Inner,
Cond);
7479 B.buildOr(Dest, Inner, False, Flags);
7486 MatchInfo = [=](MachineIRBuilder &
B) {
7487 B.setInstrAndDebugLoc(*
Select);
7489 B.buildNot(Not,
Cond);
7490 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7491 B.buildSExtOrTrunc(Inner, Not);
7492 B.buildOr(Dest, Inner, True, Flags);
7501bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7508 LLT CondTy =
MRI.getType(
Select->getCondReg());
7509 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7518 if (CondTy != TrueTy)
7523 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7524 MatchInfo = [=](MachineIRBuilder &
B) {
7525 B.setInstrAndDebugLoc(*
Select);
7526 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7527 B.buildZExtOrTrunc(Ext,
Cond);
7528 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7529 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7536 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7537 MatchInfo = [=](MachineIRBuilder &
B) {
7538 B.setInstrAndDebugLoc(*
Select);
7539 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7540 B.buildZExtOrTrunc(Ext,
Cond);
7541 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7542 B.buildAnd(DstReg, Ext, FreezeTrue);
7548 if (isOneOrOneSplat(False,
true)) {
7549 MatchInfo = [=](MachineIRBuilder &
B) {
7550 B.setInstrAndDebugLoc(*
Select);
7552 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7553 B.buildNot(Inner,
Cond);
7555 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7556 B.buildZExtOrTrunc(Ext, Inner);
7557 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7558 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7564 if (isZeroOrZeroSplat(True,
true)) {
7565 MatchInfo = [=](MachineIRBuilder &
B) {
7566 B.setInstrAndDebugLoc(*
Select);
7568 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7569 B.buildNot(Inner,
Cond);
7571 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7572 B.buildZExtOrTrunc(Ext, Inner);
7573 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7574 B.buildAnd(DstReg, Ext, FreezeFalse);
7590 LLT DstTy =
MRI.getType(DstReg);
7596 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7605 Register CmpLHS = Cmp->getLHSReg();
7606 Register CmpRHS = Cmp->getRHSReg();
7609 if (True == CmpRHS && False == CmpLHS) {
7617 if (True != CmpLHS || False != CmpRHS)
7657 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7658 Register DestReg =
MI.getOperand(0).getReg();
7659 LLT DestTy =
MRI.getType(DestReg);
7671 if (
isLegal({NewOpc, {DestTy}})) {
7673 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7685 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7688 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7698bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7700 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7701 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7705 unsigned Flags = Logic->
getFlags();
7724 std::optional<ValueAndVReg> MaybeC1 =
7728 C1 = MaybeC1->Value;
7730 std::optional<ValueAndVReg> MaybeC2 =
7734 C2 = MaybeC2->Value;
7755 std::optional<APInt> Offset1;
7756 std::optional<APInt> Offset2;
7759 std::optional<ValueAndVReg> MaybeOffset1 =
7762 R1 =
Add->getLHSReg();
7763 Offset1 = MaybeOffset1->Value;
7767 std::optional<ValueAndVReg> MaybeOffset2 =
7770 R2 =
Add->getLHSReg();
7771 Offset2 = MaybeOffset2->Value;
7790 bool CreateMask =
false;
7803 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7816 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7825 MatchInfo = [=](MachineIRBuilder &
B) {
7826 if (CreateMask &&
Offset != 0) {
7827 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7828 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7829 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7830 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7831 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7832 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7833 B.buildZExtOrTrunc(DstReg, ICmp);
7834 }
else if (CreateMask &&
Offset == 0) {
7835 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7836 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7837 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7838 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7839 B.buildZExtOrTrunc(DstReg, ICmp);
7840 }
else if (!CreateMask &&
Offset != 0) {
7841 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7842 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7843 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7844 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7845 B.buildZExtOrTrunc(DstReg, ICmp);
7846 }
else if (!CreateMask &&
Offset == 0) {
7847 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7848 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7849 B.buildZExtOrTrunc(DstReg, ICmp);
7857bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7863 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7875 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7881 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7882 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7883 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7884 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7895 if (LHS0 == RHS1 && LHS1 == RHS0) {
7901 if (LHS0 == RHS0 && LHS1 == RHS1) {
7905 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7907 MatchInfo = [=](MachineIRBuilder &
B) {
7912 auto False =
B.buildConstant(CmpTy, 0);
7913 B.buildZExtOrTrunc(DestReg, False);
7920 B.buildZExtOrTrunc(DestReg, True);
7922 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7923 B.buildZExtOrTrunc(DestReg, Cmp);
7935 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7938 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7947 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7950 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7965 bool IsSigned =
Add->isSigned();
7966 LLT DstTy =
MRI.getType(Dst);
7967 LLT CarryTy =
MRI.getType(Carry);
7970 if (
MRI.use_nodbg_empty(Carry) &&
7973 B.buildAdd(Dst, LHS, RHS);
7974 B.buildUndef(Carry);
7980 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7983 B.buildSAddo(Dst, Carry, RHS, LHS);
7989 B.buildUAddo(Dst, Carry, RHS, LHS);
7994 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7995 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8001 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8002 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8004 B.buildConstant(Dst, Result);
8005 B.buildConstant(Carry, Overflow);
8013 B.buildCopy(Dst, LHS);
8014 B.buildConstant(Carry, 0);
8023 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8026 std::optional<APInt> MaybeAddRHS =
8027 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8030 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8031 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8035 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8036 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8042 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8043 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8068 B.buildConstant(Carry, 0);
8075 B.buildAdd(Dst, LHS, RHS);
8076 B.buildConstant(Carry, 1);
8088 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8091 B.buildConstant(Carry, 0);
8107 B.buildConstant(Carry, 0);
8114 B.buildAdd(Dst, LHS, RHS);
8115 B.buildConstant(Carry, 1);
8133 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8139 auto [Dst,
Base] =
MI.getFirst2Regs();
8140 LLT Ty =
MRI.getType(Dst);
8144 Builder.buildFConstant(Dst, 1.0);
8145 MI.removeFromParent();
8157 std::optional<SrcOp> Res;
8159 while (ExpVal > 0) {
8164 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8167 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8174 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8178 MI.eraseFromParent();
8187 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8194 LLT DstTy =
MRI.getType(Dst);
8197 auto Const =
B.buildConstant(DstTy, C1 - C2);
8198 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8210 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8217 LLT DstTy =
MRI.getType(Dst);
8220 auto Const =
B.buildConstant(DstTy, C2 - C1);
8221 B.buildSub(Dst, Const,
Add->getLHSReg());
8233 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8240 LLT DstTy =
MRI.getType(Dst);
8243 auto Const =
B.buildConstant(DstTy, C1 + C2);
8256 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8263 LLT DstTy =
MRI.getType(Dst);
8266 auto Const =
B.buildConstant(DstTy, C1 - C2);
8279 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8286 LLT DstTy =
MRI.getType(Dst);
8289 auto Const =
B.buildConstant(DstTy, C2 - C1);
8290 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8337 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8341 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8344 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8345 LLT SmallBvTy = DstTy;
8349 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8354 {TargetOpcode::G_ANYEXT,
8366 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8367 Ops.push_back(AnyExt.getReg(0));
8385 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8386 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8387 const unsigned NumDstElts = OrigMask.
size();
8388 for (
unsigned i = 0; i != NumDstElts; ++i) {
8389 int Idx = OrigMask[i];
8390 if (Idx >= (
int)NumSrcElems) {
8401 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8402 std::move(NewMask));
8409 const unsigned MaskSize = Mask.size();
8410 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8415 if (Idx < (
int)NumElems)
8416 Mask[
I] = Idx + NumElems;
8418 Mask[
I] = Idx - NumElems;
8428 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8431 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8434 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8435 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8437 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8441 const unsigned NumSrcElems = Src1Ty.getNumElements();
8443 bool TouchesSrc1 =
false;
8444 bool TouchesSrc2 =
false;
8445 const unsigned NumElems = Mask.size();
8446 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8450 if (Mask[Idx] < (
int)NumSrcElems)
8456 if (TouchesSrc1 == TouchesSrc2)
8459 Register NewSrc1 = Shuffle.getSrc1Reg();
8462 NewSrc1 = Shuffle.getSrc2Reg();
8467 auto Undef =
B.buildUndef(Src1Ty);
8468 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8482 LLT DstTy =
MRI.getType(Dst);
8483 LLT CarryTy =
MRI.getType(Carry);
8505 B.buildConstant(Carry, 0);
8512 B.buildSub(Dst, LHS, RHS);
8530 B.buildConstant(Carry, 0);
8537 B.buildSub(Dst, LHS, RHS);
8554 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8555 "Expected G_CTLZ variant");
8560 LLT Ty =
MRI.getType(Dst);
8561 LLT SrcTy =
MRI.getType(Src);
8563 if (!(Ty.isValid() && Ty.isScalar()))
8572 switch (
LI->getAction(Query).Action) {
8583 bool NeedAdd =
true;
8591 unsigned BitWidth = Ty.getScalarSizeInBits();
8602 B.buildCTLS(Dst,
X);
8606 auto Ctls =
B.buildCTLS(Ty,
X);
8607 auto One =
B.buildConstant(Ty, 1);
8609 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< 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")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
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 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.
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 LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr ElementCount getElementCount() const
constexpr 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.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
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...
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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.
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< 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)
class_match< BinaryOperator > m_BinOp()
Match an arbitrary binary operation and ignore it.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > OperandBuildSteps
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
LLVM_ABI bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
LLVM_ABI std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
LLVM_ABI unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc)
Returns the inverse opcode of MinMaxOpc, which is a generic min/max opcode like G_SMIN.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a float constant integer or a splat vector of float constant integers.
constexpr unsigned BitWidth
LLVM_ABI int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI 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...