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)");
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 {
1207 if (
MRI.hasOneNonDBGUse(Ptr))
1210 if (!isIndexedLoadStoreLegal(LdSt))
1217 auto *PtrDef =
MRI.getVRegDef(Ptr);
1219 unsigned NumUsesChecked = 0;
1220 for (
auto &
Use :
MRI.use_nodbg_instructions(Ptr)) {
1227 if (!PtrAdd ||
MRI.use_nodbg_empty(PtrAdd->getReg(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: {
1714 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
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) {
4008 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
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();
5687 if (MF.getFunction().hasMinSize())
5690 if (Opcode == TargetOpcode::G_UDIV &&
5693 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5696 auto *RHSDef =
MRI.getVRegDef(RHS);
5707 {TargetOpcode::G_ICMP,
5711 if (Opcode == TargetOpcode::G_UREM &&
5717 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5726 unsigned Opcode =
MI.getOpcode();
5727 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5730 LLT DstTy =
MRI.getType(Dst);
5734 auto &MF = *
MI.getMF();
5735 AttributeList Attr = MF.getFunction().getAttributes();
5743 if (MF.getFunction().hasMinSize())
5747 if (Opcode == TargetOpcode::G_SDIV &&
5750 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5753 auto *RHSDef =
MRI.getVRegDef(RHS);
5761 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5764 if (Opcode == TargetOpcode::G_SREM &&
5770 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5779 unsigned Opcode =
MI.getOpcode();
5780 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5781 Opcode == TargetOpcode::G_SREM);
5783 Register Dst = SDivorRem.getReg(0);
5784 Register LHS = SDivorRem.getReg(1);
5785 Register RHS = SDivorRem.getReg(2);
5786 LLT Ty =
MRI.getType(Dst);
5793 bool UseSRA =
false;
5799 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5801 if (IsSplat && !ExactFactors.
empty()) {
5803 ExactFactors.
push_back(ExactFactors[0]);
5808 APInt Divisor = CI->getValue();
5818 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5819 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5827 assert(Matched &&
"Expected unary predicate match to succeed");
5830 if (Ty.isVector()) {
5831 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5832 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5834 Shift = ExactShifts[0];
5835 Factor = ExactFactors[0];
5843 return MIB.buildMul(Ty, Res, Factor);
5848 auto BuildSDIVPattern = [&](
const Constant *
C) {
5850 const APInt &Divisor = CI->getValue();
5854 int NumeratorFactor = 0;
5865 NumeratorFactor = 1;
5868 NumeratorFactor = -1;
5871 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5872 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5874 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5875 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5883 assert(Matched &&
"Expected unary predicate match to succeed");
5885 Register MagicFactor, Factor, Shift, ShiftMask;
5888 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5889 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5890 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5891 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5894 "Non-build_vector operation should have been a scalar");
5895 MagicFactor = MagicFactors[0];
5896 Factor = Factors[0];
5898 ShiftMask = ShiftMasks[0];
5902 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5905 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5906 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5909 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5912 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5913 auto T = MIB.buildLShr(Ty, Q, SignShift);
5914 T = MIB.buildAnd(Ty,
T, ShiftMask);
5915 auto ret = MIB.buildAdd(Ty, Q,
T);
5917 if (Opcode == TargetOpcode::G_SREM) {
5918 auto Prod = MIB.buildMul(Ty, ret, RHS);
5919 return MIB.buildSub(Ty, LHS, Prod);
5925 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5926 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5927 "Expected SDIV or UDIV");
5930 auto MatchPow2 = [&](
const Constant *
C) {
5932 return CI && (CI->getValue().isPowerOf2() ||
5933 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5939 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5944 LLT Ty =
MRI.getType(Dst);
5964 unsigned BitWidth = Ty.getScalarSizeInBits();
5965 auto Zero =
Builder.buildConstant(Ty, 0);
5968 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5969 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5971 auto Sign =
Builder.buildAShr(
5975 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5981 auto One =
Builder.buildConstant(Ty, 1);
5982 auto MinusOne =
Builder.buildConstant(Ty, -1);
5986 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5987 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5991 auto Neg =
Builder.buildNeg(Ty, AShr);
5993 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5994 MI.eraseFromParent();
5998 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6003 LLT Ty =
MRI.getType(Dst);
6006 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6007 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6008 MI.eraseFromParent();
6012 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6015 LLT Ty =
MRI.getType(Dst);
6016 LLT RHSTy =
MRI.getType(RHS);
6018 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6020 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6035 LLT Ty =
MRI.getType(Dst);
6041 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6042 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6043 Builder.buildLShr(Dst, LHS, Trunc);
6044 MI.eraseFromParent();
6051 LLT DstTy =
MRI.getType(Dst);
6052 LLT SrcTy =
MRI.getType(Src);
6054 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6055 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6058 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6076 Builder.buildTruncSSatS(Dst, MatchInfo);
6077 MI.eraseFromParent();
6084 LLT DstTy =
MRI.getType(Dst);
6085 LLT SrcTy =
MRI.getType(Src);
6087 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6088 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6091 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6109 Builder.buildTruncSSatU(Dst, MatchInfo);
6110 MI.eraseFromParent();
6117 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6118 LLT SrcTy =
MRI.getType(Val);
6120 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6121 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6124 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6133 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6142 unsigned Opc =
MI.getOpcode();
6143 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6144 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6145 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6157 Opc = TargetOpcode::G_FSUB;
6162 Opc = TargetOpcode::G_FADD;
6168 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6169 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6178 MI.setDesc(
B.getTII().get(
Opc));
6179 MI.getOperand(1).setReg(
X);
6180 MI.getOperand(2).setReg(
Y);
6188 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6191 MatchInfo =
MI.getOperand(2).getReg();
6192 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6194 const auto LHSCst = Ty.isVector()
6201 if (LHSCst->Value.isNegZero())
6205 if (LHSCst->Value.isPosZero())
6215 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6222 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6230 MRI.use_instr_nodbg_end()) >
6232 MRI.use_instr_nodbg_end());
6236 bool &AllowFusionGlobally,
6238 bool CanReassociate)
const {
6240 auto *MF =
MI.getMF();
6241 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6243 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6251 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6254 if (!HasFMAD && !HasFMA)
6262 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6269 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6271 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6279 unsigned PreferredFusedOpcode =
6280 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6294 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6295 {LHS.MI->getOperand(1).getReg(),
6296 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6305 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6306 {RHS.MI->getOperand(1).getReg(),
6307 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6318 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6320 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6324 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6329 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6331 unsigned PreferredFusedOpcode =
6332 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6346 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6351 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6352 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6361 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6366 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6367 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6378 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6380 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6388 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6390 unsigned PreferredFusedOpcode =
6391 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6404 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6405 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6406 TargetOpcode::G_FMUL) &&
6407 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6408 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6413 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6414 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6415 TargetOpcode::G_FMUL) &&
6416 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6417 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6424 Register X = FMA->getOperand(1).getReg();
6425 Register Y = FMA->getOperand(2).getReg();
6430 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6431 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6432 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6444 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6446 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6453 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6454 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6460 unsigned PreferredFusedOpcode =
6461 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6474 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6475 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6477 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6479 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6486 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6490 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6495 LHS.MI->getOperand(1).getReg(),
6496 LHS.MI->getOperand(2).getReg(),
B);
6507 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6510 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6515 X =
B.buildFPExt(DstType,
X).getReg(0);
6516 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6527 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6531 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6536 RHS.MI->getOperand(1).getReg(),
6537 RHS.MI->getOperand(2).getReg(),
B);
6548 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6551 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6556 X =
B.buildFPExt(DstType,
X).getReg(0);
6557 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6571 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6573 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6581 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6585 int FirstMulHasFewerUses =
true;
6589 FirstMulHasFewerUses =
false;
6591 unsigned PreferredFusedOpcode =
6592 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6595 if (FirstMulHasFewerUses &&
6599 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6600 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6601 {LHS.MI->getOperand(1).getReg(),
6602 LHS.MI->getOperand(2).getReg(), NegZ});
6611 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6612 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6613 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6624 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6626 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6632 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6634 unsigned PreferredFusedOpcode =
6635 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6646 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6647 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6659 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6672 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6674 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6680 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6682 unsigned PreferredFusedOpcode =
6683 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6695 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6696 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6697 {FpExtX, FpExtY, NegZ});
6709 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6712 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6713 {NegY, FpExtZ, LHSReg});
6724 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6726 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6730 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6731 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6735 unsigned PreferredFusedOpcode =
6736 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6740 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6741 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6742 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6753 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6756 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6759 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6769 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6782 unsigned &IdxToPropagate)
const {
6784 switch (
MI.getOpcode()) {
6787 case TargetOpcode::G_FMINNUM:
6788 case TargetOpcode::G_FMAXNUM:
6789 PropagateNaN =
false;
6791 case TargetOpcode::G_FMINIMUM:
6792 case TargetOpcode::G_FMAXIMUM:
6793 PropagateNaN =
true;
6797 auto MatchNaN = [&](
unsigned Idx) {
6798 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6802 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6806 return MatchNaN(1) || MatchNaN(2);
6814 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6824 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6837 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6838 if (&U == &
MI || U.getParent() !=
MI.getParent())
6840 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6841 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6854 return MatchInfo.
size() >= MinUses;
6862 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6863 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6864 MatchInfo[0]->getOperand(2).getReg(),
6865 MatchInfo[0]->getFlags());
6870 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6871 Div->getOperand(0).getReg(),
MI->getFlags());
6872 MI->eraseFromParent();
6877 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6887 Reg == MaybeSameReg;
6889 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6910 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6919 return MRI.getType(MatchInfo) == DstVecTy;
6922 std::optional<ValueAndVReg> ShiftAmount;
6931 return MRI.getType(MatchInfo) == DstVecTy;
6946 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6953 std::optional<ValueAndVReg> ShiftAmt;
6959 LLT MatchTy =
MRI.getType(MatchInfo);
6960 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6961 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6964unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6966 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6967 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6968 "Expected a NaN behaviour?");
6978 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6979 return TargetOpcode::G_FMAXNUM;
6980 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6981 return TargetOpcode::G_FMAXIMUM;
6982 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6983 return TargetOpcode::G_FMAXNUM;
6984 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6985 return TargetOpcode::G_FMAXIMUM;
6991 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6992 return TargetOpcode::G_FMINNUM;
6993 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6994 return TargetOpcode::G_FMINIMUM;
6995 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6996 return TargetOpcode::G_FMINNUM;
6997 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6999 return TargetOpcode::G_FMINIMUM;
7003CombinerHelper::SelectPatternNaNBehaviour
7005 bool IsOrderedComparison)
const {
7009 if (!LHSSafe && !RHSSafe)
7010 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7011 if (LHSSafe && RHSSafe)
7012 return SelectPatternNaNBehaviour::RETURNS_ANY;
7015 if (IsOrderedComparison)
7016 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7017 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7020 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7021 : SelectPatternNaNBehaviour::RETURNS_NAN;
7030 LLT DstTy =
MRI.getType(Dst);
7043 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7045 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7047 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7050 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7051 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7052 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7053 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7055 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7058 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7063 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7068 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7070 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7074 MatchInfo = [=](MachineIRBuilder &
B) {
7075 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7083 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7090 Register TrueVal =
MI.getOperand(2).getReg();
7091 Register FalseVal =
MI.getOperand(3).getReg();
7092 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7097 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7110 if (MatchedSub &&
X != OpLHS)
7118 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7121 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7122 B.buildICmp(Pred, Dst,
Y, Zero);
7129static std::optional<unsigned>
7131 std::optional<int64_t> &Result) {
7132 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7133 Opcode == TargetOpcode::G_ASHR) &&
7134 "Expect G_SHL, G_LSHR or G_ASHR.");
7135 auto SignificantBits = 0;
7137 case TargetOpcode::G_SHL:
7141 case TargetOpcode::G_LSHR:
7145 case TargetOpcode::G_ASHR:
7154 Result = std::nullopt;
7165 Register ShiftVal =
MI.getOperand(1).getReg();
7166 Register ShiftReg =
MI.getOperand(2).getReg();
7167 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7168 auto IsShiftTooBig = [&](
const Constant *
C) {
7173 MatchInfo = std::nullopt;
7177 MI.getOpcode(), MatchInfo);
7178 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7184 unsigned LHSOpndIdx = 1;
7185 unsigned RHSOpndIdx = 2;
7186 switch (
MI.getOpcode()) {
7187 case TargetOpcode::G_UADDO:
7188 case TargetOpcode::G_SADDO:
7189 case TargetOpcode::G_UMULO:
7190 case TargetOpcode::G_SMULO:
7197 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7198 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7203 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7204 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7208 return MRI.getVRegDef(RHS)->getOpcode() !=
7209 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7216 std::optional<FPValueAndVReg> ValAndVReg;
7224 unsigned LHSOpndIdx = 1;
7225 unsigned RHSOpndIdx = 2;
7226 switch (
MI.getOpcode()) {
7227 case TargetOpcode::G_UADDO:
7228 case TargetOpcode::G_SADDO:
7229 case TargetOpcode::G_UMULO:
7230 case TargetOpcode::G_SMULO:
7237 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7238 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7239 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7240 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7244bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7245 LLT SrcTy =
MRI.getType(Src);
7246 if (SrcTy.isFixedVector())
7247 return isConstantSplatVector(Src, 1, AllowUndefs);
7248 if (SrcTy.isScalar()) {
7252 return IConstant && IConstant->Value == 1;
7257bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7258 LLT SrcTy =
MRI.getType(Src);
7260 return isConstantSplatVector(Src, 0, AllowUndefs);
7265 return IConstant && IConstant->Value == 0;
7272bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7273 bool AllowUndefs)
const {
7279 for (
unsigned I = 0;
I < NumSources; ++
I) {
7280 GImplicitDef *ImplicitDef =
7282 if (ImplicitDef && AllowUndefs)
7284 if (ImplicitDef && !AllowUndefs)
7286 std::optional<ValueAndVReg> IConstant =
7288 if (IConstant && IConstant->Value == SplatValue)
7298CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7301 return IConstant->Value;
7305 return std::nullopt;
7308 std::optional<APInt>
Value = std::nullopt;
7309 for (
unsigned I = 0;
I < NumSources; ++
I) {
7310 std::optional<ValueAndVReg> IConstant =
7313 return std::nullopt;
7315 Value = IConstant->Value;
7316 else if (*
Value != IConstant->Value)
7317 return std::nullopt;
7323bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7333 for (
unsigned I = 0;
I < NumSources; ++
I) {
7334 std::optional<ValueAndVReg> IConstant =
7343bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7350 LLT CondTy =
MRI.getType(
Select->getCondReg());
7351 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7361 std::optional<ValueAndVReg> TrueOpt =
7363 std::optional<ValueAndVReg> FalseOpt =
7366 if (!TrueOpt || !FalseOpt)
7369 APInt TrueValue = TrueOpt->Value;
7370 APInt FalseValue = FalseOpt->Value;
7374 MatchInfo = [=](MachineIRBuilder &
B) {
7375 B.setInstrAndDebugLoc(*
Select);
7376 B.buildZExtOrTrunc(Dest,
Cond);
7383 MatchInfo = [=](MachineIRBuilder &
B) {
7384 B.setInstrAndDebugLoc(*
Select);
7385 B.buildSExtOrTrunc(Dest,
Cond);
7392 MatchInfo = [=](MachineIRBuilder &
B) {
7393 B.setInstrAndDebugLoc(*
Select);
7394 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7395 B.buildNot(Inner,
Cond);
7396 B.buildZExtOrTrunc(Dest, Inner);
7403 MatchInfo = [=](MachineIRBuilder &
B) {
7404 B.setInstrAndDebugLoc(*
Select);
7405 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7406 B.buildNot(Inner,
Cond);
7407 B.buildSExtOrTrunc(Dest, Inner);
7413 if (TrueValue - 1 == FalseValue) {
7414 MatchInfo = [=](MachineIRBuilder &
B) {
7415 B.setInstrAndDebugLoc(*
Select);
7416 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7417 B.buildZExtOrTrunc(Inner,
Cond);
7418 B.buildAdd(Dest, Inner, False);
7424 if (TrueValue + 1 == FalseValue) {
7425 MatchInfo = [=](MachineIRBuilder &
B) {
7426 B.setInstrAndDebugLoc(*
Select);
7427 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7428 B.buildSExtOrTrunc(Inner,
Cond);
7429 B.buildAdd(Dest, Inner, False);
7436 MatchInfo = [=](MachineIRBuilder &
B) {
7437 B.setInstrAndDebugLoc(*
Select);
7438 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7439 B.buildZExtOrTrunc(Inner,
Cond);
7442 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7443 B.buildShl(Dest, Inner, ShAmtC, Flags);
7450 MatchInfo = [=](MachineIRBuilder &
B) {
7451 B.setInstrAndDebugLoc(*
Select);
7453 B.buildNot(Not,
Cond);
7454 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7455 B.buildZExtOrTrunc(Inner, Not);
7458 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7459 B.buildShl(Dest, Inner, ShAmtC, Flags);
7466 MatchInfo = [=](MachineIRBuilder &
B) {
7467 B.setInstrAndDebugLoc(*
Select);
7468 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7469 B.buildSExtOrTrunc(Inner,
Cond);
7470 B.buildOr(Dest, Inner, False, Flags);
7477 MatchInfo = [=](MachineIRBuilder &
B) {
7478 B.setInstrAndDebugLoc(*
Select);
7480 B.buildNot(Not,
Cond);
7481 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7482 B.buildSExtOrTrunc(Inner, Not);
7483 B.buildOr(Dest, Inner, True, Flags);
7492bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7499 LLT CondTy =
MRI.getType(
Select->getCondReg());
7500 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7509 if (CondTy != TrueTy)
7514 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7515 MatchInfo = [=](MachineIRBuilder &
B) {
7516 B.setInstrAndDebugLoc(*
Select);
7517 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7518 B.buildZExtOrTrunc(Ext,
Cond);
7519 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7520 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7527 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7528 MatchInfo = [=](MachineIRBuilder &
B) {
7529 B.setInstrAndDebugLoc(*
Select);
7530 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7531 B.buildZExtOrTrunc(Ext,
Cond);
7532 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7533 B.buildAnd(DstReg, Ext, FreezeTrue);
7539 if (isOneOrOneSplat(False,
true)) {
7540 MatchInfo = [=](MachineIRBuilder &
B) {
7541 B.setInstrAndDebugLoc(*
Select);
7543 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7544 B.buildNot(Inner,
Cond);
7546 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7547 B.buildZExtOrTrunc(Ext, Inner);
7548 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7549 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7555 if (isZeroOrZeroSplat(True,
true)) {
7556 MatchInfo = [=](MachineIRBuilder &
B) {
7557 B.setInstrAndDebugLoc(*
Select);
7559 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7560 B.buildNot(Inner,
Cond);
7562 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7563 B.buildZExtOrTrunc(Ext, Inner);
7564 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7565 B.buildAnd(DstReg, Ext, FreezeFalse);
7581 LLT DstTy =
MRI.getType(DstReg);
7587 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7596 Register CmpLHS = Cmp->getLHSReg();
7597 Register CmpRHS = Cmp->getRHSReg();
7600 if (True == CmpRHS && False == CmpLHS) {
7608 if (True != CmpLHS || False != CmpRHS)
7648 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7649 Register DestReg =
MI.getOperand(0).getReg();
7650 LLT DestTy =
MRI.getType(DestReg);
7662 if (
isLegal({NewOpc, {DestTy}})) {
7664 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7676 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7679 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7689bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7691 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7692 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7696 unsigned Flags = Logic->
getFlags();
7709 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7715 std::optional<ValueAndVReg> MaybeC1 =
7719 C1 = MaybeC1->Value;
7721 std::optional<ValueAndVReg> MaybeC2 =
7725 C2 = MaybeC2->Value;
7732 LLT CmpOperandTy =
MRI.getType(R1);
7746 std::optional<APInt> Offset1;
7747 std::optional<APInt> Offset2;
7750 std::optional<ValueAndVReg> MaybeOffset1 =
7753 R1 =
Add->getLHSReg();
7754 Offset1 = MaybeOffset1->Value;
7758 std::optional<ValueAndVReg> MaybeOffset2 =
7761 R2 =
Add->getLHSReg();
7762 Offset2 = MaybeOffset2->Value;
7781 bool CreateMask =
false;
7794 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7807 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7816 MatchInfo = [=](MachineIRBuilder &
B) {
7817 if (CreateMask &&
Offset != 0) {
7818 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7819 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7820 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7821 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7822 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7823 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7824 B.buildZExtOrTrunc(DstReg, ICmp);
7825 }
else if (CreateMask &&
Offset == 0) {
7826 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7827 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7828 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7829 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7830 B.buildZExtOrTrunc(DstReg, ICmp);
7831 }
else if (!CreateMask &&
Offset != 0) {
7832 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7833 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7834 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7835 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7836 B.buildZExtOrTrunc(DstReg, ICmp);
7837 }
else if (!CreateMask &&
Offset == 0) {
7838 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7839 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7840 B.buildZExtOrTrunc(DstReg, ICmp);
7848bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7854 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7866 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7872 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7873 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7874 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7875 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7886 if (LHS0 == RHS1 && LHS1 == RHS0) {
7892 if (LHS0 == RHS0 && LHS1 == RHS1) {
7896 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7898 MatchInfo = [=](MachineIRBuilder &
B) {
7903 auto False =
B.buildConstant(CmpTy, 0);
7904 B.buildZExtOrTrunc(DestReg, False);
7911 B.buildZExtOrTrunc(DestReg, True);
7913 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7914 B.buildZExtOrTrunc(DestReg, Cmp);
7926 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7929 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7938 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7941 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7956 bool IsSigned =
Add->isSigned();
7957 LLT DstTy =
MRI.getType(Dst);
7958 LLT CarryTy =
MRI.getType(Carry);
7961 if (
MRI.use_nodbg_empty(Carry) &&
7964 B.buildAdd(Dst, LHS, RHS);
7965 B.buildUndef(Carry);
7971 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7974 B.buildSAddo(Dst, Carry, RHS, LHS);
7980 B.buildUAddo(Dst, Carry, RHS, LHS);
7985 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7986 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7992 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7993 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7995 B.buildConstant(Dst, Result);
7996 B.buildConstant(Carry, Overflow);
8004 B.buildCopy(Dst, LHS);
8005 B.buildConstant(Carry, 0);
8014 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8017 std::optional<APInt> MaybeAddRHS =
8018 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8021 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8022 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8026 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8027 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8033 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8034 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8059 B.buildConstant(Carry, 0);
8066 B.buildAdd(Dst, LHS, RHS);
8067 B.buildConstant(Carry, 1);
8079 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8082 B.buildConstant(Carry, 0);
8098 B.buildConstant(Carry, 0);
8105 B.buildAdd(Dst, LHS, RHS);
8106 B.buildConstant(Carry, 1);
8124 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8130 auto [Dst,
Base] =
MI.getFirst2Regs();
8131 LLT Ty =
MRI.getType(Dst);
8135 Builder.buildFConstant(Dst, 1.0);
8136 MI.removeFromParent();
8148 std::optional<SrcOp> Res;
8150 while (ExpVal > 0) {
8155 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8158 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8165 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8169 MI.eraseFromParent();
8178 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8185 LLT DstTy =
MRI.getType(Dst);
8188 auto Const =
B.buildConstant(DstTy, C1 - C2);
8189 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8201 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8208 LLT DstTy =
MRI.getType(Dst);
8211 auto Const =
B.buildConstant(DstTy, C2 - C1);
8212 B.buildSub(Dst, Const,
Add->getLHSReg());
8224 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8231 LLT DstTy =
MRI.getType(Dst);
8234 auto Const =
B.buildConstant(DstTy, C1 + C2);
8247 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8254 LLT DstTy =
MRI.getType(Dst);
8257 auto Const =
B.buildConstant(DstTy, C1 - C2);
8270 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8277 LLT DstTy =
MRI.getType(Dst);
8280 auto Const =
B.buildConstant(DstTy, C2 - C1);
8281 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8328 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8332 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8335 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8336 LLT SmallBvTy = DstTy;
8340 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8345 {TargetOpcode::G_ANYEXT,
8357 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8358 Ops.push_back(AnyExt.getReg(0));
8376 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8377 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8378 const unsigned NumDstElts = OrigMask.
size();
8379 for (
unsigned i = 0; i != NumDstElts; ++i) {
8380 int Idx = OrigMask[i];
8381 if (Idx >= (
int)NumSrcElems) {
8392 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8393 std::move(NewMask));
8400 const unsigned MaskSize = Mask.size();
8401 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8406 if (Idx < (
int)NumElems)
8407 Mask[
I] = Idx + NumElems;
8409 Mask[
I] = Idx - NumElems;
8419 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8422 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8425 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8426 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8428 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8432 const unsigned NumSrcElems = Src1Ty.getNumElements();
8434 bool TouchesSrc1 =
false;
8435 bool TouchesSrc2 =
false;
8436 const unsigned NumElems = Mask.size();
8437 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8441 if (Mask[Idx] < (
int)NumSrcElems)
8447 if (TouchesSrc1 == TouchesSrc2)
8450 Register NewSrc1 = Shuffle.getSrc1Reg();
8453 NewSrc1 = Shuffle.getSrc2Reg();
8458 auto Undef =
B.buildUndef(Src1Ty);
8459 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8473 LLT DstTy =
MRI.getType(Dst);
8474 LLT CarryTy =
MRI.getType(Carry);
8496 B.buildConstant(Carry, 0);
8503 B.buildSub(Dst, LHS, RHS);
8521 B.buildConstant(Carry, 0);
8528 B.buildSub(Dst, LHS, RHS);
8545 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8546 "Expected G_CTLZ variant");
8551 LLT Ty =
MRI.getType(Dst);
8552 LLT SrcTy =
MRI.getType(Src);
8554 if (!(Ty.isValid() && Ty.isScalar()))
8563 switch (
LI->getAction(Query).Action) {
8574 bool NeedAdd =
true;
8582 unsigned BitWidth = Ty.getScalarSizeInBits();
8593 B.buildCTLS(Dst,
X);
8597 auto Ctls =
B.buildCTLS(Ty,
X);
8598 auto One =
B.buildConstant(Ty, 1);
8600 B.buildAdd(Dst, Ctls, One);
unsigned const MachineRegisterInfo * MRI
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
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,...
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
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...
unsigned PostShift
post-shift amount