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();
3205 unsigned InnerOpc = InnerDef->
getOpcode();
3206 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3229 if (!TryMatch(InnerLHS, InnerRHS) && !TryMatch(InnerRHS, InnerLHS))
3233 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3234 : TargetOpcode::G_ADD;
3237 MatchInfo = [=](MachineIRBuilder &
Builder) {
3238 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3239 auto NewNot =
Builder.buildNot(Ty, NewInner);
3240 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3252 unsigned RootOpc =
MI.getOpcode();
3254 LLT Ty =
MRI.getType(Dst);
3259 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3260 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3271 unsigned LogicOpcode =
MI.getOpcode();
3272 assert(LogicOpcode == TargetOpcode::G_AND ||
3273 LogicOpcode == TargetOpcode::G_OR ||
3274 LogicOpcode == TargetOpcode::G_XOR);
3281 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3287 if (!LeftHandInst || !RightHandInst)
3289 unsigned HandOpcode = LeftHandInst->
getOpcode();
3290 if (HandOpcode != RightHandInst->
getOpcode())
3304 if (!XTy.
isValid() || XTy != YTy)
3309 switch (HandOpcode) {
3312 case TargetOpcode::G_ANYEXT:
3313 case TargetOpcode::G_SEXT:
3314 case TargetOpcode::G_ZEXT: {
3318 case TargetOpcode::G_TRUNC: {
3323 LLT DstTy =
MRI.getType(Dst);
3332 case TargetOpcode::G_AND:
3333 case TargetOpcode::G_ASHR:
3334 case TargetOpcode::G_LSHR:
3335 case TargetOpcode::G_SHL: {
3340 ExtraHandOpSrcReg = ZOp.
getReg();
3351 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3362 if (ExtraHandOpSrcReg.
isValid())
3374 "Expected at least one instr to build?");
3376 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3377 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3379 for (
auto &OperandFn : InstrToBuild.OperandFns)
3382 MI.eraseFromParent();
3386 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3387 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3388 int64_t ShlCst, AshrCst;
3394 if (ShlCst != AshrCst)
3397 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3399 MatchInfo = std::make_tuple(Src, ShlCst);
3404 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3405 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3408 std::tie(Src, ShiftAmt) = MatchInfo;
3409 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3410 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3411 MI.eraseFromParent();
3418 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3421 LLT Ty =
MRI.getType(Dst);
3433 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3436 auto Zero =
B.buildConstant(Ty, 0);
3459 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3483 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3490 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3507 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3525 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3532 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3543 unsigned ExtBits =
MI.getOperand(2).getImm();
3544 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3545 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3549 int64_t Cst,
bool IsVector,
bool IsFP) {
3551 return (ScalarSizeBits == 1 && Cst == -1) ||
3573 unsigned BuildUseCount = BV.getNumSources();
3574 if (BuildUseCount % 2 != 0)
3577 unsigned NumUnmerge = BuildUseCount / 2;
3583 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3586 UnmergeSrc = Unmerge->getSourceReg();
3588 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3589 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3596 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3601 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3602 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3605 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3608 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3613 if (Unmerge->getNumDefs() != NumUnmerge)
3617 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3620 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3631 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3632 B.setInstrAndDebugLoc(
MI);
3634 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3635 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3637 MI.eraseFromParent();
3659 unsigned NumOperands =
BuildMI->getNumSources();
3669 for (
I = 0;
I < NumOperands; ++
I) {
3670 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3671 auto SrcMIOpc = SrcMI->getOpcode();
3674 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3675 Register TruncSrcReg = SrcMI->getOperand(1).getReg();
3677 UnmergeMI =
MRI.getVRegDef(TruncSrcReg);
3678 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3681 auto UnmergeSrcMI =
MRI.getVRegDef(TruncSrcReg);
3682 if (UnmergeMI != UnmergeSrcMI)
3697 for (;
I < NumOperands; ++
I) {
3698 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3699 auto SrcMIOpc = SrcMI->getOpcode();
3701 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3707 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3714 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3715 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3723 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3726 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3738 LLT DstTy =
MRI.getType(DstReg);
3739 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3744 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3749 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3753 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3756 Builder.buildTrunc(DstReg, MidReg);
3757 MI.eraseFromParent();
3762 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3763 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3764 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3772 if (!
MRI.hasOneNonDBGUse(XorSrc))
3782 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3784 if (!
MRI.hasOneNonDBGUse(Reg))
3787 switch (Def->getOpcode()) {
3792 case TargetOpcode::G_ICMP:
3798 case TargetOpcode::G_FCMP:
3804 case TargetOpcode::G_AND:
3805 case TargetOpcode::G_OR:
3811 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3812 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3820 if (Ty.isVector()) {
3825 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3839 for (
Register Reg : RegsToNegate) {
3844 switch (Def->getOpcode()) {
3847 case TargetOpcode::G_ICMP:
3848 case TargetOpcode::G_FCMP: {
3855 case TargetOpcode::G_AND:
3856 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3858 case TargetOpcode::G_OR:
3859 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3866 MI.eraseFromParent();
3870 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3872 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3876 Register SharedReg =
MI.getOperand(2).getReg();
3890 if (!
MRI.hasOneNonDBGUse(AndReg))
3897 return Y == SharedReg;
3901 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3904 std::tie(
X,
Y) = MatchInfo;
3907 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3908 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3909 MI.getOperand(2).setReg(
Y);
3915 Register DstReg = PtrAdd.getReg(0);
3916 LLT Ty =
MRI.getType(DstReg);
3919 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3922 if (Ty.isPointer()) {
3924 return ConstVal && *ConstVal == 0;
3927 assert(Ty.isVector() &&
"Expecting a vector type");
3934 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3935 PtrAdd.eraseFromParent();
3942 Register Pow2Src1 =
MI.getOperand(2).getReg();
3943 LLT Ty =
MRI.getType(DstReg);
3946 auto NegOne =
Builder.buildConstant(Ty, -1);
3947 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3949 MI.eraseFromParent();
3953 unsigned &SelectOpNo)
const {
3963 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3964 !
MRI.hasOneNonDBGUse(LHS)) {
3965 OtherOperandReg = LHS;
3968 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3969 !
MRI.hasOneNonDBGUse(RHS))
3985 unsigned BinOpcode =
MI.getOpcode();
3990 bool CanFoldNonConst =
3991 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3996 if (CanFoldNonConst)
4017 LLT Ty =
MRI.getType(Dst);
4018 unsigned BinOpcode =
MI.getOpcode();
4025 if (SelectOperand == 1) {
4029 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4031 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4033 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4035 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4038 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4039 MI.eraseFromParent();
4042std::optional<SmallVector<Register, 8>>
4043CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4044 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4073 const unsigned MaxIter =
4075 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4084 return std::nullopt;
4100 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4101 return std::nullopt;
4113static std::optional<std::pair<GZExtLoad *, int64_t>>
4117 "Expected Reg to only have one non-debug use?");
4126 if (Shift % MemSizeInBits != 0)
4127 return std::nullopt;
4132 return std::nullopt;
4134 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4135 return std::nullopt;
4137 return std::make_pair(Load, Shift / MemSizeInBits);
4140std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4141CombinerHelper::findLoadOffsetsForLoadOrCombine(
4144 const unsigned MemSizeInBits)
const {
4147 SmallSetVector<const MachineInstr *, 8> Loads;
4153 GZExtLoad *LowestIdxLoad =
nullptr;
4156 SmallSet<int64_t, 8> SeenIdx;
4160 MachineBasicBlock *
MBB =
nullptr;
4161 const MachineMemOperand *MMO =
nullptr;
4164 GZExtLoad *EarliestLoad =
nullptr;
4167 GZExtLoad *LatestLoad =
nullptr;
4176 for (
auto Reg : RegsToVisit) {
4181 return std::nullopt;
4184 std::tie(Load, DstPos) = *LoadAndPos;
4188 MachineBasicBlock *LoadMBB =
Load->getParent();
4192 return std::nullopt;
4195 auto &LoadMMO =
Load->getMMO();
4199 return std::nullopt;
4206 LoadPtr =
Load->getOperand(1).getReg();
4211 if (!SeenIdx.
insert(Idx).second)
4212 return std::nullopt;
4219 if (BasePtr != LoadPtr)
4220 return std::nullopt;
4222 if (Idx < LowestIdx) {
4224 LowestIdxLoad =
Load;
4231 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4232 return std::nullopt;
4240 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4241 EarliestLoad =
Load;
4242 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4249 "Expected to find a load for each register?");
4250 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4251 LatestLoad &&
"Expected at least two loads?");
4260 const unsigned MaxIter = 20;
4266 if (
MI.isLoadFoldBarrier())
4267 return std::nullopt;
4268 if (Iter++ == MaxIter)
4269 return std::nullopt;
4272 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4278 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4291 LLT Ty =
MRI.getType(Dst);
4297 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4298 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4302 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4309 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4310 if (NarrowMemSizeInBits % 8 != 0)
4323 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4324 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4327 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4334 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4337 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4349 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4350 const unsigned ZeroByteOffset =
4354 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4355 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4356 ZeroOffsetIdx->second != LowestIdx)
4366 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4380 MIB.setInstrAndDebugLoc(*LatestLoad);
4381 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4382 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4384 MIB.buildBSwap(Dst, LoadDst);
4396 if (
MRI.getType(DstReg).isVector())
4400 if (!
MRI.hasOneNonDBGUse(DstReg))
4402 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4404 case TargetOpcode::G_ANYEXT:
4406 case TargetOpcode::G_ZEXT:
4407 case TargetOpcode::G_SEXT:
4414 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4421 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4423 switch (
DefMI->getOpcode()) {
4424 case TargetOpcode::G_LOAD:
4425 case TargetOpcode::G_TRUNC:
4426 case TargetOpcode::G_SEXT:
4427 case TargetOpcode::G_ZEXT:
4428 case TargetOpcode::G_ANYEXT:
4429 case TargetOpcode::G_CONSTANT:
4433 if (InSrcs.
size() > 2)
4447 LLT ExtTy =
MRI.getType(DstReg);
4454 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4455 auto SrcReg =
PHI.getIncomingValue(
I);
4456 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4457 if (!SrcMIs.
insert(SrcMI))
4461 auto *
MBB = SrcMI->getParent();
4463 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4464 InsertPt =
MBB->getFirstNonPHI();
4466 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4469 OldToNewSrcMap[SrcMI] = NewExt;
4474 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4475 NewPhi.addDef(DstReg);
4478 NewPhi.addMBB(MO.getMBB());
4481 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4482 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4490 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4494 LLT SrcTy =
MRI.getType(SrcVec);
4495 if (SrcTy.isScalableVector())
4499 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4502 unsigned VecIdx = Cst->Value.getZExtValue();
4507 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4511 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4512 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4516 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4528 LLT ScalarTy =
MRI.getType(Reg);
4530 LLT DstTy =
MRI.getType(DstReg);
4532 if (ScalarTy != DstTy) {
4534 Builder.buildTrunc(DstReg, Reg);
4535 MI.eraseFromParent();
4543 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4544 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4562 LLT DstTy =
MRI.getType(DstReg);
4567 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4572 unsigned Idx = Cst->getZExtValue();
4575 ExtractedElts.
set(Idx);
4576 SrcDstPairs.emplace_back(
4577 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4580 return ExtractedElts.
all();
4585 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4586 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4587 for (
auto &Pair : SrcDstPairs) {
4588 auto *ExtMI = Pair.second;
4590 ExtMI->eraseFromParent();
4592 MI.eraseFromParent();
4599 MI.eraseFromParent();
4609 bool AllowScalarConstants,
4611 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4614 LLT Ty =
MRI.getType(Dst);
4615 unsigned BitWidth = Ty.getScalarSizeInBits();
4617 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4618 unsigned FshOpc = 0;
4629 int64_t CstShlAmt = 0, CstLShrAmt;
4632 CstShlAmt + CstLShrAmt ==
BitWidth) {
4633 FshOpc = TargetOpcode::G_FSHR;
4639 FshOpc = TargetOpcode::G_FSHL;
4644 FshOpc = TargetOpcode::G_FSHR;
4649 LLT AmtTy =
MRI.getType(Amt);
4651 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4655 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4662 unsigned Opc =
MI.getOpcode();
4663 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4668 unsigned RotateOpc =
4669 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4674 unsigned Opc =
MI.getOpcode();
4675 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4676 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4678 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4679 : TargetOpcode::G_ROTR));
4680 MI.removeOperand(2);
4686 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4687 MI.getOpcode() == TargetOpcode::G_ROTR);
4689 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4691 bool OutOfRange =
false;
4692 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4694 OutOfRange |= CI->getValue().uge(Bitsize);
4701 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4702 MI.getOpcode() == TargetOpcode::G_ROTR);
4704 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4706 LLT AmtTy =
MRI.getType(Amt);
4707 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4708 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4710 MI.getOperand(2).setReg(Amt);
4715 int64_t &MatchInfo)
const {
4716 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4727 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4728 if (KnownRHS.isUnknown())
4731 std::optional<bool> KnownVal;
4732 if (KnownRHS.isZero()) {
4742 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4752 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4761 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4777 LLT DstTy =
MRI.getType(Dst);
4785 auto KnownLHS =
VT->getKnownBits(LHS);
4786 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4789 LLT LHSTy =
MRI.getType(LHS);
4792 unsigned Op = TargetOpcode::COPY;
4793 if (DstSize != LHSSize)
4794 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4805 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4809 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4815 int64_t AndMaskBits;
4823 if (AndMaskBits & OrMaskBits)
4829 if (
MI.getOperand(1).getReg() == AndMaskReg)
4830 MI.getOperand(2).setReg(AndMaskReg);
4831 MI.getOperand(1).setReg(Src);
4841 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4844 LLT Ty =
MRI.getType(Src);
4846 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4848 int64_t Width =
MI.getOperand(2).getImm();
4856 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4860 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4861 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4862 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4872 LLT Ty =
MRI.getType(Dst);
4876 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4879 int64_t AndImm, LSBImm;
4881 const unsigned Size = Ty.getScalarSizeInBits();
4888 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4889 if (MaybeMask & (MaybeMask + 1))
4898 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4899 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4900 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4908 const unsigned Opcode =
MI.getOpcode();
4909 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4911 const Register Dst =
MI.getOperand(0).getReg();
4913 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4914 ? TargetOpcode::G_SBFX
4915 : TargetOpcode::G_UBFX;
4918 LLT Ty =
MRI.getType(Dst);
4920 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4926 const unsigned Size = Ty.getScalarSizeInBits();
4936 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4940 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4944 const int64_t Pos = ShrAmt - ShlAmt;
4945 const int64_t Width =
Size - ShrAmt;
4948 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4949 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4950 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4958 const unsigned Opcode =
MI.getOpcode();
4959 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4961 const Register Dst =
MI.getOperand(0).getReg();
4962 LLT Ty =
MRI.getType(Dst);
4964 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4977 const unsigned Size = Ty.getScalarSizeInBits();
4978 if (ShrAmt < 0 || ShrAmt >=
Size)
4982 if (0 == (SMask >> ShrAmt)) {
4984 B.buildConstant(Dst, 0);
4990 uint64_t UMask = SMask;
4997 const int64_t Pos = ShrAmt;
5002 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5006 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5007 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5008 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5013bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5017 Register Src1Reg = PtrAdd.getBaseReg();
5022 Register Src2Reg = PtrAdd.getOffsetReg();
5024 if (
MRI.hasOneNonDBGUse(Src1Reg))
5034 const APInt &C1APIntVal = *C1;
5035 const APInt &C2APIntVal = *C2;
5036 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5038 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5041 MachineInstr *ConvUseMI = &
UseMI;
5042 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5043 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5044 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5046 if (!
MRI.hasOneNonDBGUse(DefReg))
5048 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5057 TargetLoweringBase::AddrMode AM;
5060 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5062 PtrAdd.getMF()->getFunction().getContext());
5063 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5064 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5070 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5082 Register Src1Reg =
MI.getOperand(1).getReg();
5083 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5095 unsigned PtrAddFlags =
MI.getFlags();
5096 unsigned AddFlags = RHS->getFlags();
5109 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5112 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5114 MI.getOperand(1).setReg(NewBase.getReg(0));
5115 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5119 return !reassociationCanBreakAddressingModePattern(
MI);
5129 std::optional<ValueAndVReg> LHSCstOff;
5139 unsigned PtrAddFlags =
MI.getFlags();
5140 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5142 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5144 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5158 LHSPtrAdd->moveBefore(&
MI);
5161 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5163 MI.getOperand(2).setReg(NewCst.getReg(0));
5166 Observer.changingInstr(*LHSPtrAdd);
5167 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5168 LHSPtrAdd->setFlags(Flags);
5171 return !reassociationCanBreakAddressingModePattern(
MI);
5182 Register Src2Reg =
MI.getOperand(2).getReg();
5183 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5184 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5197 unsigned PtrAddFlags =
MI.getFlags();
5198 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5211 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5213 MI.getOperand(1).setReg(LHSSrc1);
5214 MI.getOperand(2).setReg(NewCst.getReg(0));
5218 return !reassociationCanBreakAddressingModePattern(
MI);
5256 LLT OpRHSTy =
MRI.getType(OpRHS);
5275 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5276 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5284 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5285 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5298 unsigned Opc =
MI.getOpcode();
5311 APInt &MatchInfo)
const {
5312 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5316 MatchInfo = *MaybeCst;
5324 APInt &MatchInfo)
const {
5330 MatchInfo = *MaybeCst;
5342 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5348 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5349 MI.getOpcode() == TargetOpcode::G_FMAD);
5350 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5367 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5390 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5394 LLT WideTy =
MRI.getType(Dst);
5398 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5414 case TargetOpcode::G_ADD:
5415 case TargetOpcode::G_SUB:
5416 case TargetOpcode::G_MUL:
5417 case TargetOpcode::G_AND:
5418 case TargetOpcode::G_OR:
5419 case TargetOpcode::G_XOR:
5427 auto Mask = Cst->Value;
5432 unsigned NarrowWidth = Mask.countr_one();
5438 auto &MF = *
MI.getMF();
5441 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5442 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5450 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5451 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5453 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5454 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5456 MI.getOperand(1).setReg(Ext.getReg(0));
5464 unsigned Opc =
MI.getOpcode();
5465 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5472 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5473 : TargetOpcode::G_SADDO;
5474 MI.setDesc(
Builder.getTII().get(NewOpc));
5475 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5484 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5485 MI.getOpcode() == TargetOpcode::G_SMULO);
5494 B.buildConstant(Dst, 0);
5495 B.buildConstant(Carry, 0);
5504 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5505 MI.getOpcode() == TargetOpcode::G_SADDE ||
5506 MI.getOpcode() == TargetOpcode::G_USUBE ||
5507 MI.getOpcode() == TargetOpcode::G_SSUBE);
5512 switch (
MI.getOpcode()) {
5513 case TargetOpcode::G_UADDE:
5514 NewOpcode = TargetOpcode::G_UADDO;
5516 case TargetOpcode::G_SADDE:
5517 NewOpcode = TargetOpcode::G_SADDO;
5519 case TargetOpcode::G_USUBE:
5520 NewOpcode = TargetOpcode::G_USUBO;
5522 case TargetOpcode::G_SSUBE:
5523 NewOpcode = TargetOpcode::G_SSUBO;
5527 MI.setDesc(
B.getTII().get(NewOpcode));
5528 MI.removeOperand(4);
5536 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5569 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5570 B.buildSub(Dst, Zero, ReplaceReg);
5579 unsigned Opcode =
MI.getOpcode();
5580 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5582 Register Dst = UDivorRem.getReg(0);
5583 Register LHS = UDivorRem.getReg(1);
5584 Register RHS = UDivorRem.getReg(2);
5585 LLT Ty =
MRI.getType(Dst);
5593 bool UseSRL =
false;
5598 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5600 if (IsSplat && !Factors.
empty()) {
5607 APInt Divisor = CI->getValue();
5616 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5617 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5627 if (Ty.isVector()) {
5628 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5629 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5632 Factor = Factors[0];
5640 return MIB.buildMul(Ty, Res, Factor);
5643 unsigned KnownLeadingZeros =
5644 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5646 bool UseNPQ =
false;
5648 auto BuildUDIVPattern = [&](
const Constant *
C) {
5650 const APInt &Divisor = CI->getValue();
5652 bool SelNPQ =
false;
5654 unsigned PreShift = 0, PostShift = 0;
5659 if (!Divisor.
isOne()) {
5665 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5667 Magic = std::move(magics.
Magic);
5670 "We shouldn't generate an undefined shift!");
5672 "We shouldn't generate an undefined shift!");
5676 SelNPQ = magics.
IsAdd;
5680 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5681 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5683 MIB.buildConstant(ScalarTy,
5688 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5696 assert(Matched &&
"Expected unary predicate match to succeed");
5698 Register PreShift, PostShift, MagicFactor, NPQFactor;
5701 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5702 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5703 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5704 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5707 "Non-build_vector operation should have been a scalar");
5708 PreShift = PreShifts[0];
5709 MagicFactor = MagicFactors[0];
5710 PostShift = PostShifts[0];
5714 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5717 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5720 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5725 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5727 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5729 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5732 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5733 auto One = MIB.buildConstant(Ty, 1);
5734 auto IsOne = MIB.buildICmp(
5736 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5737 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5739 if (Opcode == TargetOpcode::G_UREM) {
5740 auto Prod = MIB.buildMul(Ty, ret, RHS);
5741 return MIB.buildSub(Ty, LHS, Prod);
5747 unsigned Opcode =
MI.getOpcode();
5748 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5751 LLT DstTy =
MRI.getType(Dst);
5753 auto &MF = *
MI.getMF();
5754 AttributeList Attr = MF.getFunction().getAttributes();
5763 if (MF.getFunction().hasMinSize())
5766 if (Opcode == TargetOpcode::G_UDIV &&
5769 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5772 auto *RHSDef =
MRI.getVRegDef(RHS);
5783 {TargetOpcode::G_ICMP,
5787 if (Opcode == TargetOpcode::G_UREM &&
5793 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5802 unsigned Opcode =
MI.getOpcode();
5803 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5806 LLT DstTy =
MRI.getType(Dst);
5810 auto &MF = *
MI.getMF();
5811 AttributeList Attr = MF.getFunction().getAttributes();
5820 if (MF.getFunction().hasMinSize())
5824 if (Opcode == TargetOpcode::G_SDIV &&
5827 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5830 auto *RHSDef =
MRI.getVRegDef(RHS);
5838 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5841 if (Opcode == TargetOpcode::G_SREM &&
5847 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5856 unsigned Opcode =
MI.getOpcode();
5857 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5858 Opcode == TargetOpcode::G_SREM);
5860 Register Dst = SDivorRem.getReg(0);
5861 Register LHS = SDivorRem.getReg(1);
5862 Register RHS = SDivorRem.getReg(2);
5863 LLT Ty =
MRI.getType(Dst);
5870 bool UseSRA =
false;
5876 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5878 if (IsSplat && !ExactFactors.
empty()) {
5880 ExactFactors.
push_back(ExactFactors[0]);
5885 APInt Divisor = CI->getValue();
5895 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5896 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5904 assert(Matched &&
"Expected unary predicate match to succeed");
5907 if (Ty.isVector()) {
5908 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5909 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5911 Shift = ExactShifts[0];
5912 Factor = ExactFactors[0];
5920 return MIB.buildMul(Ty, Res, Factor);
5925 auto BuildSDIVPattern = [&](
const Constant *
C) {
5927 const APInt &Divisor = CI->getValue();
5931 int NumeratorFactor = 0;
5942 NumeratorFactor = 1;
5945 NumeratorFactor = -1;
5948 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5949 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5951 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5952 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5960 assert(Matched &&
"Expected unary predicate match to succeed");
5962 Register MagicFactor, Factor, Shift, ShiftMask;
5965 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5966 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5967 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5968 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5971 "Non-build_vector operation should have been a scalar");
5972 MagicFactor = MagicFactors[0];
5973 Factor = Factors[0];
5975 ShiftMask = ShiftMasks[0];
5979 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5982 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5983 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5986 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5989 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5990 auto T = MIB.buildLShr(Ty, Q, SignShift);
5991 T = MIB.buildAnd(Ty,
T, ShiftMask);
5992 auto ret = MIB.buildAdd(Ty, Q,
T);
5994 if (Opcode == TargetOpcode::G_SREM) {
5995 auto Prod = MIB.buildMul(Ty, ret, RHS);
5996 return MIB.buildSub(Ty, LHS, Prod);
6002 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6003 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6004 "Expected SDIV or UDIV");
6007 auto MatchPow2 = [&](
const Constant *
C) {
6009 return CI && (CI->getValue().isPowerOf2() ||
6010 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6016 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6021 LLT Ty =
MRI.getType(Dst);
6041 unsigned BitWidth = Ty.getScalarSizeInBits();
6042 auto Zero =
Builder.buildConstant(Ty, 0);
6045 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6046 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6048 auto Sign =
Builder.buildAShr(
6052 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6058 auto One =
Builder.buildConstant(Ty, 1);
6059 auto MinusOne =
Builder.buildConstant(Ty, -1);
6063 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6064 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6068 auto Neg =
Builder.buildNeg(Ty, AShr);
6070 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6071 MI.eraseFromParent();
6075 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6080 LLT Ty =
MRI.getType(Dst);
6083 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6084 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6085 MI.eraseFromParent();
6089 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6092 LLT Ty =
MRI.getType(Dst);
6093 LLT RHSTy =
MRI.getType(RHS);
6095 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6097 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6112 LLT Ty =
MRI.getType(Dst);
6118 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6119 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6120 Builder.buildLShr(Dst, LHS, Trunc);
6121 MI.eraseFromParent();
6128 LLT DstTy =
MRI.getType(Dst);
6129 LLT SrcTy =
MRI.getType(Src);
6131 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6132 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6135 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6153 Builder.buildTruncSSatS(Dst, MatchInfo);
6154 MI.eraseFromParent();
6161 LLT DstTy =
MRI.getType(Dst);
6162 LLT SrcTy =
MRI.getType(Src);
6164 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6165 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6168 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6186 Builder.buildTruncSSatU(Dst, MatchInfo);
6187 MI.eraseFromParent();
6194 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6195 LLT SrcTy =
MRI.getType(Val);
6197 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6198 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6201 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6210 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6219 unsigned Opc =
MI.getOpcode();
6220 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6221 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6222 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6234 Opc = TargetOpcode::G_FSUB;
6239 Opc = TargetOpcode::G_FADD;
6245 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6246 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6255 MI.setDesc(
B.getTII().get(
Opc));
6256 MI.getOperand(1).setReg(
X);
6257 MI.getOperand(2).setReg(
Y);
6265 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6268 MatchInfo =
MI.getOperand(2).getReg();
6269 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6271 const auto LHSCst = Ty.isVector()
6278 if (LHSCst->Value.isNegZero())
6282 if (LHSCst->Value.isPosZero())
6292 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6299 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6313 bool &AllowFusionGlobally,
6315 bool CanReassociate)
const {
6317 auto *MF =
MI.getMF();
6318 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6320 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6328 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6331 if (!HasFMAD && !HasFMA)
6339 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6346 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6348 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6356 unsigned PreferredFusedOpcode =
6357 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6371 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6372 {LHS.MI->getOperand(1).getReg(),
6373 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6382 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6383 {RHS.MI->getOperand(1).getReg(),
6384 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6395 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6397 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6401 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6406 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6408 unsigned PreferredFusedOpcode =
6409 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6423 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6428 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6429 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6438 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6443 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6444 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6455 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6457 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6465 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6467 unsigned PreferredFusedOpcode =
6468 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6481 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6482 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6483 TargetOpcode::G_FMUL) &&
6484 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6485 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6490 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6491 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6492 TargetOpcode::G_FMUL) &&
6493 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6494 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6501 Register X = FMA->getOperand(1).getReg();
6502 Register Y = FMA->getOperand(2).getReg();
6507 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6508 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6509 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6521 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6523 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6530 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6531 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6537 unsigned PreferredFusedOpcode =
6538 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6551 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6552 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6554 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6556 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6563 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6567 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6572 LHS.MI->getOperand(1).getReg(),
6573 LHS.MI->getOperand(2).getReg(),
B);
6584 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6587 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6592 X =
B.buildFPExt(DstType,
X).getReg(0);
6593 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6604 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6608 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6613 RHS.MI->getOperand(1).getReg(),
6614 RHS.MI->getOperand(2).getReg(),
B);
6625 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6628 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6633 X =
B.buildFPExt(DstType,
X).getReg(0);
6634 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6648 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6650 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6658 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6662 int FirstMulHasFewerUses =
true;
6666 FirstMulHasFewerUses =
false;
6668 unsigned PreferredFusedOpcode =
6669 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6672 if (FirstMulHasFewerUses &&
6676 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6677 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6678 {LHS.MI->getOperand(1).getReg(),
6679 LHS.MI->getOperand(2).getReg(), NegZ});
6688 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6689 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6690 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6701 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6703 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6709 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6711 unsigned PreferredFusedOpcode =
6712 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6723 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6724 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6736 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6749 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6751 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6757 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6759 unsigned PreferredFusedOpcode =
6760 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6772 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6773 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6774 {FpExtX, FpExtY, NegZ});
6786 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6789 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6790 {NegY, FpExtZ, LHSReg});
6801 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6803 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6807 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6808 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6812 unsigned PreferredFusedOpcode =
6813 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6817 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6818 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6819 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6830 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6833 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6836 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6846 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6859 unsigned &IdxToPropagate)
const {
6861 switch (
MI.getOpcode()) {
6864 case TargetOpcode::G_FMINNUM:
6865 case TargetOpcode::G_FMAXNUM:
6866 PropagateNaN =
false;
6868 case TargetOpcode::G_FMINIMUM:
6869 case TargetOpcode::G_FMAXIMUM:
6870 PropagateNaN =
true;
6874 auto MatchNaN = [&](
unsigned Idx) {
6875 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6879 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6883 return MatchNaN(1) || MatchNaN(2);
6891 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6901 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6914 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6915 if (&U == &
MI || U.getParent() !=
MI.getParent())
6917 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6918 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6931 return MatchInfo.
size() >= MinUses;
6939 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6940 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6941 MatchInfo[0]->getOperand(2).getReg(),
6942 MatchInfo[0]->getFlags());
6947 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6948 Div->getOperand(0).getReg(),
MI->getFlags());
6949 MI->eraseFromParent();
6954 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6964 Reg == MaybeSameReg;
6966 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6987 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6996 return MRI.getType(MatchInfo) == DstVecTy;
6999 std::optional<ValueAndVReg> ShiftAmount;
7008 return MRI.getType(MatchInfo) == DstVecTy;
7023 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7030 std::optional<ValueAndVReg> ShiftAmt;
7036 LLT MatchTy =
MRI.getType(MatchInfo);
7037 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
7038 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7041unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7043 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7044 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7045 "Expected a NaN behaviour?");
7055 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7056 return TargetOpcode::G_FMAXNUM;
7057 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7058 return TargetOpcode::G_FMAXIMUM;
7059 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7060 return TargetOpcode::G_FMAXNUM;
7061 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7062 return TargetOpcode::G_FMAXIMUM;
7068 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7069 return TargetOpcode::G_FMINNUM;
7070 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7071 return TargetOpcode::G_FMINIMUM;
7072 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7073 return TargetOpcode::G_FMINNUM;
7074 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7076 return TargetOpcode::G_FMINIMUM;
7080CombinerHelper::SelectPatternNaNBehaviour
7082 bool IsOrderedComparison)
const {
7086 if (!LHSSafe && !RHSSafe)
7087 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7088 if (LHSSafe && RHSSafe)
7089 return SelectPatternNaNBehaviour::RETURNS_ANY;
7092 if (IsOrderedComparison)
7093 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7094 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7097 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7098 : SelectPatternNaNBehaviour::RETURNS_NAN;
7107 LLT DstTy =
MRI.getType(Dst);
7120 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7122 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7124 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7127 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7128 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7129 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7130 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7132 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7135 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7140 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7145 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7147 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7151 MatchInfo = [=](MachineIRBuilder &
B) {
7152 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7160 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7167 Register TrueVal =
MI.getOperand(2).getReg();
7168 Register FalseVal =
MI.getOperand(3).getReg();
7169 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7174 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7187 if (MatchedSub &&
X != OpLHS)
7195 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7198 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7199 B.buildICmp(Pred, Dst,
Y, Zero);
7206static std::optional<unsigned>
7208 std::optional<int64_t> &Result) {
7209 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7210 Opcode == TargetOpcode::G_ASHR) &&
7211 "Expect G_SHL, G_LSHR or G_ASHR.");
7212 auto SignificantBits = 0;
7214 case TargetOpcode::G_SHL:
7218 case TargetOpcode::G_LSHR:
7222 case TargetOpcode::G_ASHR:
7231 Result = std::nullopt;
7242 Register ShiftVal =
MI.getOperand(1).getReg();
7243 Register ShiftReg =
MI.getOperand(2).getReg();
7244 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7245 auto IsShiftTooBig = [&](
const Constant *
C) {
7250 MatchInfo = std::nullopt;
7254 MI.getOpcode(), MatchInfo);
7255 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7261 unsigned LHSOpndIdx = 1;
7262 unsigned RHSOpndIdx = 2;
7263 switch (
MI.getOpcode()) {
7264 case TargetOpcode::G_UADDO:
7265 case TargetOpcode::G_SADDO:
7266 case TargetOpcode::G_UMULO:
7267 case TargetOpcode::G_SMULO:
7274 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7275 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7280 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7281 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7285 return MRI.getVRegDef(RHS)->getOpcode() !=
7286 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7293 std::optional<FPValueAndVReg> ValAndVReg;
7301 unsigned LHSOpndIdx = 1;
7302 unsigned RHSOpndIdx = 2;
7303 switch (
MI.getOpcode()) {
7304 case TargetOpcode::G_UADDO:
7305 case TargetOpcode::G_SADDO:
7306 case TargetOpcode::G_UMULO:
7307 case TargetOpcode::G_SMULO:
7314 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7315 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7316 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7317 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7321bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7323 if (SrcTy.isFixedVector())
7324 return isConstantSplatVector(Src, 1, AllowUndefs);
7325 if (SrcTy.isScalar()) {
7329 return IConstant && IConstant->Value == 1;
7334bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7335 LLT SrcTy =
MRI.getType(Src);
7337 return isConstantSplatVector(Src, 0, AllowUndefs);
7342 return IConstant && IConstant->Value == 0;
7349bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7350 bool AllowUndefs)
const {
7356 for (
unsigned I = 0;
I < NumSources; ++
I) {
7357 GImplicitDef *ImplicitDef =
7359 if (ImplicitDef && AllowUndefs)
7361 if (ImplicitDef && !AllowUndefs)
7363 std::optional<ValueAndVReg> IConstant =
7365 if (IConstant && IConstant->Value == SplatValue)
7375CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7378 return IConstant->Value;
7382 return std::nullopt;
7385 std::optional<APInt>
Value = std::nullopt;
7386 for (
unsigned I = 0;
I < NumSources; ++
I) {
7387 std::optional<ValueAndVReg> IConstant =
7390 return std::nullopt;
7392 Value = IConstant->Value;
7393 else if (*
Value != IConstant->Value)
7394 return std::nullopt;
7400bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7410 for (
unsigned I = 0;
I < NumSources; ++
I) {
7411 std::optional<ValueAndVReg> IConstant =
7420bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7427 LLT CondTy =
MRI.getType(
Select->getCondReg());
7428 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7438 std::optional<ValueAndVReg> TrueOpt =
7440 std::optional<ValueAndVReg> FalseOpt =
7443 if (!TrueOpt || !FalseOpt)
7446 APInt TrueValue = TrueOpt->Value;
7447 APInt FalseValue = FalseOpt->Value;
7451 MatchInfo = [=](MachineIRBuilder &
B) {
7452 B.setInstrAndDebugLoc(*
Select);
7453 B.buildZExtOrTrunc(Dest,
Cond);
7460 MatchInfo = [=](MachineIRBuilder &
B) {
7461 B.setInstrAndDebugLoc(*
Select);
7462 B.buildSExtOrTrunc(Dest,
Cond);
7469 MatchInfo = [=](MachineIRBuilder &
B) {
7470 B.setInstrAndDebugLoc(*
Select);
7471 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7472 B.buildNot(Inner,
Cond);
7473 B.buildZExtOrTrunc(Dest, Inner);
7480 MatchInfo = [=](MachineIRBuilder &
B) {
7481 B.setInstrAndDebugLoc(*
Select);
7482 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7483 B.buildNot(Inner,
Cond);
7484 B.buildSExtOrTrunc(Dest, Inner);
7490 if (TrueValue - 1 == FalseValue) {
7491 MatchInfo = [=](MachineIRBuilder &
B) {
7492 B.setInstrAndDebugLoc(*
Select);
7493 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7494 B.buildZExtOrTrunc(Inner,
Cond);
7495 B.buildAdd(Dest, Inner, False);
7501 if (TrueValue + 1 == FalseValue) {
7502 MatchInfo = [=](MachineIRBuilder &
B) {
7503 B.setInstrAndDebugLoc(*
Select);
7504 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7505 B.buildSExtOrTrunc(Inner,
Cond);
7506 B.buildAdd(Dest, Inner, False);
7513 MatchInfo = [=](MachineIRBuilder &
B) {
7514 B.setInstrAndDebugLoc(*
Select);
7515 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7516 B.buildZExtOrTrunc(Inner,
Cond);
7519 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7520 B.buildShl(Dest, Inner, ShAmtC, Flags);
7527 MatchInfo = [=](MachineIRBuilder &
B) {
7528 B.setInstrAndDebugLoc(*
Select);
7530 B.buildNot(Not,
Cond);
7531 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7532 B.buildZExtOrTrunc(Inner, Not);
7535 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7536 B.buildShl(Dest, Inner, ShAmtC, Flags);
7543 MatchInfo = [=](MachineIRBuilder &
B) {
7544 B.setInstrAndDebugLoc(*
Select);
7545 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7546 B.buildSExtOrTrunc(Inner,
Cond);
7547 B.buildOr(Dest, Inner, False, Flags);
7554 MatchInfo = [=](MachineIRBuilder &
B) {
7555 B.setInstrAndDebugLoc(*
Select);
7557 B.buildNot(Not,
Cond);
7558 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7559 B.buildSExtOrTrunc(Inner, Not);
7560 B.buildOr(Dest, Inner, True, Flags);
7569bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7576 LLT CondTy =
MRI.getType(
Select->getCondReg());
7577 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7586 if (CondTy != TrueTy)
7591 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7592 MatchInfo = [=](MachineIRBuilder &
B) {
7593 B.setInstrAndDebugLoc(*
Select);
7594 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7595 B.buildZExtOrTrunc(Ext,
Cond);
7596 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7597 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7604 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7605 MatchInfo = [=](MachineIRBuilder &
B) {
7606 B.setInstrAndDebugLoc(*
Select);
7607 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7608 B.buildZExtOrTrunc(Ext,
Cond);
7609 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7610 B.buildAnd(DstReg, Ext, FreezeTrue);
7616 if (isOneOrOneSplat(False,
true)) {
7617 MatchInfo = [=](MachineIRBuilder &
B) {
7618 B.setInstrAndDebugLoc(*
Select);
7620 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7621 B.buildNot(Inner,
Cond);
7623 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7624 B.buildZExtOrTrunc(Ext, Inner);
7625 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7626 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7632 if (isZeroOrZeroSplat(True,
true)) {
7633 MatchInfo = [=](MachineIRBuilder &
B) {
7634 B.setInstrAndDebugLoc(*
Select);
7636 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7637 B.buildNot(Inner,
Cond);
7639 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7640 B.buildZExtOrTrunc(Ext, Inner);
7641 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7642 B.buildAnd(DstReg, Ext, FreezeFalse);
7658 LLT DstTy =
MRI.getType(DstReg);
7664 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7673 Register CmpLHS = Cmp->getLHSReg();
7674 Register CmpRHS = Cmp->getRHSReg();
7677 if (True == CmpRHS && False == CmpLHS) {
7685 if (True != CmpLHS || False != CmpRHS)
7725 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7726 Register DestReg =
MI.getOperand(0).getReg();
7727 LLT DestTy =
MRI.getType(DestReg);
7739 if (
isLegal({NewOpc, {DestTy}})) {
7741 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7753 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7756 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7766bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7768 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7769 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7773 unsigned Flags = Logic->
getFlags();
7792 std::optional<ValueAndVReg> MaybeC1 =
7796 C1 = MaybeC1->Value;
7798 std::optional<ValueAndVReg> MaybeC2 =
7802 C2 = MaybeC2->Value;
7823 std::optional<APInt> Offset1;
7824 std::optional<APInt> Offset2;
7827 std::optional<ValueAndVReg> MaybeOffset1 =
7830 R1 =
Add->getLHSReg();
7831 Offset1 = MaybeOffset1->Value;
7835 std::optional<ValueAndVReg> MaybeOffset2 =
7838 R2 =
Add->getLHSReg();
7839 Offset2 = MaybeOffset2->Value;
7858 bool CreateMask =
false;
7871 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7884 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7893 MatchInfo = [=](MachineIRBuilder &
B) {
7894 if (CreateMask &&
Offset != 0) {
7895 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7896 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7897 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7898 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7899 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7900 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7901 B.buildZExtOrTrunc(DstReg, ICmp);
7902 }
else if (CreateMask &&
Offset == 0) {
7903 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7904 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7905 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7906 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7907 B.buildZExtOrTrunc(DstReg, ICmp);
7908 }
else if (!CreateMask &&
Offset != 0) {
7909 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7910 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7911 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7912 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7913 B.buildZExtOrTrunc(DstReg, ICmp);
7914 }
else if (!CreateMask &&
Offset == 0) {
7915 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7916 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7917 B.buildZExtOrTrunc(DstReg, ICmp);
7925bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7931 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7943 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7949 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7950 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7951 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7952 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7963 if (LHS0 == RHS1 && LHS1 == RHS0) {
7969 if (LHS0 == RHS0 && LHS1 == RHS1) {
7973 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7975 MatchInfo = [=](MachineIRBuilder &
B) {
7980 auto False =
B.buildConstant(CmpTy, 0);
7981 B.buildZExtOrTrunc(DestReg, False);
7988 B.buildZExtOrTrunc(DestReg, True);
7990 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7991 B.buildZExtOrTrunc(DestReg, Cmp);
8003 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8006 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8015 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8018 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8033 bool IsSigned =
Add->isSigned();
8034 LLT DstTy =
MRI.getType(Dst);
8035 LLT CarryTy =
MRI.getType(Carry);
8038 if (
MRI.use_nodbg_empty(Carry) &&
8041 B.buildAdd(Dst, LHS, RHS);
8042 B.buildUndef(Carry);
8048 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8051 B.buildSAddo(Dst, Carry, RHS, LHS);
8057 B.buildUAddo(Dst, Carry, RHS, LHS);
8062 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8063 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8069 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8070 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8072 B.buildConstant(Dst, Result);
8073 B.buildConstant(Carry, Overflow);
8081 B.buildCopy(Dst, LHS);
8082 B.buildConstant(Carry, 0);
8091 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8094 std::optional<APInt> MaybeAddRHS =
8095 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8098 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8099 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8103 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8104 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8110 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8111 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8136 B.buildConstant(Carry, 0);
8143 B.buildAdd(Dst, LHS, RHS);
8144 B.buildConstant(Carry, 1);
8156 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8159 B.buildConstant(Carry, 0);
8175 B.buildConstant(Carry, 0);
8182 B.buildAdd(Dst, LHS, RHS);
8183 B.buildConstant(Carry, 1);
8201 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8207 auto [Dst,
Base] =
MI.getFirst2Regs();
8208 LLT Ty =
MRI.getType(Dst);
8212 Builder.buildFConstant(Dst, 1.0);
8213 MI.removeFromParent();
8225 std::optional<SrcOp> Res;
8227 while (ExpVal > 0) {
8232 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8235 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8242 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8246 MI.eraseFromParent();
8255 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8262 LLT DstTy =
MRI.getType(Dst);
8265 auto Const =
B.buildConstant(DstTy, C1 - C2);
8266 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8278 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8285 LLT DstTy =
MRI.getType(Dst);
8288 auto Const =
B.buildConstant(DstTy, C2 - C1);
8289 B.buildSub(Dst, Const,
Add->getLHSReg());
8301 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8308 LLT DstTy =
MRI.getType(Dst);
8311 auto Const =
B.buildConstant(DstTy, C1 + C2);
8324 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8331 LLT DstTy =
MRI.getType(Dst);
8334 auto Const =
B.buildConstant(DstTy, C1 - C2);
8347 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8354 LLT DstTy =
MRI.getType(Dst);
8357 auto Const =
B.buildConstant(DstTy, C2 - C1);
8358 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8405 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8409 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8412 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8413 LLT SmallBvTy = DstTy;
8417 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8422 {TargetOpcode::G_ANYEXT,
8434 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8435 Ops.push_back(AnyExt.getReg(0));
8453 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8454 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8455 const unsigned NumDstElts = OrigMask.
size();
8456 for (
unsigned i = 0; i != NumDstElts; ++i) {
8457 int Idx = OrigMask[i];
8458 if (Idx >= (
int)NumSrcElems) {
8469 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8470 std::move(NewMask));
8477 const unsigned MaskSize = Mask.size();
8478 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8483 if (Idx < (
int)NumElems)
8484 Mask[
I] = Idx + NumElems;
8486 Mask[
I] = Idx - NumElems;
8496 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8499 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8502 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8503 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8505 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8509 const unsigned NumSrcElems = Src1Ty.getNumElements();
8511 bool TouchesSrc1 =
false;
8512 bool TouchesSrc2 =
false;
8513 const unsigned NumElems = Mask.size();
8514 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8518 if (Mask[Idx] < (
int)NumSrcElems)
8524 if (TouchesSrc1 == TouchesSrc2)
8527 Register NewSrc1 = Shuffle.getSrc1Reg();
8530 NewSrc1 = Shuffle.getSrc2Reg();
8535 auto Undef =
B.buildUndef(Src1Ty);
8536 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8550 LLT DstTy =
MRI.getType(Dst);
8551 LLT CarryTy =
MRI.getType(Carry);
8573 B.buildConstant(Carry, 0);
8580 B.buildSub(Dst, LHS, RHS);
8598 B.buildConstant(Carry, 0);
8605 B.buildSub(Dst, LHS, RHS);
8622 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8623 "Expected G_CTLZ variant");
8628 LLT Ty =
MRI.getType(Dst);
8629 LLT SrcTy =
MRI.getType(Src);
8631 if (!(Ty.isValid() && Ty.isScalar()))
8640 switch (
LI->getAction(Query).Action) {
8651 bool NeedAdd =
true;
8659 unsigned BitWidth = Ty.getScalarSizeInBits();
8670 B.buildCTLS(Dst,
X);
8674 auto Ctls =
B.buildCTLS(Ty,
X);
8675 auto One =
B.buildConstant(Ty, 1);
8677 B.buildAdd(Dst, Ctls, One);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static std::optional< unsigned > getMinUselessShift(KnownBits ValueKB, unsigned Opcode, std::optional< int64_t > &Result)
Return the minimum useless shift amount that results in complete loss of the source value.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Interface for Targets to specify which operations they can successfully select and how the others sho...
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
static LLVM_ABI bool isEquality(Predicate pred)
Determine if this is an equals/not equals predicate.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
static LLVM_ABI bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
void applyPtrAddZero(MachineInstr &MI) const
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
void applyUDivOrURemByConst(MachineInstr &MI) const
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchPtrAddZero(MachineInstr &MI) const
}
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
bool matchShiftsTooBig(MachineInstr &MI, std::optional< int64_t > &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
const DataLayout & getDataLayout() const
bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
void applyUMulHToLShr(MachineInstr &MI) const
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
bool isLegalOrHasFewerElements(const LegalityQuery &Query) const
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
const TargetLowering & getTargetLowering() const
bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
void applySDivByPow2(MachineInstr &MI) const
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
bool tryEmitMemcpyInline(MachineInstr &MI) const
Emit loads and stores that perform the given memcpy.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
void applyCombineCopy(MachineInstr &MI) const
bool matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
bool matchSextTruncSextLoad(MachineInstr &MI) const
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchCombineCopy(MachineInstr &MI) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
bool matchRedundantSExtInReg(MachineInstr &MI) const
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
bool tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool isPreLegalize() const
bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is known to be a power of 2.
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVMContext & getContext() const
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
bool isLegal(const LegalityQuery &Query) const
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
void eraseInst(MachineInstr &MI) const
Erase MI.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
bool matchConstantFPOp(const MachineOperand &MOP, double C) const
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
bool tryCombineShuffleVector(MachineInstr &MI) const
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
void applyFunnelShiftToRotate(MachineInstr &MI) const
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
bool matchBinopWithNeg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold a bitwiseop (~b +/- c) -> a bitwiseop ~(b -/+ c)
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal) const
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applySDivOrSRemByConst(MachineInstr &MI) const
MachineInstr * buildSDivOrSRemUsingMul(MachineInstr &MI) const
Given an G_SDIV MI or G_SREM MI expressing a signed divide by constant, return an expression that imp...
bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
void applyCommuteBinOpOperands(MachineInstr &MI) const
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
void applySextTruncSextLoad(MachineInstr &MI) const
const MachineFunction & getMachineFunction() const
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Abstract class that contains various methods for clients to notify about changes.
Simple wrapper observer that takes several observers, and calls each one for each event.
Represents any type of generic load or store.
Register getPointerReg() const
Get the source register of the pointer value.
Represents a logical binary operation.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
bool isAtomic() const
Returns true if the attached MachineMemOperand has the atomic flag set.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
bool isSimple() const
Returns true if the memory operation is neither atomic or volatile.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
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...
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
static use_instr_nodbg_iterator use_instr_nodbg_end()
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual bool isTruncateFree(Type *FromTy, Type *ToTy) const
Return true if it's free to truncate a value of type FromTy to type ToTy.
virtual LLVM_READONLY LLT getPreferredShiftAmountTy(LLT ShiftValueTy) const
Return the preferred type to use for a shift opcode, given the shifted amount type is ShiftValueTy.
bool isBeneficialToExpandPowI(int64_t Exponent, bool OptForSize) const
Return true if it is beneficial to expand an @llvm.powi.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual unsigned combineRepeatedFPDivisors() const
Indicate whether this target prefers to combine FDIVs with the same divisor.
virtual const TargetLowering * getTargetLowering() const
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
@ Custom
The target wants to do something special with this combination of operand and type.
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(const APInt &RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false > m_GBuildVectorTrunc(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP, true > m_c_GICmp(const Pred &P, const LHS &L, const RHS &R)
G_ICMP matcher that also matches commuted compares.
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
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...