46#define DEBUG_TYPE "gi-combiner"
55 cl::desc(
"Force all indexed operations to be "
56 "legal for the GlobalISel combiner"));
65 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
66 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
71 return *
Builder.getMF().getSubtarget().getTargetLowering();
89 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
97 LLT Ty = MRI.getType(V);
108 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
109 return ByteWidth -
I - 1;
129static std::optional<bool>
133 unsigned Width = MemOffset2Idx.
size();
136 bool BigEndian =
true, LittleEndian =
true;
137 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
138 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
139 if (MemOffsetAndIdx == MemOffset2Idx.
end())
141 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
142 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
145 if (!BigEndian && !LittleEndian)
149 assert((BigEndian != LittleEndian) &&
150 "Pattern cannot be both big and little endian!");
157 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
185 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
186 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
193 if (
MRI.constrainRegAttrs(ToReg, FromReg))
194 MRI.replaceRegWith(FromReg, ToReg);
196 Builder.buildCopy(FromReg, ToReg);
198 Observer.finishedChangingAllUsesOfReg();
213 unsigned ToOpcode)
const {
228 MRI.setRegBank(Reg, *RegBank);
239 if (
MI.getOpcode() != TargetOpcode::COPY)
249 MI.eraseFromParent();
258 if (!
MRI.hasOneNonDBGUse(OrigOp))
277 std::optional<MachineOperand> MaybePoisonOperand;
279 if (!Operand.isReg())
285 if (!MaybePoisonOperand)
286 MaybePoisonOperand = Operand;
295 if (!MaybePoisonOperand) {
300 B.buildCopy(
DstOp, OrigOp);
305 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
306 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
313 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
324 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
325 "Invalid instruction");
335 assert(Def &&
"Operand not defined");
336 if (!
MRI.hasOneNonDBGUse(Reg))
338 switch (Def->getOpcode()) {
339 case TargetOpcode::G_BUILD_VECTOR:
344 Ops.push_back(BuildVecMO.getReg());
346 case TargetOpcode::G_IMPLICIT_DEF: {
347 LLT OpType =
MRI.getType(Reg);
354 OpType.getScalarType() &&
355 "All undefs should have the same type");
358 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
359 EltIdx != EltEnd; ++EltIdx)
360 Ops.push_back(
Undef->getOperand(0).getReg());
369 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
371 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
386 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
399 MI.eraseFromParent();
405 Register SrcVec1 = Shuffle.getSrc1Reg();
406 Register SrcVec2 = Shuffle.getSrc2Reg();
407 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
408 int Width =
MRI.getType(SrcVec1).getNumElements();
410 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
411 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
415 for (
int Val : Shuffle.getMask()) {
418 else if (Val < Width)
419 Extracts.
push_back(Unmerge1.getReg(Val));
421 Extracts.
push_back(Unmerge2.getReg(Val - Width));
423 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
424 if (Extracts.
size() == 1)
425 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
427 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
428 MI.eraseFromParent();
438 if (!ConcatMI1 || !ConcatMI2)
442 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
443 MRI.getType(ConcatMI2->getSourceReg(0)))
446 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
447 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
449 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
453 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
454 if (i + j >= Mask.size())
456 if (Mask[i + j] != -1)
460 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
463 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
464 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
465 if (i + j >= Mask.size())
467 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
473 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
475 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
476 ConcatMI1->getNumSources()));
484 {TargetOpcode::G_CONCAT_VECTORS,
485 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
496 SrcTy =
MRI.getType(Reg);
498 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
505 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
511 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
514 MI.eraseFromParent();
528 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
529 "Invalid instruction kind");
530 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
532 LLT SrcType =
MRI.getType(Src1);
534 unsigned DstNumElts = DstType.getNumElements();
535 unsigned SrcNumElts = SrcType.getNumElements();
552 if (DstNumElts < 2 * SrcNumElts)
557 if (DstNumElts % SrcNumElts != 0)
563 unsigned NumConcat = DstNumElts / SrcNumElts;
566 for (
unsigned i = 0; i != DstNumElts; ++i) {
573 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
574 (ConcatSrcs[i / SrcNumElts] >= 0 &&
575 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
578 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
585 for (
auto Src : ConcatSrcs) {
589 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
591 Ops.push_back(UndefReg);
604 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
612 MI.eraseFromParent();
621 const LLT TyForCandidate,
622 unsigned OpcodeForCandidate,
627 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
638 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
641 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
642 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
643 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
651 OpcodeForCandidate == TargetOpcode::G_ZEXT)
653 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
654 OpcodeForCandidate == TargetOpcode::G_SEXT)
655 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
664 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
675static void InsertInsnsWithoutSideEffectsBeforeUse(
687 InsertBB = PredBB->
getMBB();
692 if (InsertBB ==
DefMI.getParent()) {
694 Inserter(InsertBB, std::next(InsertPt), UseMO);
713 unsigned CandidateLoadOpc;
715 case TargetOpcode::G_ANYEXT:
716 CandidateLoadOpc = TargetOpcode::G_LOAD;
718 case TargetOpcode::G_SEXT:
719 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
721 case TargetOpcode::G_ZEXT:
722 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
727 return CandidateLoadOpc;
744 LLT LoadValueTy =
MRI.getType(LoadReg);
766 unsigned PreferredOpcode =
768 ? TargetOpcode::G_ANYEXT
770 Preferred = {
LLT(), PreferredOpcode,
nullptr};
771 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
772 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
773 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
774 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
775 const auto &MMO = LoadMI->
getMMO();
783 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
785 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
789 Preferred = ChoosePreferredUse(
MI, Preferred,
790 MRI.getType(
UseMI.getOperand(0).getReg()),
800 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
818 if (PreviouslyEmitted) {
825 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
826 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
828 EmittedInsns[InsertIntoBB] = NewMI;
834 MI.setDesc(
Builder.getTII().get(LoadOpc));
841 for (
auto *UseMO :
Uses) {
847 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
850 const LLT UseDstTy =
MRI.getType(UseDstReg);
851 if (UseDstReg != ChosenDstReg) {
852 if (Preferred.
Ty == UseDstTy) {
889 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
904 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
907 MI.getOperand(0).setReg(ChosenDstReg);
913 assert(
MI.getOpcode() == TargetOpcode::G_AND);
924 if (
MRI.getType(Dst).isVector())
932 APInt MaskVal = MaybeMask->Value;
941 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
945 LLT RegTy =
MRI.getType(LoadReg);
953 if (MaskSizeBits > LoadSizeBits.
getValue())
973 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
979 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
983 B.setInstrAndDebugLoc(*LoadMI);
984 auto &MF =
B.getMF();
986 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
987 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
996 "shouldn't consider debug uses");
1004 if (DefOrUse ==
MBB.end())
1006 return &*DefOrUse == &
DefMI;
1012 "shouldn't consider debug uses");
1015 else if (
DefMI.getParent() !=
UseMI.getParent())
1022 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1026 if (
MRI.getType(SrcReg).isVector())
1031 LoadUser = TruncSrc;
1033 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1038 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1040 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1042 if (LoadSizeBits == SizeInBits)
1049 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1050 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1051 MI.eraseFromParent();
1055 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1056 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1059 LLT RegTy =
MRI.getType(DstReg);
1067 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1070 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1075 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1078 if (NewSizeBits < 8)
1090 if (LoadDef->isSimple())
1092 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1097 {
MRI.getType(LoadDef->getDstReg()),
1098 MRI.getType(LoadDef->getPointerReg())},
1102 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1107 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1108 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1110 unsigned ScalarSizeBits;
1111 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1120 auto &MMO = LoadDef->
getMMO();
1121 Builder.setInstrAndDebugLoc(*LoadDef);
1123 auto PtrInfo = MMO.getPointerInfo();
1124 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1125 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1127 MI.eraseFromParent();
1138 auto *MF =
MI->getMF();
1145 AM.
BaseOffs = CstOff->getSExtValue();
1150 MF->getDataLayout(), AM,
1152 MF->getFunction().getContext()),
1153 MI->getMMO().getAddrSpace());
1158 case TargetOpcode::G_LOAD:
1159 return TargetOpcode::G_INDEXED_LOAD;
1160 case TargetOpcode::G_STORE:
1161 return TargetOpcode::G_INDEXED_STORE;
1162 case TargetOpcode::G_ZEXTLOAD:
1163 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1164 case TargetOpcode::G_SEXTLOAD:
1165 return TargetOpcode::G_INDEXED_SEXTLOAD;
1171bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1181 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1182 OpTys = {PtrTy, Ty, Ty};
1184 OpTys = {Ty, PtrTy};
1186 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1192 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1193 "considered for post-indexing."));
1197 bool &RematOffset)
const {
1210 if (!isIndexedLoadStoreLegal(LdSt))
1219 unsigned NumUsesChecked = 0;
1232 if (StoredValDef == &
Use)
1235 Offset = PtrAdd->getOffsetReg();
1237 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1243 RematOffset =
false;
1247 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1252 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1253 if (&BasePtrUse == PtrDef)
1259 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1261 isIndexedLoadStoreLegal(*BasePtrLdSt))
1267 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1268 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1271 if (BaseUseUse.getParent() != LdSt.
getParent())
1283 Addr = PtrAdd->getReg(0);
1284 Base = PtrAdd->getBaseReg();
1299 MRI.hasOneNonDBGUse(Addr))
1306 if (!isIndexedLoadStoreLegal(LdSt))
1310 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1315 if (
Base == St->getValueReg())
1320 if (St->getValueReg() == Addr)
1325 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1326 if (AddrUse.getParent() != LdSt.
getParent())
1331 bool RealUse =
false;
1332 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1350 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1360 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1367 if (!LoadMI->isSimple())
1379 const unsigned MaxIter = 20;
1382 if (
II->isLoadFoldBarrier())
1384 if (Iter++ == MaxIter)
1400 int Elt = CVal->getZExtValue();
1413 Register VecPtr = LoadMI->getPointerReg();
1414 LLT PtrTy =
MRI.getType(VecPtr);
1422 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1445 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1460 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1462 if (!MatchInfo.
IsPre &&
1463 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1473 unsigned Opcode =
MI.getOpcode();
1474 bool IsStore = Opcode == TargetOpcode::G_STORE;
1480 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1482 *OldCst->getOperand(1).getCImm());
1483 MatchInfo.
Offset = NewCst.getReg(0);
1486 auto MIB =
Builder.buildInstr(NewOpcode);
1488 MIB.addDef(MatchInfo.
Addr);
1489 MIB.addUse(
MI.getOperand(0).getReg());
1491 MIB.addDef(
MI.getOperand(0).getReg());
1492 MIB.addDef(MatchInfo.
Addr);
1495 MIB.addUse(MatchInfo.
Base);
1496 MIB.addUse(MatchInfo.
Offset);
1497 MIB.addImm(MatchInfo.
IsPre);
1498 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1499 MI.eraseFromParent();
1507 unsigned Opcode =
MI.getOpcode();
1508 bool IsDiv, IsSigned;
1513 case TargetOpcode::G_SDIV:
1514 case TargetOpcode::G_UDIV: {
1516 IsSigned = Opcode == TargetOpcode::G_SDIV;
1519 case TargetOpcode::G_SREM:
1520 case TargetOpcode::G_UREM: {
1522 IsSigned = Opcode == TargetOpcode::G_SREM;
1528 unsigned DivOpcode, RemOpcode, DivremOpcode;
1530 DivOpcode = TargetOpcode::G_SDIV;
1531 RemOpcode = TargetOpcode::G_SREM;
1532 DivremOpcode = TargetOpcode::G_SDIVREM;
1534 DivOpcode = TargetOpcode::G_UDIV;
1535 RemOpcode = TargetOpcode::G_UREM;
1536 DivremOpcode = TargetOpcode::G_UDIVREM;
1554 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1555 if (
MI.getParent() ==
UseMI.getParent() &&
1556 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1557 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1570 unsigned Opcode =
MI.getOpcode();
1571 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1574 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1575 DestDivReg =
MI.getOperand(0).getReg();
1579 DestRemReg =
MI.getOperand(0).getReg();
1583 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1590 Builder.setInstrAndDebugLoc(*FirstInst);
1592 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1593 : TargetOpcode::G_UDIVREM,
1594 {DestDivReg, DestRemReg},
1596 MI.eraseFromParent();
1602 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1619 if (BrIt ==
MBB->begin())
1621 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1623 BrCond = &*std::prev(BrIt);
1624 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1630 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1631 MBB->isLayoutSuccessor(BrCondTarget);
1637 Builder.setInstrAndDebugLoc(*BrCond);
1642 auto True =
Builder.buildConstant(
1648 MI.getOperand(0).setMBB(FallthroughBB);
1663 return Helper.lowerMemcpyInline(
MI) ==
1668 unsigned MaxLen)
const {
1680 switch (
MI.getOpcode()) {
1683 case TargetOpcode::G_FNEG: {
1684 Result.changeSign();
1687 case TargetOpcode::G_FABS: {
1691 case TargetOpcode::G_FCEIL:
1694 case TargetOpcode::G_FFLOOR:
1697 case TargetOpcode::G_INTRINSIC_TRUNC:
1700 case TargetOpcode::G_INTRINSIC_ROUND:
1703 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1706 case TargetOpcode::G_FRINT:
1707 case TargetOpcode::G_FNEARBYINT:
1711 case TargetOpcode::G_FPEXT:
1712 case TargetOpcode::G_FPTRUNC: {
1719 case TargetOpcode::G_FSQRT: {
1723 Result =
APFloat(sqrt(Result.convertToDouble()));
1726 case TargetOpcode::G_FLOG2: {
1746 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1747 MI.eraseFromParent();
1758 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1768 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1781 Type *AccessTy =
nullptr;
1782 auto &MF = *
MI.getMF();
1783 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1786 MF.getFunction().getContext());
1791 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1796 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1798 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1799 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1800 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1801 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1810 unsigned PtrAddFlags =
MI.getFlags();
1811 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1827 MatchInfo.
Flags = Flags;
1833 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1835 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1839 MI.getOperand(1).setReg(MatchInfo.
Base);
1840 MI.getOperand(2).setReg(NewOffset.getReg(0));
1854 unsigned Opcode =
MI.getOpcode();
1855 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1856 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1857 Opcode == TargetOpcode::G_USHLSAT) &&
1858 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1878 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1883 if (Opcode == TargetOpcode::G_USHLSAT &&
1884 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1892 unsigned Opcode =
MI.getOpcode();
1893 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1894 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1895 Opcode == TargetOpcode::G_USHLSAT) &&
1896 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1898 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1899 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1900 auto Imm = MatchInfo.
Imm;
1902 if (Imm >= ScalarSizeInBits) {
1904 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1905 Builder.buildConstant(
MI.getOperand(0), 0);
1906 MI.eraseFromParent();
1911 Imm = ScalarSizeInBits - 1;
1914 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1917 MI.getOperand(1).setReg(MatchInfo.
Reg);
1918 MI.getOperand(2).setReg(NewImm);
1934 unsigned ShiftOpcode =
MI.getOpcode();
1935 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1936 ShiftOpcode == TargetOpcode::G_ASHR ||
1937 ShiftOpcode == TargetOpcode::G_LSHR ||
1938 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1939 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1940 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1943 Register LogicDest =
MI.getOperand(1).getReg();
1944 if (!
MRI.hasOneNonDBGUse(LogicDest))
1948 unsigned LogicOpcode = LogicMI->
getOpcode();
1949 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1950 LogicOpcode != TargetOpcode::G_XOR)
1954 const Register C1 =
MI.getOperand(2).getReg();
1956 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1959 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1963 if (
MI->getOpcode() != ShiftOpcode ||
1964 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1973 ShiftVal = MaybeImmVal->Value.getSExtValue();
1984 if (matchFirstShift(LogicMIOp1, C0Val)) {
1986 MatchInfo.
Shift2 = LogicMIOp1;
1987 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1989 MatchInfo.
Shift2 = LogicMIOp2;
1993 MatchInfo.
ValSum = C0Val + C1Val;
1996 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
1999 MatchInfo.
Logic = LogicMI;
2005 unsigned Opcode =
MI.getOpcode();
2006 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2007 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2008 Opcode == TargetOpcode::G_SSHLSAT) &&
2009 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2011 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2012 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2018 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2027 Register Shift2Const =
MI.getOperand(2).getReg();
2029 .buildInstr(Opcode, {DestType},
2039 MI.eraseFromParent();
2044 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2066 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2067 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2068 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2069 LLT SrcTy =
MRI.getType(SrcReg);
2071 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2072 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2073 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2081 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2085 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2100 LLT InnerShiftTy =
MRI.getType(InnerShift);
2102 if ((N1C + N001C).ult(InnerShiftSize)) {
2108 if ((N001C + OpSizeInBits) == InnerShiftSize)
2110 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2111 MatchInfo.
Mask =
true;
2121 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2128 if (MatchInfo.
Mask ==
true) {
2136 Builder.buildTrunc(Dst, Shift);
2137 MI.eraseFromParent();
2141 unsigned &ShiftVal)
const {
2142 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2148 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2149 return (
static_cast<int32_t
>(ShiftVal) != -1);
2153 unsigned &ShiftVal)
const {
2154 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2156 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2159 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2160 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2181 auto NegCst =
B.buildConstant(Ty, -Imm);
2183 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2184 MI.getOperand(2).setReg(NegCst.getReg(0));
2186 if (Imm.isMinSignedValue())
2196 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2211 if (!MaybeShiftAmtVal)
2215 LLT SrcTy =
MRI.getType(ExtSrc);
2225 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2226 MatchData.
Reg = ExtSrc;
2227 MatchData.
Imm = ShiftAmt;
2229 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2230 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2231 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2237 int64_t ShiftAmtVal = MatchData.
Imm;
2239 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2240 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2242 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2243 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2244 MI.eraseFromParent();
2251 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2255 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2258 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2259 if (MergedValues[
I] != Unmerge->getReg(
I))
2262 MatchInfo = Unmerge->getSourceReg();
2276 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2277 "Expected an unmerge");
2286 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2287 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2289 if (SrcMergeTy != Dst0Ty && !SameSize)
2293 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2294 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2300 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2301 "Expected an unmerge");
2303 "Not enough operands to replace all defs");
2304 unsigned NumElems =
MI.getNumOperands() - 1;
2306 LLT SrcTy =
MRI.getType(Operands[0]);
2307 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2308 bool CanReuseInputDirectly = DstTy == SrcTy;
2309 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2310 Register DstReg =
MI.getOperand(Idx).getReg();
2315 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2316 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2317 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2318 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2321 if (CanReuseInputDirectly)
2324 Builder.buildCast(DstReg, SrcReg);
2326 MI.eraseFromParent();
2331 unsigned SrcIdx =
MI.getNumOperands() - 1;
2332 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2334 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2335 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2343 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2346 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2348 Val = Val.
lshr(ShiftAmt);
2356 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2357 "Expected an unmerge");
2359 "Not enough operands to replace all defs");
2360 unsigned NumElems =
MI.getNumOperands() - 1;
2361 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2362 Register DstReg =
MI.getOperand(Idx).getReg();
2363 Builder.buildConstant(DstReg, Csts[Idx]);
2366 MI.eraseFromParent();
2372 unsigned SrcIdx =
MI.getNumOperands() - 1;
2373 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2375 unsigned NumElems =
MI.getNumOperands() - 1;
2376 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2377 Register DstReg =
MI.getOperand(Idx).getReg();
2378 B.buildUndef(DstReg);
2386 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2387 "Expected an unmerge");
2388 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2389 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2392 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2393 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2401 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2402 Register Dst0Reg =
MI.getOperand(0).getReg();
2403 Builder.buildTrunc(Dst0Reg, SrcReg);
2404 MI.eraseFromParent();
2408 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2409 "Expected an unmerge");
2410 Register Dst0Reg =
MI.getOperand(0).getReg();
2411 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2417 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2418 LLT SrcTy =
MRI.getType(SrcReg);
2419 if (SrcTy.isVector())
2429 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2434 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2435 "Expected an unmerge");
2437 Register Dst0Reg =
MI.getOperand(0).getReg();
2440 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2442 "Expecting a G_ZEXT");
2445 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2446 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2449 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2452 "ZExt src doesn't fit in destination");
2457 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2459 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2462 MI.eraseFromParent();
2466 unsigned TargetShiftSize,
2467 unsigned &ShiftVal)
const {
2468 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2469 MI.getOpcode() == TargetOpcode::G_LSHR ||
2470 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2472 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2477 unsigned Size = Ty.getSizeInBits();
2478 if (
Size <= TargetShiftSize)
2486 ShiftVal = MaybeImmVal->Value.getSExtValue();
2487 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2494 LLT Ty =
MRI.getType(SrcReg);
2495 unsigned Size = Ty.getSizeInBits();
2496 unsigned HalfSize =
Size / 2;
2497 assert(ShiftVal >= HalfSize);
2501 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2502 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2504 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2505 Register Narrowed = Unmerge.getReg(1);
2512 if (NarrowShiftAmt != 0) {
2513 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2514 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2517 auto Zero =
Builder.buildConstant(HalfTy, 0);
2518 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2519 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2520 Register Narrowed = Unmerge.getReg(0);
2525 if (NarrowShiftAmt != 0) {
2526 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2527 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2530 auto Zero =
Builder.buildConstant(HalfTy, 0);
2531 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2533 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2535 HalfTy, Unmerge.getReg(1),
2536 Builder.buildConstant(HalfTy, HalfSize - 1));
2538 if (ShiftVal == HalfSize) {
2541 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2542 }
else if (ShiftVal ==
Size - 1) {
2550 HalfTy, Unmerge.getReg(1),
2551 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2559 MI.eraseFromParent();
2575 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2577 LLT DstTy =
MRI.getType(DstReg);
2585 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2587 Builder.buildCopy(DstReg, Reg);
2588 MI.eraseFromParent();
2593 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2595 Builder.buildZExtOrTrunc(DstReg, Reg);
2596 MI.eraseFromParent();
2601 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2604 LLT IntTy =
MRI.getType(LHS);
2608 PtrReg.second =
false;
2609 for (
Register SrcReg : {LHS, RHS}) {
2613 LLT PtrTy =
MRI.getType(PtrReg.first);
2618 PtrReg.second =
true;
2630 const bool DoCommute = PtrReg.second;
2635 LLT PtrTy =
MRI.getType(LHS);
2637 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2638 Builder.buildPtrToInt(Dst, PtrAdd);
2639 MI.eraseFromParent();
2643 APInt &NewCst)
const {
2645 Register LHS = PtrAdd.getBaseReg();
2646 Register RHS = PtrAdd.getOffsetReg();
2652 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2655 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2664 APInt &NewCst)
const {
2668 Builder.buildConstant(Dst, NewCst);
2669 PtrAdd.eraseFromParent();
2674 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2679 SrcReg = OriginalSrcReg;
2680 LLT DstTy =
MRI.getType(DstReg);
2688 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2691 LLT DstTy =
MRI.getType(DstReg);
2696 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2697 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2707 if (ShiftSize > 32 && TruncSize < 32)
2720 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2721 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2725 if (!
MRI.hasOneNonDBGUse(SrcReg))
2728 LLT SrcTy =
MRI.getType(SrcReg);
2729 LLT DstTy =
MRI.getType(DstReg);
2738 case TargetOpcode::G_SHL: {
2747 case TargetOpcode::G_LSHR:
2748 case TargetOpcode::G_ASHR: {
2754 for (
auto &
User :
MRI.use_instructions(DstReg))
2755 if (
User.getOpcode() == TargetOpcode::G_STORE)
2759 if (NewShiftTy == SrcTy)
2773 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2776 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2781 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2783 LLT NewShiftTy = MatchInfo.second;
2786 LLT DstTy =
MRI.getType(Dst);
2790 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2794 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2797 if (NewShiftTy == DstTy)
2800 Builder.buildTrunc(Dst, NewShift);
2807 return MO.isReg() &&
2808 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2814 return !MO.isReg() ||
2815 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2820 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2822 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2826 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2827 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2832 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2833 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2839 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2840 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2841 "Expected an insert/extract element op");
2842 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2847 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2855 unsigned &
OpIdx)
const {
2861 OpIdx = Cst->isZero() ? 3 : 2;
2906 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2933 return MO.isReg() && MO.getReg().isPhysical();
2943 return I1->isIdenticalTo(*I2);
2951 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2958 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2970 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2971 MaybeCst->getSExtValue() ==
C;
2978 std::optional<FPValueAndVReg> MaybeCst;
2982 return MaybeCst->Value.isExactlyValue(
C);
2986 unsigned OpIdx)
const {
2987 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2992 MI.eraseFromParent();
2997 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3001 MI.eraseFromParent();
3005 unsigned ConstIdx)
const {
3006 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3007 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3019 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3020 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3021 "This is not a funnel shift operation");
3023 Register ConstReg =
MI.getOperand(3).getReg();
3024 LLT ConstTy =
MRI.getType(ConstReg);
3025 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3028 assert((VRegAndVal) &&
"Value is not a constant");
3031 APInt NewConst = VRegAndVal->Value.
urem(
3036 MI.getOpcode(), {MI.getOperand(0)},
3037 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3039 MI.eraseFromParent();
3043 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3057 unsigned OpIdx)
const {
3059 return MO.
isReg() &&
3064 unsigned OpIdx)
const {
3071 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3073 MI.eraseFromParent();
3078 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3080 MI.eraseFromParent();
3084 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3086 MI.eraseFromParent();
3091 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3093 MI.eraseFromParent();
3097 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3099 MI.eraseFromParent();
3103 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3106 Register &NewLHS = std::get<0>(MatchInfo);
3107 Register &NewRHS = std::get<1>(MatchInfo);
3115 NewLHS = MaybeNewLHS;
3119 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3124 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3127 LLT DstTy =
MRI.getType(DstReg);
3136 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3137 TargetOpcode::G_INSERT_VECTOR_ELT)
3143 MatchInfo.
resize(NumElts);
3147 if (IntImm >= NumElts || IntImm < 0)
3149 if (!MatchInfo[IntImm])
3150 MatchInfo[IntImm] = TmpReg;
3154 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3156 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3165 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3172 auto GetUndef = [&]() {
3175 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3183 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3184 MI.eraseFromParent();
3188 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3190 std::tie(SubLHS, SubRHS) = MatchInfo;
3191 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3192 MI.eraseFromParent();
3203 unsigned LogicOpcode =
MI.getOpcode();
3204 assert(LogicOpcode == TargetOpcode::G_AND ||
3205 LogicOpcode == TargetOpcode::G_OR ||
3206 LogicOpcode == TargetOpcode::G_XOR);
3213 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3219 if (!LeftHandInst || !RightHandInst)
3221 unsigned HandOpcode = LeftHandInst->
getOpcode();
3222 if (HandOpcode != RightHandInst->
getOpcode())
3236 if (!XTy.
isValid() || XTy != YTy)
3241 switch (HandOpcode) {
3244 case TargetOpcode::G_ANYEXT:
3245 case TargetOpcode::G_SEXT:
3246 case TargetOpcode::G_ZEXT: {
3250 case TargetOpcode::G_TRUNC: {
3255 LLT DstTy =
MRI.getType(Dst);
3264 case TargetOpcode::G_AND:
3265 case TargetOpcode::G_ASHR:
3266 case TargetOpcode::G_LSHR:
3267 case TargetOpcode::G_SHL: {
3272 ExtraHandOpSrcReg = ZOp.
getReg();
3283 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3294 if (ExtraHandOpSrcReg.
isValid())
3306 "Expected at least one instr to build?");
3308 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3309 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3311 for (
auto &OperandFn : InstrToBuild.OperandFns)
3314 MI.eraseFromParent();
3318 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3319 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3320 int64_t ShlCst, AshrCst;
3326 if (ShlCst != AshrCst)
3329 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3331 MatchInfo = std::make_tuple(Src, ShlCst);
3336 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3337 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3340 std::tie(Src, ShiftAmt) = MatchInfo;
3341 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3342 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3343 MI.eraseFromParent();
3350 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3353 LLT Ty =
MRI.getType(Dst);
3365 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3368 auto Zero =
B.buildConstant(Ty, 0);
3391 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3415 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3422 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3439 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3457 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3464 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3475 unsigned ExtBits =
MI.getOperand(2).getImm();
3476 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3477 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3481 int64_t Cst,
bool IsVector,
bool IsFP) {
3483 return (ScalarSizeBits == 1 && Cst == -1) ||
3505 unsigned BuildUseCount = BV.getNumSources();
3506 if (BuildUseCount % 2 != 0)
3509 unsigned NumUnmerge = BuildUseCount / 2;
3515 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3518 UnmergeSrc = Unmerge->getSourceReg();
3520 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3521 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3528 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3533 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3534 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3537 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3540 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3545 if (Unmerge->getNumDefs() != NumUnmerge)
3549 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3552 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3563 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3564 B.setInstrAndDebugLoc(
MI);
3566 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3567 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3569 MI.eraseFromParent();
3591 unsigned NumOperands =
BuildMI->getNumSources();
3599 for (
I = 0;
I < NumOperands; ++
I) {
3600 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3601 auto SrcMIOpc = SrcMI->getOpcode();
3604 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3606 UnmergeMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3607 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3610 auto UnmergeSrcMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3611 if (UnmergeMI != UnmergeSrcMI)
3622 for (;
I < NumOperands; ++
I) {
3623 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3624 auto SrcMIOpc = SrcMI->getOpcode();
3626 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3632 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3639 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3640 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3648 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3651 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3663 LLT DstTy =
MRI.getType(DstReg);
3664 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3669 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3674 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3678 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3681 Builder.buildTrunc(DstReg, MidReg);
3682 MI.eraseFromParent();
3687 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3688 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3689 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3697 if (!
MRI.hasOneNonDBGUse(XorSrc))
3707 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3709 if (!
MRI.hasOneNonDBGUse(Reg))
3712 switch (Def->getOpcode()) {
3717 case TargetOpcode::G_ICMP:
3723 case TargetOpcode::G_FCMP:
3729 case TargetOpcode::G_AND:
3730 case TargetOpcode::G_OR:
3736 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3737 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3745 if (Ty.isVector()) {
3750 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3764 for (
Register Reg : RegsToNegate) {
3769 switch (Def->getOpcode()) {
3772 case TargetOpcode::G_ICMP:
3773 case TargetOpcode::G_FCMP: {
3780 case TargetOpcode::G_AND:
3781 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3783 case TargetOpcode::G_OR:
3784 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3791 MI.eraseFromParent();
3795 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3797 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3801 Register SharedReg =
MI.getOperand(2).getReg();
3815 if (!
MRI.hasOneNonDBGUse(AndReg))
3822 return Y == SharedReg;
3826 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3829 std::tie(
X,
Y) = MatchInfo;
3832 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3833 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3834 MI.getOperand(2).setReg(
Y);
3840 Register DstReg = PtrAdd.getReg(0);
3841 LLT Ty =
MRI.getType(DstReg);
3844 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3847 if (Ty.isPointer()) {
3849 return ConstVal && *ConstVal == 0;
3852 assert(Ty.isVector() &&
"Expecting a vector type");
3859 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3860 PtrAdd.eraseFromParent();
3867 Register Pow2Src1 =
MI.getOperand(2).getReg();
3868 LLT Ty =
MRI.getType(DstReg);
3871 auto NegOne =
Builder.buildConstant(Ty, -1);
3872 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3874 MI.eraseFromParent();
3878 unsigned &SelectOpNo)
const {
3888 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3889 !
MRI.hasOneNonDBGUse(LHS)) {
3890 OtherOperandReg = LHS;
3893 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3894 !
MRI.hasOneNonDBGUse(RHS))
3910 unsigned BinOpcode =
MI.getOpcode();
3915 bool CanFoldNonConst =
3916 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3921 if (CanFoldNonConst)
3942 LLT Ty =
MRI.getType(Dst);
3943 unsigned BinOpcode =
MI.getOpcode();
3950 if (SelectOperand == 1) {
3954 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3956 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3958 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3960 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3963 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3964 MI.eraseFromParent();
3967std::optional<SmallVector<Register, 8>>
3968CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3969 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3998 const unsigned MaxIter =
4000 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4009 return std::nullopt;
4025 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4026 return std::nullopt;
4038static std::optional<std::pair<GZExtLoad *, int64_t>>
4042 "Expected Reg to only have one non-debug use?");
4051 if (Shift % MemSizeInBits != 0)
4052 return std::nullopt;
4057 return std::nullopt;
4059 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4060 return std::nullopt;
4062 return std::make_pair(Load, Shift / MemSizeInBits);
4065std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4066CombinerHelper::findLoadOffsetsForLoadOrCombine(
4069 const unsigned MemSizeInBits)
const {
4072 SmallSetVector<const MachineInstr *, 8> Loads;
4078 GZExtLoad *LowestIdxLoad =
nullptr;
4081 SmallSet<int64_t, 8> SeenIdx;
4085 MachineBasicBlock *
MBB =
nullptr;
4086 const MachineMemOperand *MMO =
nullptr;
4089 GZExtLoad *EarliestLoad =
nullptr;
4092 GZExtLoad *LatestLoad =
nullptr;
4101 for (
auto Reg : RegsToVisit) {
4106 return std::nullopt;
4109 std::tie(Load, DstPos) = *LoadAndPos;
4113 MachineBasicBlock *LoadMBB =
Load->getParent();
4117 return std::nullopt;
4120 auto &LoadMMO =
Load->getMMO();
4124 return std::nullopt;
4131 LoadPtr =
Load->getOperand(1).getReg();
4136 if (!SeenIdx.
insert(Idx).second)
4137 return std::nullopt;
4144 if (BasePtr != LoadPtr)
4145 return std::nullopt;
4147 if (Idx < LowestIdx) {
4149 LowestIdxLoad =
Load;
4156 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4157 return std::nullopt;
4165 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4166 EarliestLoad =
Load;
4167 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4174 "Expected to find a load for each register?");
4175 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4176 LatestLoad &&
"Expected at least two loads?");
4185 const unsigned MaxIter = 20;
4191 if (
MI.isLoadFoldBarrier())
4192 return std::nullopt;
4193 if (Iter++ == MaxIter)
4194 return std::nullopt;
4197 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4203 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4216 LLT Ty =
MRI.getType(Dst);
4222 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4223 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4227 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4234 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4235 if (NarrowMemSizeInBits % 8 != 0)
4248 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4249 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4252 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4259 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4262 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4274 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4275 const unsigned ZeroByteOffset =
4279 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4280 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4281 ZeroOffsetIdx->second != LowestIdx)
4291 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4305 MIB.setInstrAndDebugLoc(*LatestLoad);
4306 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4307 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4309 MIB.buildBSwap(Dst, LoadDst);
4321 if (
MRI.getType(DstReg).isVector())
4325 if (!
MRI.hasOneNonDBGUse(DstReg))
4327 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4329 case TargetOpcode::G_ANYEXT:
4331 case TargetOpcode::G_ZEXT:
4332 case TargetOpcode::G_SEXT:
4339 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4346 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4348 switch (
DefMI->getOpcode()) {
4349 case TargetOpcode::G_LOAD:
4350 case TargetOpcode::G_TRUNC:
4351 case TargetOpcode::G_SEXT:
4352 case TargetOpcode::G_ZEXT:
4353 case TargetOpcode::G_ANYEXT:
4354 case TargetOpcode::G_CONSTANT:
4358 if (InSrcs.
size() > 2)
4372 LLT ExtTy =
MRI.getType(DstReg);
4379 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4380 auto SrcReg =
PHI.getIncomingValue(
I);
4381 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4382 if (!SrcMIs.
insert(SrcMI))
4386 auto *
MBB = SrcMI->getParent();
4388 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4389 InsertPt =
MBB->getFirstNonPHI();
4391 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4394 OldToNewSrcMap[SrcMI] = NewExt;
4399 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4400 NewPhi.addDef(DstReg);
4403 NewPhi.addMBB(MO.getMBB());
4406 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4407 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4415 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4419 LLT SrcTy =
MRI.getType(SrcVec);
4420 if (SrcTy.isScalableVector())
4424 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4427 unsigned VecIdx = Cst->Value.getZExtValue();
4432 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4436 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4437 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4441 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4453 LLT ScalarTy =
MRI.getType(Reg);
4455 LLT DstTy =
MRI.getType(DstReg);
4457 if (ScalarTy != DstTy) {
4459 Builder.buildTrunc(DstReg, Reg);
4460 MI.eraseFromParent();
4468 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4469 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4487 LLT DstTy =
MRI.getType(DstReg);
4492 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4497 unsigned Idx = Cst->getZExtValue();
4500 ExtractedElts.
set(Idx);
4501 SrcDstPairs.emplace_back(
4502 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4505 return ExtractedElts.
all();
4510 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4511 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4512 for (
auto &Pair : SrcDstPairs) {
4513 auto *ExtMI = Pair.second;
4515 ExtMI->eraseFromParent();
4517 MI.eraseFromParent();
4524 MI.eraseFromParent();
4534 bool AllowScalarConstants,
4536 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4539 LLT Ty =
MRI.getType(Dst);
4540 unsigned BitWidth = Ty.getScalarSizeInBits();
4542 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4543 unsigned FshOpc = 0;
4554 int64_t CstShlAmt = 0, CstLShrAmt;
4557 CstShlAmt + CstLShrAmt ==
BitWidth) {
4558 FshOpc = TargetOpcode::G_FSHR;
4564 FshOpc = TargetOpcode::G_FSHL;
4569 FshOpc = TargetOpcode::G_FSHR;
4574 LLT AmtTy =
MRI.getType(Amt);
4576 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4580 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4587 unsigned Opc =
MI.getOpcode();
4588 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4593 unsigned RotateOpc =
4594 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4599 unsigned Opc =
MI.getOpcode();
4600 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4601 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4603 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4604 : TargetOpcode::G_ROTR));
4605 MI.removeOperand(2);
4611 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4612 MI.getOpcode() == TargetOpcode::G_ROTR);
4614 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4616 bool OutOfRange =
false;
4617 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4619 OutOfRange |= CI->getValue().uge(Bitsize);
4626 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4627 MI.getOpcode() == TargetOpcode::G_ROTR);
4629 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4631 LLT AmtTy =
MRI.getType(Amt);
4632 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4633 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4635 MI.getOperand(2).setReg(Amt);
4640 int64_t &MatchInfo)
const {
4641 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4652 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4653 if (KnownRHS.isUnknown())
4656 std::optional<bool> KnownVal;
4657 if (KnownRHS.isZero()) {
4667 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4677 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4686 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4702 LLT DstTy =
MRI.getType(Dst);
4710 auto KnownLHS =
VT->getKnownBits(LHS);
4711 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4714 LLT LHSTy =
MRI.getType(LHS);
4717 unsigned Op = TargetOpcode::COPY;
4718 if (DstSize != LHSSize)
4719 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4730 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4734 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4740 int64_t AndMaskBits;
4748 if (AndMaskBits & OrMaskBits)
4754 if (
MI.getOperand(1).getReg() == AndMaskReg)
4755 MI.getOperand(2).setReg(AndMaskReg);
4756 MI.getOperand(1).setReg(Src);
4766 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4769 LLT Ty =
MRI.getType(Src);
4771 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4773 int64_t Width =
MI.getOperand(2).getImm();
4781 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4785 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4786 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4787 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4797 LLT Ty =
MRI.getType(Dst);
4801 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4804 int64_t AndImm, LSBImm;
4806 const unsigned Size = Ty.getScalarSizeInBits();
4813 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4814 if (MaybeMask & (MaybeMask + 1))
4823 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4824 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4825 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4833 const unsigned Opcode =
MI.getOpcode();
4834 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4836 const Register Dst =
MI.getOperand(0).getReg();
4838 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4839 ? TargetOpcode::G_SBFX
4840 : TargetOpcode::G_UBFX;
4843 LLT Ty =
MRI.getType(Dst);
4845 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4851 const unsigned Size = Ty.getScalarSizeInBits();
4861 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4865 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4869 const int64_t Pos = ShrAmt - ShlAmt;
4870 const int64_t Width =
Size - ShrAmt;
4873 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4874 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4875 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4883 const unsigned Opcode =
MI.getOpcode();
4884 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4886 const Register Dst =
MI.getOperand(0).getReg();
4887 LLT Ty =
MRI.getType(Dst);
4889 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4902 const unsigned Size = Ty.getScalarSizeInBits();
4903 if (ShrAmt < 0 || ShrAmt >=
Size)
4907 if (0 == (SMask >> ShrAmt)) {
4909 B.buildConstant(Dst, 0);
4915 uint64_t UMask = SMask;
4922 const int64_t Pos = ShrAmt;
4927 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4931 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4932 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4933 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4938bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4942 Register Src1Reg = PtrAdd.getBaseReg();
4947 Register Src2Reg = PtrAdd.getOffsetReg();
4949 if (
MRI.hasOneNonDBGUse(Src1Reg))
4959 const APInt &C1APIntVal = *C1;
4960 const APInt &C2APIntVal = *C2;
4961 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4963 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4966 MachineInstr *ConvUseMI = &
UseMI;
4967 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4968 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4969 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4971 if (!
MRI.hasOneNonDBGUse(DefReg))
4973 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4982 TargetLoweringBase::AddrMode AM;
4985 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4987 PtrAdd.getMF()->getFunction().getContext());
4988 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4989 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4995 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5007 Register Src1Reg =
MI.getOperand(1).getReg();
5008 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5020 unsigned PtrAddFlags =
MI.getFlags();
5021 unsigned AddFlags = RHS->getFlags();
5034 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5037 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5039 MI.getOperand(1).setReg(NewBase.getReg(0));
5040 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5044 return !reassociationCanBreakAddressingModePattern(
MI);
5054 std::optional<ValueAndVReg> LHSCstOff;
5064 unsigned PtrAddFlags =
MI.getFlags();
5065 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5067 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5069 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5083 LHSPtrAdd->moveBefore(&
MI);
5086 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5088 MI.getOperand(2).setReg(NewCst.getReg(0));
5091 Observer.changingInstr(*LHSPtrAdd);
5092 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5093 LHSPtrAdd->setFlags(Flags);
5096 return !reassociationCanBreakAddressingModePattern(
MI);
5107 Register Src2Reg =
MI.getOperand(2).getReg();
5108 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5109 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5122 unsigned PtrAddFlags =
MI.getFlags();
5123 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5136 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5138 MI.getOperand(1).setReg(LHSSrc1);
5139 MI.getOperand(2).setReg(NewCst.getReg(0));
5143 return !reassociationCanBreakAddressingModePattern(
MI);
5181 LLT OpRHSTy =
MRI.getType(OpRHS);
5200 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5201 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5209 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5210 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5223 unsigned Opc =
MI.getOpcode();
5236 APInt &MatchInfo)
const {
5237 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5241 MatchInfo = *MaybeCst;
5249 APInt &MatchInfo)
const {
5255 MatchInfo = *MaybeCst;
5267 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5273 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5274 MI.getOpcode() == TargetOpcode::G_FMAD);
5275 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5292 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5315 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5319 LLT WideTy =
MRI.getType(Dst);
5323 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5339 case TargetOpcode::G_ADD:
5340 case TargetOpcode::G_SUB:
5341 case TargetOpcode::G_MUL:
5342 case TargetOpcode::G_AND:
5343 case TargetOpcode::G_OR:
5344 case TargetOpcode::G_XOR:
5352 auto Mask = Cst->Value;
5357 unsigned NarrowWidth = Mask.countr_one();
5363 auto &MF = *
MI.getMF();
5366 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5367 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5375 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5376 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5378 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5379 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5381 MI.getOperand(1).setReg(Ext.getReg(0));
5389 unsigned Opc =
MI.getOpcode();
5390 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5397 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5398 : TargetOpcode::G_SADDO;
5399 MI.setDesc(
Builder.getTII().get(NewOpc));
5400 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5409 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5410 MI.getOpcode() == TargetOpcode::G_SMULO);
5419 B.buildConstant(Dst, 0);
5420 B.buildConstant(Carry, 0);
5429 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5430 MI.getOpcode() == TargetOpcode::G_SADDE ||
5431 MI.getOpcode() == TargetOpcode::G_USUBE ||
5432 MI.getOpcode() == TargetOpcode::G_SSUBE);
5437 switch (
MI.getOpcode()) {
5438 case TargetOpcode::G_UADDE:
5439 NewOpcode = TargetOpcode::G_UADDO;
5441 case TargetOpcode::G_SADDE:
5442 NewOpcode = TargetOpcode::G_SADDO;
5444 case TargetOpcode::G_USUBE:
5445 NewOpcode = TargetOpcode::G_USUBO;
5447 case TargetOpcode::G_SSUBE:
5448 NewOpcode = TargetOpcode::G_SSUBO;
5452 MI.setDesc(
B.getTII().get(NewOpcode));
5453 MI.removeOperand(4);
5461 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5494 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5495 B.buildSub(Dst, Zero, ReplaceReg);
5504 unsigned Opcode =
MI.getOpcode();
5505 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5507 Register Dst = UDivorRem.getReg(0);
5508 Register LHS = UDivorRem.getReg(1);
5509 Register RHS = UDivorRem.getReg(2);
5510 LLT Ty =
MRI.getType(Dst);
5518 bool UseSRL =
false;
5523 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5525 if (IsSplat && !Factors.
empty()) {
5532 APInt Divisor = CI->getValue();
5541 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5542 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5552 if (Ty.isVector()) {
5553 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5554 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5557 Factor = Factors[0];
5565 return MIB.buildMul(Ty, Res, Factor);
5568 unsigned KnownLeadingZeros =
5569 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5571 bool UseNPQ =
false;
5573 auto BuildUDIVPattern = [&](
const Constant *
C) {
5575 const APInt &Divisor = CI->getValue();
5577 bool SelNPQ =
false;
5579 unsigned PreShift = 0, PostShift = 0;
5584 if (!Divisor.
isOne()) {
5590 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5592 Magic = std::move(magics.
Magic);
5595 "We shouldn't generate an undefined shift!");
5597 "We shouldn't generate an undefined shift!");
5601 SelNPQ = magics.
IsAdd;
5605 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5606 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5608 MIB.buildConstant(ScalarTy,
5613 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5621 assert(Matched &&
"Expected unary predicate match to succeed");
5623 Register PreShift, PostShift, MagicFactor, NPQFactor;
5626 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5627 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5628 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5629 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5632 "Non-build_vector operation should have been a scalar");
5633 PreShift = PreShifts[0];
5634 MagicFactor = MagicFactors[0];
5635 PostShift = PostShifts[0];
5639 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5642 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5645 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5650 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5652 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5654 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5657 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5658 auto One = MIB.buildConstant(Ty, 1);
5659 auto IsOne = MIB.buildICmp(
5661 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5662 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5664 if (Opcode == TargetOpcode::G_UREM) {
5665 auto Prod = MIB.buildMul(Ty, ret, RHS);
5666 return MIB.buildSub(Ty, LHS, Prod);
5672 unsigned Opcode =
MI.getOpcode();
5673 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5676 LLT DstTy =
MRI.getType(Dst);
5678 auto &MF = *
MI.getMF();
5679 AttributeList Attr = MF.getFunction().getAttributes();
5688 if (MF.getFunction().hasMinSize())
5691 if (Opcode == TargetOpcode::G_UDIV &&
5694 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5697 auto *RHSDef =
MRI.getVRegDef(RHS);
5708 {TargetOpcode::G_ICMP,
5712 if (Opcode == TargetOpcode::G_UREM &&
5718 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5727 unsigned Opcode =
MI.getOpcode();
5728 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5731 LLT DstTy =
MRI.getType(Dst);
5735 auto &MF = *
MI.getMF();
5736 AttributeList Attr = MF.getFunction().getAttributes();
5745 if (MF.getFunction().hasMinSize())
5749 if (Opcode == TargetOpcode::G_SDIV &&
5752 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5755 auto *RHSDef =
MRI.getVRegDef(RHS);
5763 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5766 if (Opcode == TargetOpcode::G_SREM &&
5772 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5781 unsigned Opcode =
MI.getOpcode();
5782 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5783 Opcode == TargetOpcode::G_SREM);
5785 Register Dst = SDivorRem.getReg(0);
5786 Register LHS = SDivorRem.getReg(1);
5787 Register RHS = SDivorRem.getReg(2);
5788 LLT Ty =
MRI.getType(Dst);
5795 bool UseSRA =
false;
5801 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5803 if (IsSplat && !ExactFactors.
empty()) {
5805 ExactFactors.
push_back(ExactFactors[0]);
5810 APInt Divisor = CI->getValue();
5820 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5821 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5829 assert(Matched &&
"Expected unary predicate match to succeed");
5832 if (Ty.isVector()) {
5833 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5834 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5836 Shift = ExactShifts[0];
5837 Factor = ExactFactors[0];
5845 return MIB.buildMul(Ty, Res, Factor);
5850 auto BuildSDIVPattern = [&](
const Constant *
C) {
5852 const APInt &Divisor = CI->getValue();
5856 int NumeratorFactor = 0;
5867 NumeratorFactor = 1;
5870 NumeratorFactor = -1;
5873 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5874 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5876 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5877 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5885 assert(Matched &&
"Expected unary predicate match to succeed");
5887 Register MagicFactor, Factor, Shift, ShiftMask;
5890 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5891 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5892 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5893 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5896 "Non-build_vector operation should have been a scalar");
5897 MagicFactor = MagicFactors[0];
5898 Factor = Factors[0];
5900 ShiftMask = ShiftMasks[0];
5904 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5907 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5908 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5911 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5914 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5915 auto T = MIB.buildLShr(Ty, Q, SignShift);
5916 T = MIB.buildAnd(Ty,
T, ShiftMask);
5917 auto ret = MIB.buildAdd(Ty, Q,
T);
5919 if (Opcode == TargetOpcode::G_SREM) {
5920 auto Prod = MIB.buildMul(Ty, ret, RHS);
5921 return MIB.buildSub(Ty, LHS, Prod);
5927 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5928 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5929 "Expected SDIV or UDIV");
5932 auto MatchPow2 = [&](
const Constant *
C) {
5934 return CI && (CI->getValue().isPowerOf2() ||
5935 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5941 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5946 LLT Ty =
MRI.getType(Dst);
5966 unsigned BitWidth = Ty.getScalarSizeInBits();
5967 auto Zero =
Builder.buildConstant(Ty, 0);
5970 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5971 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5973 auto Sign =
Builder.buildAShr(
5977 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5983 auto One =
Builder.buildConstant(Ty, 1);
5984 auto MinusOne =
Builder.buildConstant(Ty, -1);
5988 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5989 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5993 auto Neg =
Builder.buildNeg(Ty, AShr);
5995 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5996 MI.eraseFromParent();
6000 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6005 LLT Ty =
MRI.getType(Dst);
6008 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6009 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6010 MI.eraseFromParent();
6014 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6017 LLT Ty =
MRI.getType(Dst);
6018 LLT RHSTy =
MRI.getType(RHS);
6020 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6022 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6037 LLT Ty =
MRI.getType(Dst);
6043 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6044 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6045 Builder.buildLShr(Dst, LHS, Trunc);
6046 MI.eraseFromParent();
6053 LLT DstTy =
MRI.getType(Dst);
6054 LLT SrcTy =
MRI.getType(Src);
6056 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6057 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6060 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6078 Builder.buildTruncSSatS(Dst, MatchInfo);
6079 MI.eraseFromParent();
6086 LLT DstTy =
MRI.getType(Dst);
6087 LLT SrcTy =
MRI.getType(Src);
6089 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6090 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6093 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6111 Builder.buildTruncSSatU(Dst, MatchInfo);
6112 MI.eraseFromParent();
6119 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6120 LLT SrcTy =
MRI.getType(Val);
6122 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6123 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6126 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6135 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6144 unsigned Opc =
MI.getOpcode();
6145 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6146 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6147 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6159 Opc = TargetOpcode::G_FSUB;
6164 Opc = TargetOpcode::G_FADD;
6170 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6171 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6180 MI.setDesc(
B.getTII().get(
Opc));
6181 MI.getOperand(1).setReg(
X);
6182 MI.getOperand(2).setReg(
Y);
6190 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6193 MatchInfo =
MI.getOperand(2).getReg();
6194 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6196 const auto LHSCst = Ty.isVector()
6203 if (LHSCst->Value.isNegZero())
6207 if (LHSCst->Value.isPosZero())
6217 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6224 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6238 bool &AllowFusionGlobally,
6240 bool CanReassociate)
const {
6242 auto *MF =
MI.getMF();
6243 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6245 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6253 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6256 if (!HasFMAD && !HasFMA)
6264 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6271 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6273 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6281 unsigned PreferredFusedOpcode =
6282 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6296 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6297 {LHS.MI->getOperand(1).getReg(),
6298 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6307 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6308 {RHS.MI->getOperand(1).getReg(),
6309 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6320 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6322 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6326 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6331 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6333 unsigned PreferredFusedOpcode =
6334 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6348 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6353 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6354 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6363 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6368 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6369 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6380 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6382 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6390 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6392 unsigned PreferredFusedOpcode =
6393 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6406 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6407 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6408 TargetOpcode::G_FMUL) &&
6409 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6410 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6415 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6416 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6417 TargetOpcode::G_FMUL) &&
6418 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6419 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6426 Register X = FMA->getOperand(1).getReg();
6427 Register Y = FMA->getOperand(2).getReg();
6432 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6433 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6434 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6446 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6448 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6455 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6456 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6462 unsigned PreferredFusedOpcode =
6463 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6476 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6477 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6479 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6481 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6488 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6492 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6497 LHS.MI->getOperand(1).getReg(),
6498 LHS.MI->getOperand(2).getReg(),
B);
6509 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6512 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6517 X =
B.buildFPExt(DstType,
X).getReg(0);
6518 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6529 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6533 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6538 RHS.MI->getOperand(1).getReg(),
6539 RHS.MI->getOperand(2).getReg(),
B);
6550 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6553 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6558 X =
B.buildFPExt(DstType,
X).getReg(0);
6559 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6573 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6575 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6583 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6587 int FirstMulHasFewerUses =
true;
6591 FirstMulHasFewerUses =
false;
6593 unsigned PreferredFusedOpcode =
6594 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6597 if (FirstMulHasFewerUses &&
6601 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6602 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6603 {LHS.MI->getOperand(1).getReg(),
6604 LHS.MI->getOperand(2).getReg(), NegZ});
6613 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6614 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6615 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6626 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6628 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6634 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6636 unsigned PreferredFusedOpcode =
6637 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6648 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6649 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6661 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6674 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6676 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6682 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6684 unsigned PreferredFusedOpcode =
6685 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6697 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6698 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6699 {FpExtX, FpExtY, NegZ});
6711 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6714 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6715 {NegY, FpExtZ, LHSReg});
6726 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6728 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6732 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6733 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6737 unsigned PreferredFusedOpcode =
6738 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6742 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6743 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6744 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6755 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6758 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6761 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6771 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6784 unsigned &IdxToPropagate)
const {
6786 switch (
MI.getOpcode()) {
6789 case TargetOpcode::G_FMINNUM:
6790 case TargetOpcode::G_FMAXNUM:
6791 PropagateNaN =
false;
6793 case TargetOpcode::G_FMINIMUM:
6794 case TargetOpcode::G_FMAXIMUM:
6795 PropagateNaN =
true;
6799 auto MatchNaN = [&](
unsigned Idx) {
6800 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6804 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6808 return MatchNaN(1) || MatchNaN(2);
6816 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6826 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6839 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6840 if (&U == &
MI || U.getParent() !=
MI.getParent())
6842 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6843 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6856 return MatchInfo.
size() >= MinUses;
6864 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6865 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6866 MatchInfo[0]->getOperand(2).getReg(),
6867 MatchInfo[0]->getFlags());
6872 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6873 Div->getOperand(0).getReg(),
MI->getFlags());
6874 MI->eraseFromParent();
6879 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6889 Reg == MaybeSameReg;
6891 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6912 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6921 return MRI.getType(MatchInfo) == DstVecTy;
6924 std::optional<ValueAndVReg> ShiftAmount;
6933 return MRI.getType(MatchInfo) == DstVecTy;
6948 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6955 std::optional<ValueAndVReg> ShiftAmt;
6961 LLT MatchTy =
MRI.getType(MatchInfo);
6962 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6963 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6966unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6968 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6969 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6970 "Expected a NaN behaviour?");
6980 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6981 return TargetOpcode::G_FMAXNUM;
6982 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6983 return TargetOpcode::G_FMAXIMUM;
6984 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6985 return TargetOpcode::G_FMAXNUM;
6986 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6987 return TargetOpcode::G_FMAXIMUM;
6993 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6994 return TargetOpcode::G_FMINNUM;
6995 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6996 return TargetOpcode::G_FMINIMUM;
6997 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6998 return TargetOpcode::G_FMINNUM;
6999 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7001 return TargetOpcode::G_FMINIMUM;
7005CombinerHelper::SelectPatternNaNBehaviour
7007 bool IsOrderedComparison)
const {
7011 if (!LHSSafe && !RHSSafe)
7012 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7013 if (LHSSafe && RHSSafe)
7014 return SelectPatternNaNBehaviour::RETURNS_ANY;
7017 if (IsOrderedComparison)
7018 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7019 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7022 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7023 : SelectPatternNaNBehaviour::RETURNS_NAN;
7032 LLT DstTy =
MRI.getType(Dst);
7045 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7047 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7049 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7052 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7053 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7054 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7055 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7057 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7060 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7065 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7070 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7072 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7076 MatchInfo = [=](MachineIRBuilder &
B) {
7077 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7085 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7092 Register TrueVal =
MI.getOperand(2).getReg();
7093 Register FalseVal =
MI.getOperand(3).getReg();
7094 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7099 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7112 if (MatchedSub &&
X != OpLHS)
7120 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7123 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7124 B.buildICmp(Pred, Dst,
Y, Zero);
7131static std::optional<unsigned>
7133 std::optional<int64_t> &Result) {
7134 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7135 Opcode == TargetOpcode::G_ASHR) &&
7136 "Expect G_SHL, G_LSHR or G_ASHR.");
7137 auto SignificantBits = 0;
7139 case TargetOpcode::G_SHL:
7143 case TargetOpcode::G_LSHR:
7147 case TargetOpcode::G_ASHR:
7156 Result = std::nullopt;
7167 Register ShiftVal =
MI.getOperand(1).getReg();
7168 Register ShiftReg =
MI.getOperand(2).getReg();
7169 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7170 auto IsShiftTooBig = [&](
const Constant *
C) {
7175 MatchInfo = std::nullopt;
7179 MI.getOpcode(), MatchInfo);
7180 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7186 unsigned LHSOpndIdx = 1;
7187 unsigned RHSOpndIdx = 2;
7188 switch (
MI.getOpcode()) {
7189 case TargetOpcode::G_UADDO:
7190 case TargetOpcode::G_SADDO:
7191 case TargetOpcode::G_UMULO:
7192 case TargetOpcode::G_SMULO:
7199 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7200 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7205 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7206 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7210 return MRI.getVRegDef(RHS)->getOpcode() !=
7211 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7218 std::optional<FPValueAndVReg> ValAndVReg;
7226 unsigned LHSOpndIdx = 1;
7227 unsigned RHSOpndIdx = 2;
7228 switch (
MI.getOpcode()) {
7229 case TargetOpcode::G_UADDO:
7230 case TargetOpcode::G_SADDO:
7231 case TargetOpcode::G_UMULO:
7232 case TargetOpcode::G_SMULO:
7239 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7240 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7241 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7242 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7246bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7248 if (SrcTy.isFixedVector())
7249 return isConstantSplatVector(Src, 1, AllowUndefs);
7250 if (SrcTy.isScalar()) {
7254 return IConstant && IConstant->Value == 1;
7259bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7260 LLT SrcTy =
MRI.getType(Src);
7262 return isConstantSplatVector(Src, 0, AllowUndefs);
7267 return IConstant && IConstant->Value == 0;
7274bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7275 bool AllowUndefs)
const {
7281 for (
unsigned I = 0;
I < NumSources; ++
I) {
7282 GImplicitDef *ImplicitDef =
7284 if (ImplicitDef && AllowUndefs)
7286 if (ImplicitDef && !AllowUndefs)
7288 std::optional<ValueAndVReg> IConstant =
7290 if (IConstant && IConstant->Value == SplatValue)
7300CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7303 return IConstant->Value;
7307 return std::nullopt;
7310 std::optional<APInt>
Value = std::nullopt;
7311 for (
unsigned I = 0;
I < NumSources; ++
I) {
7312 std::optional<ValueAndVReg> IConstant =
7315 return std::nullopt;
7317 Value = IConstant->Value;
7318 else if (*
Value != IConstant->Value)
7319 return std::nullopt;
7325bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7335 for (
unsigned I = 0;
I < NumSources; ++
I) {
7336 std::optional<ValueAndVReg> IConstant =
7345bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7352 LLT CondTy =
MRI.getType(
Select->getCondReg());
7353 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7363 std::optional<ValueAndVReg> TrueOpt =
7365 std::optional<ValueAndVReg> FalseOpt =
7368 if (!TrueOpt || !FalseOpt)
7371 APInt TrueValue = TrueOpt->Value;
7372 APInt FalseValue = FalseOpt->Value;
7376 MatchInfo = [=](MachineIRBuilder &
B) {
7377 B.setInstrAndDebugLoc(*
Select);
7378 B.buildZExtOrTrunc(Dest,
Cond);
7385 MatchInfo = [=](MachineIRBuilder &
B) {
7386 B.setInstrAndDebugLoc(*
Select);
7387 B.buildSExtOrTrunc(Dest,
Cond);
7394 MatchInfo = [=](MachineIRBuilder &
B) {
7395 B.setInstrAndDebugLoc(*
Select);
7396 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7397 B.buildNot(Inner,
Cond);
7398 B.buildZExtOrTrunc(Dest, Inner);
7405 MatchInfo = [=](MachineIRBuilder &
B) {
7406 B.setInstrAndDebugLoc(*
Select);
7407 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7408 B.buildNot(Inner,
Cond);
7409 B.buildSExtOrTrunc(Dest, Inner);
7415 if (TrueValue - 1 == FalseValue) {
7416 MatchInfo = [=](MachineIRBuilder &
B) {
7417 B.setInstrAndDebugLoc(*
Select);
7418 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7419 B.buildZExtOrTrunc(Inner,
Cond);
7420 B.buildAdd(Dest, Inner, False);
7426 if (TrueValue + 1 == FalseValue) {
7427 MatchInfo = [=](MachineIRBuilder &
B) {
7428 B.setInstrAndDebugLoc(*
Select);
7429 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7430 B.buildSExtOrTrunc(Inner,
Cond);
7431 B.buildAdd(Dest, Inner, False);
7438 MatchInfo = [=](MachineIRBuilder &
B) {
7439 B.setInstrAndDebugLoc(*
Select);
7440 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7441 B.buildZExtOrTrunc(Inner,
Cond);
7444 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7445 B.buildShl(Dest, Inner, ShAmtC, Flags);
7452 MatchInfo = [=](MachineIRBuilder &
B) {
7453 B.setInstrAndDebugLoc(*
Select);
7455 B.buildNot(Not,
Cond);
7456 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7457 B.buildZExtOrTrunc(Inner, Not);
7460 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7461 B.buildShl(Dest, Inner, ShAmtC, Flags);
7468 MatchInfo = [=](MachineIRBuilder &
B) {
7469 B.setInstrAndDebugLoc(*
Select);
7470 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7471 B.buildSExtOrTrunc(Inner,
Cond);
7472 B.buildOr(Dest, Inner, False, Flags);
7479 MatchInfo = [=](MachineIRBuilder &
B) {
7480 B.setInstrAndDebugLoc(*
Select);
7482 B.buildNot(Not,
Cond);
7483 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7484 B.buildSExtOrTrunc(Inner, Not);
7485 B.buildOr(Dest, Inner, True, Flags);
7494bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7501 LLT CondTy =
MRI.getType(
Select->getCondReg());
7502 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7511 if (CondTy != TrueTy)
7516 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7517 MatchInfo = [=](MachineIRBuilder &
B) {
7518 B.setInstrAndDebugLoc(*
Select);
7519 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7520 B.buildZExtOrTrunc(Ext,
Cond);
7521 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7522 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7529 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7530 MatchInfo = [=](MachineIRBuilder &
B) {
7531 B.setInstrAndDebugLoc(*
Select);
7532 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7533 B.buildZExtOrTrunc(Ext,
Cond);
7534 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7535 B.buildAnd(DstReg, Ext, FreezeTrue);
7541 if (isOneOrOneSplat(False,
true)) {
7542 MatchInfo = [=](MachineIRBuilder &
B) {
7543 B.setInstrAndDebugLoc(*
Select);
7545 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7546 B.buildNot(Inner,
Cond);
7548 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7549 B.buildZExtOrTrunc(Ext, Inner);
7550 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7551 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7557 if (isZeroOrZeroSplat(True,
true)) {
7558 MatchInfo = [=](MachineIRBuilder &
B) {
7559 B.setInstrAndDebugLoc(*
Select);
7561 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7562 B.buildNot(Inner,
Cond);
7564 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7565 B.buildZExtOrTrunc(Ext, Inner);
7566 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7567 B.buildAnd(DstReg, Ext, FreezeFalse);
7583 LLT DstTy =
MRI.getType(DstReg);
7589 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7598 Register CmpLHS = Cmp->getLHSReg();
7599 Register CmpRHS = Cmp->getRHSReg();
7602 if (True == CmpRHS && False == CmpLHS) {
7610 if (True != CmpLHS || False != CmpRHS)
7650 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7651 Register DestReg =
MI.getOperand(0).getReg();
7652 LLT DestTy =
MRI.getType(DestReg);
7664 if (
isLegal({NewOpc, {DestTy}})) {
7666 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7678 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7681 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7691bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7693 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7694 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7698 unsigned Flags = Logic->
getFlags();
7717 std::optional<ValueAndVReg> MaybeC1 =
7721 C1 = MaybeC1->Value;
7723 std::optional<ValueAndVReg> MaybeC2 =
7727 C2 = MaybeC2->Value;
7748 std::optional<APInt> Offset1;
7749 std::optional<APInt> Offset2;
7752 std::optional<ValueAndVReg> MaybeOffset1 =
7755 R1 =
Add->getLHSReg();
7756 Offset1 = MaybeOffset1->Value;
7760 std::optional<ValueAndVReg> MaybeOffset2 =
7763 R2 =
Add->getLHSReg();
7764 Offset2 = MaybeOffset2->Value;
7783 bool CreateMask =
false;
7796 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7809 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7818 MatchInfo = [=](MachineIRBuilder &
B) {
7819 if (CreateMask &&
Offset != 0) {
7820 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7821 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7822 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7823 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7824 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7825 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7826 B.buildZExtOrTrunc(DstReg, ICmp);
7827 }
else if (CreateMask &&
Offset == 0) {
7828 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7829 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7830 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7831 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7832 B.buildZExtOrTrunc(DstReg, ICmp);
7833 }
else if (!CreateMask &&
Offset != 0) {
7834 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7835 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7836 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7837 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7838 B.buildZExtOrTrunc(DstReg, ICmp);
7839 }
else if (!CreateMask &&
Offset == 0) {
7840 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7841 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7842 B.buildZExtOrTrunc(DstReg, ICmp);
7850bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7856 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7868 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7874 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7875 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7876 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7877 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7888 if (LHS0 == RHS1 && LHS1 == RHS0) {
7894 if (LHS0 == RHS0 && LHS1 == RHS1) {
7898 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7900 MatchInfo = [=](MachineIRBuilder &
B) {
7905 auto False =
B.buildConstant(CmpTy, 0);
7906 B.buildZExtOrTrunc(DestReg, False);
7913 B.buildZExtOrTrunc(DestReg, True);
7915 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7916 B.buildZExtOrTrunc(DestReg, Cmp);
7928 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7931 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7940 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7943 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7958 bool IsSigned =
Add->isSigned();
7959 LLT DstTy =
MRI.getType(Dst);
7960 LLT CarryTy =
MRI.getType(Carry);
7963 if (
MRI.use_nodbg_empty(Carry) &&
7966 B.buildAdd(Dst, LHS, RHS);
7967 B.buildUndef(Carry);
7973 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7976 B.buildSAddo(Dst, Carry, RHS, LHS);
7982 B.buildUAddo(Dst, Carry, RHS, LHS);
7987 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7988 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7994 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7995 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7997 B.buildConstant(Dst, Result);
7998 B.buildConstant(Carry, Overflow);
8006 B.buildCopy(Dst, LHS);
8007 B.buildConstant(Carry, 0);
8016 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8019 std::optional<APInt> MaybeAddRHS =
8020 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8023 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8024 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8028 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8029 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8035 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8036 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8061 B.buildConstant(Carry, 0);
8068 B.buildAdd(Dst, LHS, RHS);
8069 B.buildConstant(Carry, 1);
8081 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8084 B.buildConstant(Carry, 0);
8100 B.buildConstant(Carry, 0);
8107 B.buildAdd(Dst, LHS, RHS);
8108 B.buildConstant(Carry, 1);
8126 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8132 auto [Dst,
Base] =
MI.getFirst2Regs();
8133 LLT Ty =
MRI.getType(Dst);
8137 Builder.buildFConstant(Dst, 1.0);
8138 MI.removeFromParent();
8150 std::optional<SrcOp> Res;
8152 while (ExpVal > 0) {
8157 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8160 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8167 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8171 MI.eraseFromParent();
8180 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8187 LLT DstTy =
MRI.getType(Dst);
8190 auto Const =
B.buildConstant(DstTy, C1 - C2);
8191 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8203 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8210 LLT DstTy =
MRI.getType(Dst);
8213 auto Const =
B.buildConstant(DstTy, C2 - C1);
8214 B.buildSub(Dst, Const,
Add->getLHSReg());
8226 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8233 LLT DstTy =
MRI.getType(Dst);
8236 auto Const =
B.buildConstant(DstTy, C1 + C2);
8249 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8256 LLT DstTy =
MRI.getType(Dst);
8259 auto Const =
B.buildConstant(DstTy, C1 - C2);
8272 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8279 LLT DstTy =
MRI.getType(Dst);
8282 auto Const =
B.buildConstant(DstTy, C2 - C1);
8283 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8330 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8334 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8337 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8338 LLT SmallBvTy = DstTy;
8342 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8347 {TargetOpcode::G_ANYEXT,
8359 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8360 Ops.push_back(AnyExt.getReg(0));
8378 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8379 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8380 const unsigned NumDstElts = OrigMask.
size();
8381 for (
unsigned i = 0; i != NumDstElts; ++i) {
8382 int Idx = OrigMask[i];
8383 if (Idx >= (
int)NumSrcElems) {
8394 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8395 std::move(NewMask));
8402 const unsigned MaskSize = Mask.size();
8403 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8408 if (Idx < (
int)NumElems)
8409 Mask[
I] = Idx + NumElems;
8411 Mask[
I] = Idx - NumElems;
8421 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8424 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8427 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8428 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8430 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8434 const unsigned NumSrcElems = Src1Ty.getNumElements();
8436 bool TouchesSrc1 =
false;
8437 bool TouchesSrc2 =
false;
8438 const unsigned NumElems = Mask.size();
8439 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8443 if (Mask[Idx] < (
int)NumSrcElems)
8449 if (TouchesSrc1 == TouchesSrc2)
8452 Register NewSrc1 = Shuffle.getSrc1Reg();
8455 NewSrc1 = Shuffle.getSrc2Reg();
8460 auto Undef =
B.buildUndef(Src1Ty);
8461 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8475 LLT DstTy =
MRI.getType(Dst);
8476 LLT CarryTy =
MRI.getType(Carry);
8498 B.buildConstant(Carry, 0);
8505 B.buildSub(Dst, LHS, RHS);
8523 B.buildConstant(Carry, 0);
8530 B.buildSub(Dst, LHS, RHS);
8547 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8548 "Expected G_CTLZ variant");
8553 LLT Ty =
MRI.getType(Dst);
8554 LLT SrcTy =
MRI.getType(Src);
8556 if (!(Ty.isValid() && Ty.isScalar()))
8565 switch (
LI->getAction(Query).Action) {
8576 bool NeedAdd =
true;
8584 unsigned BitWidth = Ty.getScalarSizeInBits();
8595 B.buildCTLS(Dst,
X);
8599 auto Ctls =
B.buildCTLS(Ty,
X);
8600 auto One =
B.buildConstant(Ty, 1);
8602 B.buildAdd(Dst, Ctls, One);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static std::optional< unsigned > getMinUselessShift(KnownBits ValueKB, unsigned Opcode, std::optional< int64_t > &Result)
Return the minimum useless shift amount that results in complete loss of the source value.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Interface for Targets to specify which operations they can successfully select and how the others sho...
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
static LLVM_ABI bool isEquality(Predicate pred)
Determine if this is an equals/not equals predicate.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
static LLVM_ABI bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
void applyPtrAddZero(MachineInstr &MI) const
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
void applyUDivOrURemByConst(MachineInstr &MI) const
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchPtrAddZero(MachineInstr &MI) const
}
void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
bool matchShiftsTooBig(MachineInstr &MI, std::optional< int64_t > &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
const DataLayout & getDataLayout() const
bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
void applyUMulHToLShr(MachineInstr &MI) const
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
bool isLegalOrHasFewerElements(const LegalityQuery &Query) const
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
const TargetLowering & getTargetLowering() const
bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
void applySDivByPow2(MachineInstr &MI) const
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
bool tryEmitMemcpyInline(MachineInstr &MI) const
Emit loads and stores that perform the given memcpy.
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
void applyCombineCopy(MachineInstr &MI) const
bool matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
bool matchSextTruncSextLoad(MachineInstr &MI) const
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchCombineCopy(MachineInstr &MI) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
bool matchRedundantSExtInReg(MachineInstr &MI) const
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
bool tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool isPreLegalize() const
bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is known to be a power of 2.
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVMContext & getContext() const
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
bool isLegal(const LegalityQuery &Query) const
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
void eraseInst(MachineInstr &MI) const
Erase MI.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
bool matchConstantFPOp(const MachineOperand &MOP, double C) const
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
bool tryCombineShuffleVector(MachineInstr &MI) const
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
If a brcond's true block is not the fallthrough, make it so by inverting the condition and swapping o...
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
void applyFunnelShiftToRotate(MachineInstr &MI) const
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal) const
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applySDivOrSRemByConst(MachineInstr &MI) const
MachineInstr * buildSDivOrSRemUsingMul(MachineInstr &MI) const
Given an G_SDIV MI or G_SREM MI expressing a signed divide by constant, return an expression that imp...
bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
void applyCommuteBinOpOperands(MachineInstr &MI) const
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
void applySextTruncSextLoad(MachineInstr &MI) const
const MachineFunction & getMachineFunction() const
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Abstract class that contains various methods for clients to notify about changes.
Simple wrapper observer that takes several observers, and calls each one for each event.
Represents any type of generic load or store.
Register getPointerReg() const
Get the source register of the pointer value.
Represents a logical binary operation.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
bool isAtomic() const
Returns true if the attached MachineMemOperand has the atomic flag set.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
bool isSimple() const
Returns true if the memory operation is neither atomic or volatile.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr ElementCount getElementCount() const
constexpr LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
This is an important class for using LLVM in a threaded context.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
LLVM_ABI bool isDereferenceableInvariantLoad() const
Return true if this load instruction never traps and points to a memory location whose value doesn't ...
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
mop_range uses()
Returns all operands which may be register uses.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
static use_instr_nodbg_iterator use_instr_nodbg_end()
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual bool isTruncateFree(Type *FromTy, Type *ToTy) const
Return true if it's free to truncate a value of type FromTy to type ToTy.
virtual LLVM_READONLY LLT getPreferredShiftAmountTy(LLT ShiftValueTy) const
Return the preferred type to use for a shift opcode, given the shifted amount type is ShiftValueTy.
bool isBeneficialToExpandPowI(int64_t Exponent, bool OptForSize) const
Return true if it is beneficial to expand an @llvm.powi.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual unsigned combineRepeatedFPDivisors() const
Indicate whether this target prefers to combine FDIVs with the same divisor.
virtual const TargetLowering * getTargetLowering() const
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
@ Custom
The target wants to do something special with this combination of operand and type.
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(const APInt &RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false > m_GBuildVectorTrunc(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP, true > m_c_GICmp(const Pred &P, const LHS &L, const RHS &R)
G_ICMP matcher that also matches commuted compares.
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
class_match< BinaryOperator > m_BinOp()
Match an arbitrary binary operation and ignore it.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > OperandBuildSteps
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
LLVM_ABI bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
LLVM_ABI std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
LLVM_ABI unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc)
Returns the inverse opcode of MinMaxOpc, which is a generic min/max opcode like G_SMIN.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a float constant integer or a splat vector of float constant integers.
constexpr unsigned BitWidth
LLVM_ABI int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool isKnownNeverNaN(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if the floating-point scalar value is not a NaN or if the floating-point vector value has...
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
LLVM_ABI bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return true if the given value is known to have exactly one bit set when defined.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
LLVM_ABI std::optional< int64_t > getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Simple struct used to hold a Register value and the instruction which defines it.
SmallVector< InstructionBuildSteps, 2 > InstrsToBuild
Describes instructions to be built during a combine.
bool isNonNegative() const
Returns true if this value is known to be non-negative.
unsigned countMinLeadingOnes() const
Returns the minimum number of leading one bits.
unsigned countMinTrailingZeros() const
Returns the minimum number of trailing zero bits.
bool isUnknown() const
Returns true if we don't know any bits.
unsigned getBitWidth() const
Get the bit width of this value.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
bool isNegative() const
Returns true if this value is known to be negative.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
This class contains a discriminated union of information about pointers in memory operands,...
LLVM_ABI unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
Magic data for optimising signed division by a constant.
unsigned ShiftAmount
shift amount
static LLVM_ABI SignedDivisionByConstantInfo get(const APInt &D)
Calculate the magic numbers required to implement a signed integer division by a constant as a sequen...
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
unsigned PostShift
post-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true, bool AllowWidenOptimization=false)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...