47#define DEBUG_TYPE "gi-combiner"
56 cl::desc(
"Force all indexed operations to be "
57 "legal for the GlobalISel combiner"));
66 TII(
Builder.getMF().getSubtarget().getInstrInfo()),
67 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
68 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
73 return *
Builder.getMF().getSubtarget().getTargetLowering();
87 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
95 LLT Ty = MRI.getType(V);
106 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
107 return ByteWidth -
I - 1;
127static std::optional<bool>
131 unsigned Width = MemOffset2Idx.
size();
134 bool BigEndian =
true, LittleEndian =
true;
135 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
136 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
137 if (MemOffsetAndIdx == MemOffset2Idx.
end())
139 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
140 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
143 if (!BigEndian && !LittleEndian)
147 assert((BigEndian != LittleEndian) &&
148 "Pattern cannot be both big and little endian!");
155 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
183 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
184 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
191 if (
MRI.constrainRegAttrs(ToReg, FromReg))
192 MRI.replaceRegWith(FromReg, ToReg);
194 Builder.buildCopy(FromReg, ToReg);
196 Observer.finishedChangingAllUsesOfReg();
211 unsigned ToOpcode)
const {
226 MRI.setRegBank(Reg, *RegBank);
230 if (
MI.getOpcode() != TargetOpcode::COPY)
240 MI.eraseFromParent();
245 assert(
MI.getOpcode() == TargetOpcode::G_FREEZE &&
"Invalid instruction");
251 if (!
MRI.hasOneNonDBGUse(OrigOp))
272 std::optional<MachineOperand> MaybePoisonOperand;
274 if (!Operand.isReg())
280 if (!MaybePoisonOperand)
281 MaybePoisonOperand = Operand;
290 if (!MaybePoisonOperand) {
295 B.buildCopy(
DstOp, OrigOp);
300 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
301 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
304 {TargetOpcode::G_FREEZE, {MaybePoisonOperandRegTy}}))
312 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
323 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
324 "Invalid instruction");
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();
408 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
413 LLT InputTy =
MRI.getType(BCSrc);
415 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
420 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
424 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
440 Ops.push_back(BCSrc);
461 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
462 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
463 MI.eraseFromParent();
469 Register SrcVec1 = Shuffle.getSrc1Reg();
470 Register SrcVec2 = Shuffle.getSrc2Reg();
471 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
472 int Width =
MRI.getType(SrcVec1).getNumElements();
474 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
475 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
479 for (
int Val : Shuffle.getMask()) {
482 else if (Val < Width)
483 Extracts.
push_back(Unmerge1.getReg(Val));
485 Extracts.
push_back(Unmerge2.getReg(Val - Width));
487 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
488 if (Extracts.
size() == 1)
489 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
491 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
492 MI.eraseFromParent();
509 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
511 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
515 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
516 if (i + j >= Mask.size())
518 if (Mask[i + j] != -1)
522 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
525 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
526 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
527 if (i + j >= Mask.size())
529 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
546 {TargetOpcode::G_CONCAT_VECTORS,
547 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
558 SrcTy =
MRI.getType(Reg);
560 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
567 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
573 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
576 MI.eraseFromParent();
581 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
582 "Invalid instruction kind");
583 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
585 LLT SrcType =
MRI.getType(Src1);
587 unsigned DstNumElts = DstType.getNumElements();
588 unsigned SrcNumElts = SrcType.getNumElements();
605 if (DstNumElts < 2 * SrcNumElts)
610 if (DstNumElts % SrcNumElts != 0)
616 unsigned NumConcat = DstNumElts / SrcNumElts;
619 for (
unsigned i = 0; i != DstNumElts; ++i) {
626 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
627 (ConcatSrcs[i / SrcNumElts] >= 0 &&
628 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
631 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
638 for (
auto Src : ConcatSrcs) {
642 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
644 Ops.push_back(UndefReg);
657 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
665 MI.eraseFromParent();
674 const LLT TyForCandidate,
675 unsigned OpcodeForCandidate,
680 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
691 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
694 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
695 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
696 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
704 OpcodeForCandidate == TargetOpcode::G_ZEXT)
706 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
707 OpcodeForCandidate == TargetOpcode::G_SEXT)
708 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
717 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
728static void InsertInsnsWithoutSideEffectsBeforeUse(
740 InsertBB = PredBB->
getMBB();
745 if (InsertBB ==
DefMI.getParent()) {
747 Inserter(InsertBB, std::next(InsertPt), UseMO);
766 unsigned CandidateLoadOpc;
768 case TargetOpcode::G_ANYEXT:
769 CandidateLoadOpc = TargetOpcode::G_LOAD;
771 case TargetOpcode::G_SEXT:
772 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
774 case TargetOpcode::G_ZEXT:
775 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
780 return CandidateLoadOpc;
797 LLT LoadValueTy =
MRI.getType(LoadReg);
819 unsigned PreferredOpcode =
821 ? TargetOpcode::G_ANYEXT
823 Preferred = {
LLT(), PreferredOpcode,
nullptr};
824 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
825 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
826 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
827 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
828 const auto &MMO = LoadMI->
getMMO();
836 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
838 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
842 Preferred = ChoosePreferredUse(
MI, Preferred,
843 MRI.getType(
UseMI.getOperand(0).getReg()),
853 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
871 if (PreviouslyEmitted) {
878 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
879 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
881 EmittedInsns[InsertIntoBB] = NewMI;
887 MI.setDesc(
Builder.getTII().get(LoadOpc));
894 for (
auto *UseMO :
Uses) {
900 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
903 const LLT UseDstTy =
MRI.getType(UseDstReg);
904 if (UseDstReg != ChosenDstReg) {
905 if (Preferred.
Ty == UseDstTy) {
942 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
957 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
960 MI.getOperand(0).setReg(ChosenDstReg);
966 assert(
MI.getOpcode() == TargetOpcode::G_AND);
977 if (
MRI.getType(Dst).isVector())
985 APInt MaskVal = MaybeMask->Value;
1000 LLT RegTy =
MRI.getType(LoadReg);
1003 unsigned MaskSizeBits = MaskVal.
countr_one();
1006 !
MRI.hasOneNonDBGUse(LoadReg))
1011 if (MaskSizeBits > LoadSizeBits)
1030 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1035 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1039 B.setInstrAndDebugLoc(*LoadMI);
1040 auto &MF =
B.getMF();
1042 auto *NewMMO = MF.getMachineMemOperand(MMO, PtrInfo, MemDesc.
MemoryTy);
1043 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1053 "shouldn't consider debug uses");
1061 if (DefOrUse ==
MBB.end())
1063 return &*DefOrUse == &
DefMI;
1069 "shouldn't consider debug uses");
1072 else if (
DefMI.getParent() !=
UseMI.getParent())
1079 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1083 if (
MRI.getType(SrcReg).isVector())
1088 LoadUser = TruncSrc;
1090 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1095 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1097 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1099 if (LoadSizeBits == SizeInBits)
1106 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1107 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1110 LLT RegTy =
MRI.getType(DstReg);
1123 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1125 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1131 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1134 if (NewSizeBits < 8)
1147 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1152 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1155 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1160 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1161 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1163 unsigned ScalarSizeBits;
1164 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1173 auto &MMO = LoadDef->
getMMO();
1174 Builder.setInstrAndDebugLoc(*LoadDef);
1176 auto PtrInfo = MMO.getPointerInfo();
1177 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1178 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1181 MI.eraseFromParent();
1192 auto *MF =
MI->getMF();
1199 AM.
BaseOffs = CstOff->getSExtValue();
1204 MF->getDataLayout(), AM,
1206 MF->getFunction().getContext()),
1207 MI->getMMO().getAddrSpace());
1212 case TargetOpcode::G_LOAD:
1213 return TargetOpcode::G_INDEXED_LOAD;
1214 case TargetOpcode::G_STORE:
1215 return TargetOpcode::G_INDEXED_STORE;
1216 case TargetOpcode::G_ZEXTLOAD:
1217 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1218 case TargetOpcode::G_SEXTLOAD:
1219 return TargetOpcode::G_INDEXED_SEXTLOAD;
1225bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1235 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1236 OpTys = {PtrTy, Ty, Ty};
1238 OpTys = {Ty, PtrTy};
1240 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1246 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1247 "considered for post-indexing."));
1251 bool &RematOffset)
const {
1264 if (!isIndexedLoadStoreLegal(LdSt))
1275 unsigned NumUsesChecked = 0;
1288 if (StoredValDef == &
Use)
1291 Offset = PtrAdd->getOffsetReg();
1293 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1301 RematOffset =
false;
1305 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1310 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1311 if (&BasePtrUse == PtrDef)
1317 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1319 isIndexedLoadStoreLegal(*BasePtrLdSt))
1325 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1326 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1329 if (BaseUseUse.getParent() != LdSt.
getParent())
1341 Addr = PtrAdd->getReg(0);
1342 Base = PtrAdd->getBaseReg();
1357 MRI.hasOneNonDBGUse(Addr))
1364 if (!isIndexedLoadStoreLegal(LdSt))
1368 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1373 if (
Base == St->getValueReg())
1378 if (St->getValueReg() == Addr)
1383 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1384 if (AddrUse.getParent() != LdSt.
getParent())
1389 bool RealUse =
false;
1390 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1408 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1418 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1425 if (!LoadMI->isSimple())
1437 const unsigned MaxIter = 20;
1439 for (
const auto &Instr :
1441 if (Instr.isLoadFoldBarrier())
1443 if (Iter++ == MaxIter)
1459 int Elt = CVal->getZExtValue();
1472 Register VecPtr = LoadMI->getPointerReg();
1473 LLT PtrTy =
MRI.getType(VecPtr);
1481 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1504 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1519 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1521 if (!MatchInfo.
IsPre &&
1522 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1532 unsigned Opcode =
MI.getOpcode();
1533 bool IsStore = Opcode == TargetOpcode::G_STORE;
1539 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1541 *OldCst->getOperand(1).getCImm());
1542 MatchInfo.
Offset = NewCst.getReg(0);
1545 auto MIB =
Builder.buildInstr(NewOpcode);
1547 MIB.addDef(MatchInfo.
Addr);
1548 MIB.addUse(
MI.getOperand(0).getReg());
1550 MIB.addDef(
MI.getOperand(0).getReg());
1551 MIB.addDef(MatchInfo.
Addr);
1554 MIB.addUse(MatchInfo.
Base);
1555 MIB.addUse(MatchInfo.
Offset);
1556 MIB.addImm(MatchInfo.
IsPre);
1557 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1558 MI.eraseFromParent();
1566 unsigned Opcode =
MI.getOpcode();
1567 bool IsDiv, IsSigned;
1572 case TargetOpcode::G_SDIV:
1573 case TargetOpcode::G_UDIV: {
1575 IsSigned = Opcode == TargetOpcode::G_SDIV;
1578 case TargetOpcode::G_SREM:
1579 case TargetOpcode::G_UREM: {
1581 IsSigned = Opcode == TargetOpcode::G_SREM;
1587 unsigned DivOpcode, RemOpcode, DivremOpcode;
1589 DivOpcode = TargetOpcode::G_SDIV;
1590 RemOpcode = TargetOpcode::G_SREM;
1591 DivremOpcode = TargetOpcode::G_SDIVREM;
1593 DivOpcode = TargetOpcode::G_UDIV;
1594 RemOpcode = TargetOpcode::G_UREM;
1595 DivremOpcode = TargetOpcode::G_UDIVREM;
1613 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1614 if (
MI.getParent() ==
UseMI.getParent() &&
1615 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1616 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1629 unsigned Opcode =
MI.getOpcode();
1630 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1633 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1634 DestDivReg =
MI.getOperand(0).getReg();
1638 DestRemReg =
MI.getOperand(0).getReg();
1642 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1649 Builder.setInstrAndDebugLoc(*FirstInst);
1651 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1652 : TargetOpcode::G_UDIVREM,
1653 {DestDivReg, DestRemReg},
1655 MI.eraseFromParent();
1661 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1678 if (BrIt ==
MBB->begin())
1680 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1682 BrCond = &*std::prev(BrIt);
1683 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1689 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1690 MBB->isLayoutSuccessor(BrCondTarget);
1696 Builder.setInstrAndDebugLoc(*BrCond);
1707 MI.getOperand(0).setMBB(FallthroughBB);
1720 unsigned MaxLen)
const {
1721 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1723 DstAlignCanChange, MemOps);
1728 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1733 DstAlignCanChange, MemOps) ==
1735 assert(
Changed &&
"expected memcpy-family instruction to lower");
1740 unsigned MaxLen)
const {
1752 switch (
MI.getOpcode()) {
1755 case TargetOpcode::G_FNEG: {
1756 Result.changeSign();
1759 case TargetOpcode::G_FABS: {
1763 case TargetOpcode::G_FCEIL:
1766 case TargetOpcode::G_FFLOOR:
1769 case TargetOpcode::G_INTRINSIC_TRUNC:
1772 case TargetOpcode::G_INTRINSIC_ROUND:
1775 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1778 case TargetOpcode::G_FRINT:
1779 case TargetOpcode::G_FNEARBYINT:
1783 case TargetOpcode::G_FPEXT:
1784 case TargetOpcode::G_FPTRUNC: {
1791 case TargetOpcode::G_FSQRT: {
1795 Result =
APFloat(sqrt(Result.convertToDouble()));
1798 case TargetOpcode::G_FLOG2: {
1818 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1819 MI.eraseFromParent();
1830 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1853 Type *AccessTy =
nullptr;
1854 auto &MF = *
MI.getMF();
1855 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1858 MF.getFunction().getContext());
1863 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1868 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1870 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1871 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1872 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1873 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1882 unsigned PtrAddFlags =
MI.getFlags();
1898 MatchInfo.
Flags = Flags;
1904 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1906 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1910 MI.getOperand(1).setReg(MatchInfo.
Base);
1911 MI.getOperand(2).setReg(NewOffset.getReg(0));
1925 unsigned Opcode =
MI.getOpcode();
1926 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1927 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1928 Opcode == TargetOpcode::G_USHLSAT) &&
1929 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1949 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1954 if (Opcode == TargetOpcode::G_USHLSAT &&
1955 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1963 unsigned Opcode =
MI.getOpcode();
1964 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1965 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1966 Opcode == TargetOpcode::G_USHLSAT) &&
1967 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1969 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1970 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1971 auto Imm = MatchInfo.
Imm;
1973 if (
Imm >= ScalarSizeInBits) {
1975 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1976 Builder.buildConstant(
MI.getOperand(0), 0);
1977 MI.eraseFromParent();
1982 Imm = ScalarSizeInBits - 1;
1985 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1988 MI.getOperand(1).setReg(MatchInfo.
Reg);
1989 MI.getOperand(2).setReg(NewImm);
2005 unsigned ShiftOpcode =
MI.getOpcode();
2006 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2007 ShiftOpcode == TargetOpcode::G_ASHR ||
2008 ShiftOpcode == TargetOpcode::G_LSHR ||
2009 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2010 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2011 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2014 Register LogicDest =
MI.getOperand(1).getReg();
2015 if (!
MRI.hasOneNonDBGUse(LogicDest))
2021 unsigned LogicOpcode = LogicMI->
getOpcode();
2022 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2023 LogicOpcode != TargetOpcode::G_XOR)
2027 const Register C1 =
MI.getOperand(2).getReg();
2029 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2032 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2034 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2036 if (
MI->getOpcode() != ShiftOpcode ||
2037 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2046 ShiftVal = MaybeImmVal->Value.getSExtValue();
2060 if (matchFirstShift(LogicMIOp1, C0Val)) {
2062 MatchInfo.
Shift2 = LogicMIOp1;
2063 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2065 MatchInfo.
Shift2 = LogicMIOp2;
2069 MatchInfo.
ValSum = C0Val + C1Val;
2072 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2075 MatchInfo.
Logic = LogicMI;
2081 unsigned Opcode =
MI.getOpcode();
2082 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2083 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2084 Opcode == TargetOpcode::G_SSHLSAT) &&
2085 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2087 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2088 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2094 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2103 Register Shift2Const =
MI.getOperand(2).getReg();
2105 .buildInstr(Opcode, {DestType},
2115 MI.eraseFromParent();
2127 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2131 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2146 LLT InnerShiftTy =
MRI.getType(InnerShift);
2148 if ((N1C + N001C).ult(InnerShiftSize)) {
2154 if ((N001C + OpSizeInBits) == InnerShiftSize)
2156 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2157 MatchInfo.
Mask =
true;
2167 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2174 if (MatchInfo.
Mask ==
true) {
2182 Builder.buildTrunc(Dst, Shift);
2183 MI.eraseFromParent();
2187 unsigned &ShiftVal)
const {
2188 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2194 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2195 return (
static_cast<int32_t
>(ShiftVal) != -1);
2199 unsigned &ShiftVal)
const {
2200 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2202 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2205 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2206 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2227 auto NegCst =
B.buildConstant(Ty, -
Imm);
2229 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2230 MI.getOperand(2).setReg(NegCst.getReg(0));
2232 if (
Imm.isMinSignedValue())
2242 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2256 if (!MaybeShiftAmtVal)
2260 LLT SrcTy =
MRI.getType(ExtSrc);
2270 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2271 MatchData.
Reg = ExtSrc;
2272 MatchData.
Imm = ShiftAmt;
2274 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2275 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2276 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2282 int64_t ShiftAmtVal = MatchData.
Imm;
2284 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2285 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2287 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2288 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2289 MI.eraseFromParent();
2302 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2303 "Expected an unmerge");
2312 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2313 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2315 if (SrcMergeTy != Dst0Ty && !SameSize)
2319 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2320 Operands.push_back(SrcInstr->getSourceReg(Idx));
2326 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2327 "Expected an unmerge");
2329 "Not enough operands to replace all defs");
2330 unsigned NumElems =
MI.getNumOperands() - 1;
2333 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2334 bool CanReuseInputDirectly = DstTy == SrcTy;
2335 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2336 Register DstReg =
MI.getOperand(Idx).getReg();
2341 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2342 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2343 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2344 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2347 if (CanReuseInputDirectly)
2350 Builder.buildCast(DstReg, SrcReg);
2352 MI.eraseFromParent();
2357 unsigned SrcIdx =
MI.getNumOperands() - 1;
2358 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2364 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2367 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2369 Val = Val.
lshr(ShiftAmt);
2377 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2378 "Expected an unmerge");
2380 "Not enough operands to replace all defs");
2381 unsigned NumElems =
MI.getNumOperands() - 1;
2382 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2383 Register DstReg =
MI.getOperand(Idx).getReg();
2384 Builder.buildConstant(DstReg, Csts[Idx]);
2387 MI.eraseFromParent();
2393 unsigned SrcIdx =
MI.getNumOperands() - 1;
2394 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2396 unsigned NumElems =
MI.getNumOperands() - 1;
2397 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2398 Register DstReg =
MI.getOperand(Idx).getReg();
2399 B.buildUndef(DstReg);
2407 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2408 "Expected an unmerge");
2409 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2410 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2413 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2414 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2422 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2423 Register Dst0Reg =
MI.getOperand(0).getReg();
2424 Builder.buildTrunc(Dst0Reg, SrcReg);
2425 MI.eraseFromParent();
2429 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2430 "Expected an unmerge");
2431 Register Dst0Reg =
MI.getOperand(0).getReg();
2432 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2438 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2439 LLT SrcTy =
MRI.getType(SrcReg);
2440 if (SrcTy.isVector())
2450 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2455 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2456 "Expected an unmerge");
2458 Register Dst0Reg =
MI.getOperand(0).getReg();
2463 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2464 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2467 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2470 "ZExt src doesn't fit in destination");
2475 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2477 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2480 MI.eraseFromParent();
2484 unsigned TargetShiftSize,
2485 unsigned &ShiftVal)
const {
2486 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2487 MI.getOpcode() == TargetOpcode::G_LSHR ||
2488 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2490 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2495 unsigned Size = Ty.getSizeInBits();
2496 if (
Size <= TargetShiftSize)
2504 ShiftVal = MaybeImmVal->Value.getSExtValue();
2505 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2512 LLT Ty =
MRI.getType(SrcReg);
2513 unsigned Size = Ty.getSizeInBits();
2514 unsigned HalfSize =
Size / 2;
2515 assert(ShiftVal >= HalfSize);
2519 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2520 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2522 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2523 Register Narrowed = Unmerge.getReg(1);
2530 if (NarrowShiftAmt != 0) {
2531 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2532 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2535 auto Zero =
Builder.buildConstant(HalfTy, 0);
2536 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2537 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2538 Register Narrowed = Unmerge.getReg(0);
2543 if (NarrowShiftAmt != 0) {
2544 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2545 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2548 auto Zero =
Builder.buildConstant(HalfTy, 0);
2549 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2551 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2553 HalfTy, Unmerge.getReg(1),
2554 Builder.buildConstant(HalfTy, HalfSize - 1));
2556 if (ShiftVal == HalfSize) {
2559 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2560 }
else if (ShiftVal ==
Size - 1) {
2568 HalfTy, Unmerge.getReg(1),
2569 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2577 MI.eraseFromParent();
2593 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2598 SrcReg = OriginalSrcReg;
2599 LLT DstTy =
MRI.getType(DstReg);
2607 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2610 LLT DstTy =
MRI.getType(DstReg);
2615 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2616 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2626 if (ShiftSize > 32 && TruncSize < 32)
2639 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2640 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2644 if (!
MRI.hasOneNonDBGUse(SrcReg))
2647 LLT SrcTy =
MRI.getType(SrcReg);
2648 LLT DstTy =
MRI.getType(DstReg);
2657 case TargetOpcode::G_SHL: {
2666 case TargetOpcode::G_LSHR:
2667 case TargetOpcode::G_ASHR: {
2673 for (
auto &
User :
MRI.use_instructions(DstReg))
2674 if (
User.getOpcode() == TargetOpcode::G_STORE)
2678 if (NewShiftTy == SrcTy)
2692 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2695 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2700 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2702 LLT NewShiftTy = MatchInfo.second;
2705 LLT DstTy =
MRI.getType(Dst);
2709 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2712 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2713 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2714 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2718 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2721 if (NewShiftTy == DstTy)
2724 Builder.buildTrunc(Dst, NewShift);
2731 return !MO.isReg() ||
2732 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2737 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2739 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2744 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2745 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2746 "Expected an insert/extract element op");
2747 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2752 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2800 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2827 return MO.isReg() && MO.getReg().isPhysical();
2837 return I1->isIdenticalTo(*I2);
2845 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2852 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2873 std::optional<FPValueAndVReg> MaybeCst;
2877 return MaybeCst->Value.isExactlyValue(
C);
2881 unsigned OpIdx)
const {
2882 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2884 Register Replacement =
MI.getOperand(OpIdx).getReg();
2887 MI.eraseFromParent();
2892 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2896 MI.eraseFromParent();
2900 unsigned ConstIdx)
const {
2901 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2902 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2914 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2915 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2916 "This is not a funnel shift operation");
2918 Register ConstReg =
MI.getOperand(3).getReg();
2919 LLT ConstTy =
MRI.getType(ConstReg);
2920 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2923 assert((VRegAndVal) &&
"Value is not a constant");
2926 APInt NewConst = VRegAndVal->Value.
urem(
2931 MI.getOpcode(), {MI.getOperand(0)},
2932 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2934 MI.eraseFromParent();
2938 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2952 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2954 MI.eraseFromParent();
2959 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2961 MI.eraseFromParent();
2965 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2967 MI.eraseFromParent();
2972 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2974 MI.eraseFromParent();
2978 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2980 MI.eraseFromParent();
2985 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
2988 LLT DstTy =
MRI.getType(DstReg);
2997 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
2998 TargetOpcode::G_INSERT_VECTOR_ELT)
3004 MatchInfo.
resize(NumElts);
3008 if (IntImm >= NumElts || IntImm < 0)
3010 if (!MatchInfo[IntImm])
3011 MatchInfo[IntImm] = TmpReg;
3015 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3017 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3026 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3033 auto GetUndef = [&]() {
3036 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3044 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3045 MI.eraseFromParent();
3058 unsigned InnerOpc = InnerDef->
getOpcode();
3059 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3083 if (!TryMatch(InnerLHS, InnerRHS) &&
3084 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3088 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3089 : TargetOpcode::G_ADD;
3092 MatchInfo = [=](MachineIRBuilder &
Builder) {
3093 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3094 auto NewNot =
Builder.buildNot(Ty, NewInner);
3095 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3107 unsigned RootOpc =
MI.getOpcode();
3109 LLT Ty =
MRI.getType(Dst);
3114 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3115 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3126 unsigned LogicOpcode =
MI.getOpcode();
3127 assert(LogicOpcode == TargetOpcode::G_AND ||
3128 LogicOpcode == TargetOpcode::G_OR ||
3129 LogicOpcode == TargetOpcode::G_XOR);
3136 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3142 if (!LeftHandInst || !RightHandInst)
3144 unsigned HandOpcode = LeftHandInst->
getOpcode();
3145 if (HandOpcode != RightHandInst->
getOpcode())
3159 if (!XTy.
isValid() || XTy != YTy)
3164 switch (HandOpcode) {
3167 case TargetOpcode::G_ANYEXT:
3168 case TargetOpcode::G_SEXT:
3169 case TargetOpcode::G_ZEXT: {
3173 case TargetOpcode::G_TRUNC: {
3178 LLT DstTy =
MRI.getType(Dst);
3187 case TargetOpcode::G_AND:
3188 case TargetOpcode::G_ASHR:
3189 case TargetOpcode::G_LSHR:
3190 case TargetOpcode::G_SHL: {
3195 ExtraHandOpSrcReg = ZOp.
getReg();
3206 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3217 if (ExtraHandOpSrcReg.
isValid())
3229 "Expected at least one instr to build?");
3231 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3232 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3234 for (
auto &OperandFn : InstrToBuild.OperandFns)
3237 MI.eraseFromParent();
3241 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3242 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3243 int64_t ShlCst, AshrCst;
3249 if (ShlCst != AshrCst)
3252 {TargetOpcode::G_SEXT_INREG,
3255 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3257 MatchInfo = std::make_tuple(Src, ShlCst);
3262 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3263 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3266 std::tie(Src, ShiftAmt) = MatchInfo;
3267 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3268 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3269 MI.eraseFromParent();
3276 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3279 LLT Ty =
MRI.getType(Dst);
3291 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3294 auto Zero =
B.buildConstant(Ty, 0);
3317 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3341 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3348 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3365 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3383 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3390 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3401 unsigned ExtBits =
MI.getOperand(2).getImm();
3402 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3403 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3407 int64_t Cst,
bool IsVector,
bool IsFP) {
3409 return (ScalarSizeBits == 1 && Cst == -1) ||
3431 unsigned BuildUseCount = BV.getNumSources();
3432 if (BuildUseCount % 2 != 0)
3435 unsigned NumUnmerge = BuildUseCount / 2;
3441 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3444 UnmergeSrc = Unmerge->getSourceReg();
3446 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3447 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3454 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3459 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3460 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3463 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3466 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3471 if (Unmerge->getNumDefs() != NumUnmerge)
3475 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3478 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3489 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3490 B.setInstrAndDebugLoc(
MI);
3492 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3493 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3495 MI.eraseFromParent();
3517 unsigned NumOperands =
BuildMI->getNumSources();
3527 for (
I = 0;
I < NumOperands; ++
I) {
3539 UnmergeMI != UnmergeSrcMI)
3550 for (;
I < NumOperands; ++
I) {
3557 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3567 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3568 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3576 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3579 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3591 LLT DstTy =
MRI.getType(DstReg);
3592 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3597 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3602 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3606 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3609 Builder.buildTrunc(DstReg, MidReg);
3610 MI.eraseFromParent();
3615 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3616 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3617 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3625 if (!
MRI.hasOneNonDBGUse(XorSrc))
3635 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3637 if (!
MRI.hasOneNonDBGUse(Reg))
3642 switch (Def->getOpcode()) {
3647 case TargetOpcode::G_ICMP:
3653 case TargetOpcode::G_FCMP:
3659 case TargetOpcode::G_AND:
3660 case TargetOpcode::G_OR:
3666 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3667 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3675 if (Ty.isVector()) {
3679 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), SplatCst,
true, IsFP))
3693 for (
Register Reg : RegsToNegate) {
3698 switch (Def->getOpcode()) {
3701 case TargetOpcode::G_ICMP:
3702 case TargetOpcode::G_FCMP: {
3709 case TargetOpcode::G_AND:
3710 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3712 case TargetOpcode::G_OR:
3713 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3720 MI.eraseFromParent();
3724 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3726 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3730 Register SharedReg =
MI.getOperand(2).getReg();
3744 if (!
MRI.hasOneNonDBGUse(AndReg))
3751 return Y == SharedReg;
3755 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3758 std::tie(
X,
Y) = MatchInfo;
3761 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3762 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3763 MI.getOperand(2).setReg(
Y);
3769 Register DstReg = PtrAdd.getReg(0);
3770 LLT Ty =
MRI.getType(DstReg);
3773 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3788 Register Pow2Src1 =
MI.getOperand(2).getReg();
3789 LLT Ty =
MRI.getType(DstReg);
3792 auto NegOne =
Builder.buildConstant(Ty, -1);
3793 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3795 MI.eraseFromParent();
3799 unsigned &SelectOpNo)
const {
3811 !
MRI.hasOneNonDBGUse(LHS)) {
3812 OtherOperandReg = LHS;
3816 !
MRI.hasOneNonDBGUse(RHS))
3834 unsigned BinOpcode =
MI.getOpcode();
3839 bool CanFoldNonConst =
3840 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3845 if (CanFoldNonConst)
3870 LLT Ty =
MRI.getType(Dst);
3871 unsigned BinOpcode =
MI.getOpcode();
3878 if (SelectOperand == 1) {
3882 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3884 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3886 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3888 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3891 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3892 MI.eraseFromParent();
3895std::optional<SmallVector<Register, 8>>
3896CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3897 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3926 const unsigned MaxIter =
3928 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3937 return std::nullopt;
3953 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3954 return std::nullopt;
3966static std::optional<std::pair<GZExtLoad *, int64_t>>
3970 "Expected Reg to only have one non-debug use?");
3979 if (Shift % MemSizeInBits != 0)
3980 return std::nullopt;
3985 return std::nullopt;
3987 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
3988 return std::nullopt;
3990 return std::make_pair(
Load, Shift / MemSizeInBits);
3993std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
3994CombinerHelper::findLoadOffsetsForLoadOrCombine(
3997 const unsigned MemSizeInBits)
const {
4000 SmallSetVector<const MachineInstr *, 8> Loads;
4006 GZExtLoad *LowestIdxLoad =
nullptr;
4009 SmallSet<int64_t, 8> SeenIdx;
4013 MachineBasicBlock *
MBB =
nullptr;
4014 const MachineMemOperand *MMO =
nullptr;
4017 GZExtLoad *EarliestLoad =
nullptr;
4020 GZExtLoad *LatestLoad =
nullptr;
4029 for (
auto Reg : RegsToVisit) {
4034 return std::nullopt;
4037 std::tie(
Load, DstPos) = *LoadAndPos;
4041 MachineBasicBlock *LoadMBB =
Load->getParent();
4045 return std::nullopt;
4048 auto &LoadMMO =
Load->getMMO();
4052 return std::nullopt;
4059 LoadPtr =
Load->getOperand(1).getReg();
4064 if (!SeenIdx.
insert(Idx).second)
4065 return std::nullopt;
4072 if (BasePtr != LoadPtr)
4073 return std::nullopt;
4075 if (Idx < LowestIdx) {
4077 LowestIdxLoad =
Load;
4084 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4085 return std::nullopt;
4094 EarliestLoad =
Load;
4102 "Expected to find a load for each register?");
4103 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4104 LatestLoad &&
"Expected at least two loads?");
4113 const unsigned MaxIter = 20;
4119 if (
MI.isLoadFoldBarrier())
4120 return std::nullopt;
4121 if (Iter++ == MaxIter)
4122 return std::nullopt;
4125 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4131 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4144 LLT Ty =
MRI.getType(Dst);
4150 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4151 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4155 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4162 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4163 if (NarrowMemSizeInBits % 8 != 0)
4176 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4177 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4180 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4187 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4190 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4202 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4203 const unsigned ZeroByteOffset =
4207 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4208 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4209 ZeroOffsetIdx->second != LowestIdx)
4219 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4233 MIB.setInstrAndDebugLoc(*LatestLoad);
4234 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4235 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4237 MIB.buildBSwap(Dst, LoadDst);
4249 if (
MRI.getType(DstReg).isVector())
4253 if (!
MRI.hasOneNonDBGUse(DstReg))
4255 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4257 case TargetOpcode::G_ANYEXT:
4259 case TargetOpcode::G_ZEXT:
4260 case TargetOpcode::G_SEXT:
4267 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4274 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4276 switch (
DefMI->getOpcode()) {
4277 case TargetOpcode::G_LOAD:
4278 case TargetOpcode::G_TRUNC:
4279 case TargetOpcode::G_SEXT:
4280 case TargetOpcode::G_ZEXT:
4281 case TargetOpcode::G_ANYEXT:
4282 case TargetOpcode::G_CONSTANT:
4286 if (InSrcs.
size() > 2)
4300 LLT ExtTy =
MRI.getType(DstReg);
4307 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4308 auto SrcReg =
PHI.getIncomingValue(
I);
4312 if (!SrcMIs.
insert(SrcMI))
4318 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4319 InsertPt =
MBB->getFirstNonPHI();
4324 OldToNewSrcMap[SrcMI] = NewExt;
4329 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4330 NewPhi.addDef(DstReg);
4333 NewPhi.addMBB(MO.getMBB());
4336 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4337 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4345 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4349 LLT SrcTy =
MRI.getType(SrcVec);
4350 if (SrcTy.isScalableVector())
4354 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4357 unsigned VecIdx = Cst->Value.getZExtValue();
4369 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4370 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4374 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4386 LLT ScalarTy =
MRI.getType(Reg);
4388 LLT DstTy =
MRI.getType(DstReg);
4390 if (ScalarTy != DstTy) {
4392 Builder.buildTrunc(DstReg, Reg);
4393 MI.eraseFromParent();
4401 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4402 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4420 LLT DstTy =
MRI.getType(DstReg);
4425 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4430 unsigned Idx = Cst->getZExtValue();
4433 ExtractedElts.
set(Idx);
4434 SrcDstPairs.emplace_back(
4435 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4438 return ExtractedElts.
all();
4443 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4444 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4445 for (
auto &Pair : SrcDstPairs) {
4446 auto *ExtMI = Pair.second;
4448 ExtMI->eraseFromParent();
4450 MI.eraseFromParent();
4457 MI.eraseFromParent();
4467 bool AllowScalarConstants,
4469 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4472 LLT Ty =
MRI.getType(Dst);
4473 unsigned BitWidth = Ty.getScalarSizeInBits();
4475 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4476 unsigned FshOpc = 0;
4487 int64_t CstShlAmt = 0, CstLShrAmt;
4490 CstShlAmt + CstLShrAmt ==
BitWidth) {
4491 FshOpc = TargetOpcode::G_FSHR;
4497 FshOpc = TargetOpcode::G_FSHL;
4502 FshOpc = TargetOpcode::G_FSHR;
4507 LLT AmtTy =
MRI.getType(Amt);
4509 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4513 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4520 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4521 MI.getOpcode() == TargetOpcode::G_ROTR);
4523 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4525 bool OutOfRange =
false;
4526 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4528 OutOfRange |= CI->getValue().uge(Bitsize);
4535 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4536 MI.getOpcode() == TargetOpcode::G_ROTR);
4538 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4540 LLT AmtTy =
MRI.getType(Amt);
4541 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4542 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4544 MI.getOperand(2).setReg(Amt);
4549 int64_t &MatchInfo)
const {
4550 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4561 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4562 if (KnownRHS.isUnknown())
4565 std::optional<bool> KnownVal;
4566 if (KnownRHS.isZero()) {
4576 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4586 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4595 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4611 LLT DstTy =
MRI.getType(Dst);
4619 auto KnownLHS =
VT->getKnownBits(LHS);
4620 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4623 LLT LHSTy =
MRI.getType(LHS);
4626 unsigned Op = TargetOpcode::COPY;
4627 if (DstSize != LHSSize)
4628 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4639 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4643 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4649 int64_t AndMaskBits;
4657 if (AndMaskBits & OrMaskBits)
4663 if (
MI.getOperand(1).getReg() == AndMaskReg)
4664 MI.getOperand(2).setReg(AndMaskReg);
4665 MI.getOperand(1).setReg(Src);
4675 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4678 LLT Ty =
MRI.getType(Src);
4680 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4682 int64_t Width =
MI.getOperand(2).getImm();
4690 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4694 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4695 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4696 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4706 LLT Ty =
MRI.getType(Dst);
4710 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4713 int64_t AndImm, LSBImm;
4715 const unsigned Size = Ty.getScalarSizeInBits();
4723 uint64_t MaybeMask =
static_cast<uint64_t
>(AndImm);
4728 if (MaybeMask & (MaybeMask + 1))
4732 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4740 if (
static_cast<uint64_t
>(LSBImm) + Width >
Size)
4744 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4745 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4746 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4754 const unsigned Opcode =
MI.getOpcode();
4755 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4757 const Register Dst =
MI.getOperand(0).getReg();
4759 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4760 ? TargetOpcode::G_SBFX
4761 : TargetOpcode::G_UBFX;
4764 LLT Ty =
MRI.getType(Dst);
4766 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4772 const unsigned Size = Ty.getScalarSizeInBits();
4782 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4786 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4790 const int64_t Pos = ShrAmt - ShlAmt;
4791 const int64_t Width =
Size - ShrAmt;
4794 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4795 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4796 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4804 const unsigned Opcode =
MI.getOpcode();
4805 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4807 const Register Dst =
MI.getOperand(0).getReg();
4808 LLT Ty =
MRI.getType(Dst);
4810 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4823 const unsigned Size = Ty.getScalarSizeInBits();
4824 if (ShrAmt < 0 || ShrAmt >=
Size)
4828 if (0 == (SMask >> ShrAmt)) {
4830 B.buildConstant(Dst, 0);
4843 const int64_t Pos = ShrAmt;
4848 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4852 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4853 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4854 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4859bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4863 Register Src1Reg = PtrAdd.getBaseReg();
4868 Register Src2Reg = PtrAdd.getOffsetReg();
4870 if (
MRI.hasOneNonDBGUse(Src1Reg))
4880 const APInt &C1APIntVal = *C1;
4881 const APInt &C2APIntVal = *C2;
4882 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4884 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4887 MachineInstr *ConvUseMI = &
UseMI;
4888 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4889 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4890 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4892 if (!
MRI.hasOneNonDBGUse(DefReg))
4894 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4903 TargetLoweringBase::AddrMode AM;
4906 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4908 PtrAdd.getMF()->getFunction().getContext());
4909 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4910 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4916 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4928 Register Src1Reg =
MI.getOperand(1).getReg();
4929 if (RHS->getOpcode() != TargetOpcode::G_ADD)
4941 unsigned PtrAddFlags =
MI.getFlags();
4942 unsigned AddFlags = RHS->getFlags();
4955 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
4958 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
4960 MI.getOperand(1).setReg(NewBase.getReg(0));
4961 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
4965 return !reassociationCanBreakAddressingModePattern(
MI);
4975 std::optional<ValueAndVReg> LHSCstOff;
4985 unsigned PtrAddFlags =
MI.getFlags();
4986 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
4988 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
4990 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5004 LHSPtrAdd->moveBefore(&
MI);
5007 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5009 MI.getOperand(2).setReg(NewCst.getReg(0));
5012 Observer.changingInstr(*LHSPtrAdd);
5013 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5014 LHSPtrAdd->setFlags(Flags);
5017 return !reassociationCanBreakAddressingModePattern(
MI);
5028 Register Src2Reg =
MI.getOperand(2).getReg();
5029 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5030 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5043 unsigned PtrAddFlags =
MI.getFlags();
5044 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5057 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5059 MI.getOperand(1).setReg(LHSSrc1);
5060 MI.getOperand(2).setReg(NewCst.getReg(0));
5064 return !reassociationCanBreakAddressingModePattern(
MI);
5104 LLT OpRHSTy =
MRI.getType(OpRHS);
5121 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5122 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5130 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5131 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5144 unsigned Opc =
MI.getOpcode();
5157 APInt &MatchInfo)
const {
5158 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5162 MatchInfo = *MaybeCst;
5173 MI.getOperand(1).getReg(),
MRI);
5178 if (Csts.size() == 1)
5179 B.buildConstant(Dst, Csts[0]);
5181 B.buildBuildVectorConstant(Dst, Csts);
5187 APInt &MatchInfo)
const {
5193 MatchInfo = *MaybeCst;
5205 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5211 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5212 MI.getOpcode() == TargetOpcode::G_FMAD);
5213 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5230 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5253 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5257 LLT WideTy =
MRI.getType(Dst);
5261 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5277 case TargetOpcode::G_ADD:
5278 case TargetOpcode::G_SUB:
5279 case TargetOpcode::G_MUL:
5280 case TargetOpcode::G_AND:
5281 case TargetOpcode::G_OR:
5282 case TargetOpcode::G_XOR:
5290 auto Mask = Cst->Value;
5295 unsigned NarrowWidth = Mask.countr_one();
5301 auto &MF = *
MI.getMF();
5304 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5305 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5313 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5314 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5316 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5317 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5319 MI.getOperand(1).setReg(Ext.getReg(0));
5328 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5329 MI.getOpcode() == TargetOpcode::G_SMULO);
5338 B.buildConstant(Dst, 0);
5339 B.buildConstant(Carry, 0);
5347 if (SrcA.
isValid() && SrcA == SrcB)
5355 unsigned Opcode =
MI.getOpcode();
5356 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5358 Register Dst = UDivorRem.getReg(0);
5359 Register LHS = UDivorRem.getReg(1);
5360 Register RHS = UDivorRem.getReg(2);
5361 LLT Ty =
MRI.getType(Dst);
5369 bool UseSRL =
false;
5374 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5376 if (IsSplat && !Factors.
empty()) {
5383 APInt Divisor = CI->getValue();
5392 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5393 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5403 if (Ty.isVector()) {
5404 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5405 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5408 Factor = Factors[0];
5416 return MIB.buildMul(Ty, Res, Factor);
5419 unsigned KnownLeadingZeros =
5420 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5422 bool UseNPQ =
false;
5424 auto BuildUDIVPattern = [&](
const Constant *
C) {
5426 const APInt &Divisor = CI->getValue();
5428 bool SelNPQ =
false;
5430 unsigned PreShift = 0, PostShift = 0;
5435 if (!Divisor.
isOne()) {
5441 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5443 Magic = std::move(magics.
Magic);
5446 "We shouldn't generate an undefined shift!");
5448 "We shouldn't generate an undefined shift!");
5452 SelNPQ = magics.
IsAdd;
5456 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5457 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5459 MIB.buildConstant(ScalarTy,
5464 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5472 assert(Matched &&
"Expected unary predicate match to succeed");
5474 Register PreShift, PostShift, MagicFactor, NPQFactor;
5477 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5478 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5479 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5480 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5483 "Non-build_vector operation should have been a scalar");
5484 PreShift = PreShifts[0];
5485 MagicFactor = MagicFactors[0];
5486 PostShift = PostShifts[0];
5490 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5493 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5496 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5501 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5503 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5505 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5508 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5509 auto One = MIB.buildConstant(Ty, 1);
5510 auto IsOne = MIB.buildICmp(
5514 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5516 if (Opcode == TargetOpcode::G_UREM) {
5517 auto Prod = MIB.buildMul(Ty, ret, RHS);
5518 return MIB.buildSub(Ty, LHS, Prod);
5524 unsigned Opcode =
MI.getOpcode();
5525 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5528 LLT DstTy =
MRI.getType(Dst);
5530 auto &MF = *
MI.getMF();
5540 if (MF.getFunction().hasMinSize())
5543 if (Opcode == TargetOpcode::G_UDIV &&
5546 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5561 {TargetOpcode::G_ICMP,
5565 if (Opcode == TargetOpcode::G_UREM &&
5571 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5580 unsigned Opcode =
MI.getOpcode();
5581 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5584 LLT DstTy =
MRI.getType(Dst);
5588 auto &MF = *
MI.getMF();
5598 if (MF.getFunction().hasMinSize())
5602 if (Opcode == TargetOpcode::G_SDIV &&
5605 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5617 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5620 if (Opcode == TargetOpcode::G_SREM &&
5626 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5635 unsigned Opcode =
MI.getOpcode();
5636 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5637 Opcode == TargetOpcode::G_SREM);
5639 Register Dst = SDivorRem.getReg(0);
5640 Register LHS = SDivorRem.getReg(1);
5641 Register RHS = SDivorRem.getReg(2);
5642 LLT Ty =
MRI.getType(Dst);
5649 bool UseSRA =
false;
5655 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5657 if (IsSplat && !ExactFactors.
empty()) {
5659 ExactFactors.
push_back(ExactFactors[0]);
5664 APInt Divisor = CI->getValue();
5674 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5675 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5683 assert(Matched &&
"Expected unary predicate match to succeed");
5686 if (Ty.isVector()) {
5687 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5688 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5690 Shift = ExactShifts[0];
5691 Factor = ExactFactors[0];
5699 return MIB.buildMul(Ty, Res, Factor);
5704 auto BuildSDIVPattern = [&](
const Constant *
C) {
5706 const APInt &Divisor = CI->getValue();
5710 int NumeratorFactor = 0;
5721 NumeratorFactor = 1;
5724 NumeratorFactor = -1;
5727 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5728 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5730 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5731 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5739 assert(Matched &&
"Expected unary predicate match to succeed");
5741 Register MagicFactor, Factor, Shift, ShiftMask;
5744 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5745 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5746 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5747 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5750 "Non-build_vector operation should have been a scalar");
5751 MagicFactor = MagicFactors[0];
5752 Factor = Factors[0];
5754 ShiftMask = ShiftMasks[0];
5758 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5761 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5762 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5765 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5768 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5769 auto T = MIB.buildLShr(Ty, Q, SignShift);
5770 T = MIB.buildAnd(Ty,
T, ShiftMask);
5771 auto ret = MIB.buildAdd(Ty, Q,
T);
5773 if (Opcode == TargetOpcode::G_SREM) {
5774 auto Prod = MIB.buildMul(Ty, ret, RHS);
5775 return MIB.buildSub(Ty, LHS, Prod);
5781 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5782 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5783 "Expected SDIV or UDIV");
5786 auto MatchPow2 = [&](
const Constant *
C) {
5788 return CI && (CI->getValue().isPowerOf2() ||
5789 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5795 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5800 LLT Ty =
MRI.getType(Dst);
5820 unsigned BitWidth = Ty.getScalarSizeInBits();
5821 auto Zero =
Builder.buildConstant(Ty, 0);
5824 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5825 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5827 auto Sign =
Builder.buildAShr(
5831 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5837 auto One =
Builder.buildConstant(Ty, 1);
5838 auto MinusOne =
Builder.buildConstant(Ty, -1);
5842 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5843 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5847 auto Neg =
Builder.buildNeg(Ty, AShr);
5849 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5850 MI.eraseFromParent();
5854 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5859 LLT Ty =
MRI.getType(Dst);
5862 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5863 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
5864 MI.eraseFromParent();
5868 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
5873 LLT Ty =
MRI.getType(Dst);
5892 unsigned BitWidth = Ty.getScalarSizeInBits();
5893 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
5894 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
5896 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
5897 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
5898 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
5901 MI.eraseFromParent();
5905 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5908 LLT Ty =
MRI.getType(Dst);
5909 LLT RHSTy =
MRI.getType(RHS);
5911 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5913 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5928 LLT Ty =
MRI.getType(Dst);
5934 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
5935 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
5936 Builder.buildLShr(Dst, LHS, Trunc);
5937 MI.eraseFromParent();
5944 LLT DstTy =
MRI.getType(Dst);
5945 LLT SrcTy =
MRI.getType(Src);
5947 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
5948 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
5951 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
5980 Builder.buildTruncSSatS(Dst, MatchInfo);
5981 MI.eraseFromParent();
5988 LLT DstTy =
MRI.getType(Dst);
5989 LLT SrcTy =
MRI.getType(Src);
5991 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
5992 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
5995 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6013 Builder.buildTruncSSatU(Dst, MatchInfo);
6014 MI.eraseFromParent();
6021 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6022 LLT SrcTy =
MRI.getType(Val);
6024 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6025 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6028 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6037 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6045 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6048 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6050 const auto LHSCst = Ty.isVector()
6064 if (LHSCst->Value.isNegZero())
6068 if (LHSCst->Value.isPosZero())
6077 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6091 bool &AllowFusionGlobally,
6093 bool CanReassociate)
const {
6095 auto *MF =
MI.getMF();
6096 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6097 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6105 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6108 if (!HasFMAD && !HasFMA)
6113 AllowFusionGlobally = HasFMAD;
6118 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6125 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6127 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6139 unsigned PreferredFusedOpcode =
6140 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6153 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6155 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6156 {LHS.MI->getOperand(1).getReg(),
6157 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6166 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6168 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6169 {RHS.MI->getOperand(1).getReg(),
6170 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6182 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6184 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6188 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6197 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6199 unsigned PreferredFusedOpcode =
6200 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6203 bool LHSContractable =
6206 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6209 bool RHSContractable =
6212 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6216 if (LHSContractable || RHSContractable) {
6219 if (!LHSContractable ||
6220 (RHSContractable &&
hasMoreUses(*LHSFpExtSrc, *RHSFpExtSrc,
MRI))) {
6222 LHSFpExtSrc = RHSFpExtSrc;
6225 unsigned Flags =
MI.getFlags() & LHSFpExtSrc->
getFlags();
6229 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6230 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6241 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6243 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6255 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6257 unsigned PreferredFusedOpcode =
6258 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6263 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6266 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6267 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6272 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6275 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6276 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6285 Register X = FMA->getOperand(1).getReg();
6286 Register Y = FMA->getOperand(2).getReg();
6289 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6290 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6293 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6294 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6295 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6296 {
X,
Y, InnerFMA}, OuterFlags);
6307 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6309 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6316 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6317 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6327 unsigned PreferredFusedOpcode =
6328 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6342 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6343 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6344 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6345 {FpExtU, FpExtV, Z}, InnerFlags)
6347 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6348 {
X,
Y, InnerFMA}, OuterFlags);
6354 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6358 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6360 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6361 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6365 LHS.MI->getOperand(1).getReg(),
6366 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6377 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6382 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6384 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6385 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6389 X =
B.buildFPExt(DstType,
X).getReg(0);
6390 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6393 InnerFlags, OuterFlags,
B);
6402 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6406 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6408 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6409 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6413 RHS.MI->getOperand(1).getReg(),
6414 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6425 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6430 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6432 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6433 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6437 X =
B.buildFPExt(DstType,
X).getReg(0);
6438 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6441 InnerFlags, OuterFlags,
B);
6453 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6455 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6467 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6471 int FirstMulHasFewerUses =
true;
6475 FirstMulHasFewerUses =
false;
6477 unsigned PreferredFusedOpcode =
6478 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6481 if (FirstMulHasFewerUses &&
6484 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6486 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6487 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6488 {LHS.MI->getOperand(1).getReg(),
6489 LHS.MI->getOperand(2).getReg(), NegZ},
6497 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6500 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6501 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6502 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6513 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6515 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6521 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6523 unsigned PreferredFusedOpcode =
6524 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6532 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6536 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6537 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6548 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6550 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6564 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6566 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6572 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6574 unsigned PreferredFusedOpcode =
6575 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6582 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6588 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6589 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6590 {FpExtX, FpExtY, NegZ}, Flags);
6599 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6603 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6606 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6607 {NegY, FpExtZ, LHSReg}, Flags);
6618 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6620 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6624 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6625 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6629 unsigned PreferredFusedOpcode =
6630 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6634 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6635 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6636 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
6647 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6649 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6651 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6654 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6664 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6666 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6682 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6692 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
6709 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6710 if (&U == &
MI || U.getParent() !=
MI.getParent())
6712 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6713 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
6714 !IsOne(U.getOperand(1).getReg())) {
6727 return MatchInfo.
size() >= MinUses;
6735 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6736 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6737 MatchInfo[0]->getOperand(2).getReg(),
6738 MatchInfo[0]->getFlags());
6743 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6744 Div->getOperand(0).getReg(),
MI->getFlags());
6745 MI->eraseFromParent();
6767 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6776 return MRI.getType(MatchInfo) == DstVecTy;
6779 std::optional<ValueAndVReg> ShiftAmount;
6788 return MRI.getType(MatchInfo) == DstVecTy;
6803 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6810 std::optional<ValueAndVReg> ShiftAmt;
6816 LLT MatchTy =
MRI.getType(MatchInfo);
6817 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6818 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6821unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6823 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6824 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6825 "Expected a NaN behaviour?");
6835 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6836 return TargetOpcode::G_FMAXNUM;
6837 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6838 return TargetOpcode::G_FMAXIMUM;
6839 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6840 return TargetOpcode::G_FMAXNUM;
6841 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6842 return TargetOpcode::G_FMAXIMUM;
6848 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6849 return TargetOpcode::G_FMINNUM;
6850 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6851 return TargetOpcode::G_FMINIMUM;
6852 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6853 return TargetOpcode::G_FMINNUM;
6854 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6856 return TargetOpcode::G_FMINIMUM;
6860CombinerHelper::SelectPatternNaNBehaviour
6862 bool IsOrderedComparison)
const {
6863 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
6864 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
6866 if (!LHSSafe && !RHSSafe)
6867 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6868 if (LHSSafe && RHSSafe)
6869 return SelectPatternNaNBehaviour::RETURNS_ANY;
6872 if (IsOrderedComparison)
6873 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6874 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6877 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6878 : SelectPatternNaNBehaviour::RETURNS_NAN;
6887 LLT DstTy =
MRI.getType(Dst);
6900 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6902 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6904 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6907 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6908 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6909 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6910 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6912 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6915 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6920 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
6925 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6927 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6931 MatchInfo = [=](MachineIRBuilder &
B) {
6932 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
6940 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6947 Register TrueVal =
MI.getOperand(2).getReg();
6948 Register FalseVal =
MI.getOperand(3).getReg();
6949 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6954 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6967 if (MatchedSub &&
X != OpLHS)
6975 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
6978 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
6979 B.buildICmp(Pred, Dst,
Y, Zero);
6986static std::optional<unsigned>
6988 std::optional<int64_t> &Result) {
6989 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
6990 Opcode == TargetOpcode::G_ASHR) &&
6991 "Expect G_SHL, G_LSHR or G_ASHR.");
6992 auto SignificantBits = 0;
6994 case TargetOpcode::G_SHL:
6998 case TargetOpcode::G_LSHR:
7002 case TargetOpcode::G_ASHR:
7011 Result = std::nullopt;
7022 Register ShiftVal =
MI.getOperand(1).getReg();
7023 Register ShiftReg =
MI.getOperand(2).getReg();
7024 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7025 auto IsShiftTooBig = [&](
const Constant *
C) {
7030 MatchInfo = std::nullopt;
7034 MI.getOpcode(), MatchInfo);
7035 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7041 unsigned LHSOpndIdx = 1;
7042 unsigned RHSOpndIdx = 2;
7043 switch (
MI.getOpcode()) {
7044 case TargetOpcode::G_UADDO:
7045 case TargetOpcode::G_SADDO:
7046 case TargetOpcode::G_UMULO:
7047 case TargetOpcode::G_SMULO:
7054 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7055 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7065 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7069 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7076 std::optional<FPValueAndVReg> ValAndVReg;
7082bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7084 if (SrcTy.isFixedVector())
7086 if (SrcTy.isScalar()) {
7090 return IConstant && IConstant->Value == 1;
7095bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7096 LLT SrcTy =
MRI.getType(Src);
7098 return isConstantSplatVector(Src, 0, AllowUndefs);
7103 return IConstant && IConstant->Value == 0;
7110bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7111 bool AllowUndefs)
const {
7117 for (
unsigned I = 0;
I < NumSources; ++
I) {
7118 GImplicitDef *ImplicitDef =
7120 if (ImplicitDef && AllowUndefs)
7122 if (ImplicitDef && !AllowUndefs)
7124 std::optional<ValueAndVReg> IConstant =
7126 if (IConstant && IConstant->Value == SplatValue)
7136CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7139 return IConstant->Value;
7143 return std::nullopt;
7146 std::optional<APInt>
Value = std::nullopt;
7147 for (
unsigned I = 0;
I < NumSources; ++
I) {
7148 std::optional<ValueAndVReg> IConstant =
7151 return std::nullopt;
7153 Value = IConstant->Value;
7154 else if (*
Value != IConstant->Value)
7155 return std::nullopt;
7161bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7171 for (
unsigned I = 0;
I < NumSources; ++
I) {
7172 std::optional<ValueAndVReg> IConstant =
7181bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7188 LLT CondTy =
MRI.getType(
Select->getCondReg());
7189 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7199 std::optional<ValueAndVReg> TrueOpt =
7201 std::optional<ValueAndVReg> FalseOpt =
7204 if (!TrueOpt || !FalseOpt)
7207 APInt TrueValue = TrueOpt->Value;
7208 APInt FalseValue = FalseOpt->Value;
7212 MatchInfo = [=](MachineIRBuilder &
B) {
7213 B.setInstrAndDebugLoc(*
Select);
7214 B.buildZExtOrTrunc(Dest,
Cond);
7221 MatchInfo = [=](MachineIRBuilder &
B) {
7222 B.setInstrAndDebugLoc(*
Select);
7223 B.buildSExtOrTrunc(Dest,
Cond);
7230 MatchInfo = [=](MachineIRBuilder &
B) {
7231 B.setInstrAndDebugLoc(*
Select);
7232 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7233 B.buildNot(Inner,
Cond);
7234 B.buildZExtOrTrunc(Dest, Inner);
7241 MatchInfo = [=](MachineIRBuilder &
B) {
7242 B.setInstrAndDebugLoc(*
Select);
7243 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7244 B.buildNot(Inner,
Cond);
7245 B.buildSExtOrTrunc(Dest, Inner);
7251 if (TrueValue - 1 == FalseValue) {
7252 MatchInfo = [=](MachineIRBuilder &
B) {
7253 B.setInstrAndDebugLoc(*
Select);
7254 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7255 B.buildZExtOrTrunc(Inner,
Cond);
7256 B.buildAdd(Dest, Inner,
False);
7262 if (TrueValue + 1 == FalseValue) {
7263 MatchInfo = [=](MachineIRBuilder &
B) {
7264 B.setInstrAndDebugLoc(*
Select);
7265 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7266 B.buildSExtOrTrunc(Inner,
Cond);
7267 B.buildAdd(Dest, Inner,
False);
7274 MatchInfo = [=](MachineIRBuilder &
B) {
7275 B.setInstrAndDebugLoc(*
Select);
7276 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7277 B.buildZExtOrTrunc(Inner,
Cond);
7280 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7281 B.buildShl(Dest, Inner, ShAmtC, Flags);
7288 MatchInfo = [=](MachineIRBuilder &
B) {
7289 B.setInstrAndDebugLoc(*
Select);
7291 B.buildNot(Not,
Cond);
7292 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7293 B.buildZExtOrTrunc(Inner, Not);
7296 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7297 B.buildShl(Dest, Inner, ShAmtC, Flags);
7304 MatchInfo = [=](MachineIRBuilder &
B) {
7305 B.setInstrAndDebugLoc(*
Select);
7306 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7307 B.buildSExtOrTrunc(Inner,
Cond);
7308 B.buildOr(Dest, Inner,
False, Flags);
7315 MatchInfo = [=](MachineIRBuilder &
B) {
7316 B.setInstrAndDebugLoc(*
Select);
7318 B.buildNot(Not,
Cond);
7319 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7320 B.buildSExtOrTrunc(Inner, Not);
7321 B.buildOr(Dest, Inner,
True, Flags);
7330bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7337 LLT CondTy =
MRI.getType(
Select->getCondReg());
7338 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7347 if (CondTy != TrueTy)
7353 MatchInfo = [=](MachineIRBuilder &
B) {
7354 B.setInstrAndDebugLoc(*
Select);
7355 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7356 B.buildZExtOrTrunc(Ext,
Cond);
7357 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7358 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7366 MatchInfo = [=](MachineIRBuilder &
B) {
7367 B.setInstrAndDebugLoc(*
Select);
7368 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7369 B.buildZExtOrTrunc(Ext,
Cond);
7370 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7371 B.buildAnd(DstReg, Ext, FreezeTrue);
7377 if (isOneOrOneSplat(
False,
true)) {
7378 MatchInfo = [=](MachineIRBuilder &
B) {
7379 B.setInstrAndDebugLoc(*
Select);
7381 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7382 B.buildNot(Inner,
Cond);
7384 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7385 B.buildZExtOrTrunc(Ext, Inner);
7386 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7387 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7393 if (isZeroOrZeroSplat(
True,
true)) {
7394 MatchInfo = [=](MachineIRBuilder &
B) {
7395 B.setInstrAndDebugLoc(*
Select);
7397 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7398 B.buildNot(Inner,
Cond);
7400 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7401 B.buildZExtOrTrunc(Ext, Inner);
7402 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7403 B.buildAnd(DstReg, Ext, FreezeFalse);
7425 LLT DstTy =
MRI.getType(DstReg);
7430 if (!
MRI.hasOneNonDBGUse(CondReg))
7439 if (
True == CmpRHS &&
False == CmpLHS) {
7487 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7488 Register DestReg =
MI.getOperand(0).getReg();
7489 LLT DestTy =
MRI.getType(DestReg);
7503 if (
isLegal({NewOpc, {DestTy}})) {
7505 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7517 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7520 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7530bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7532 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7533 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7537 unsigned Flags = Logic->
getFlags();
7556 std::optional<ValueAndVReg> MaybeC1 =
7560 C1 = MaybeC1->Value;
7562 std::optional<ValueAndVReg> MaybeC2 =
7566 C2 = MaybeC2->Value;
7587 std::optional<APInt> Offset1;
7588 std::optional<APInt> Offset2;
7591 std::optional<ValueAndVReg> MaybeOffset1 =
7594 R1 =
Add->getLHSReg();
7595 Offset1 = MaybeOffset1->Value;
7599 std::optional<ValueAndVReg> MaybeOffset2 =
7602 R2 =
Add->getLHSReg();
7603 Offset2 = MaybeOffset2->Value;
7622 bool CreateMask =
false;
7635 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7648 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7657 MatchInfo = [=](MachineIRBuilder &
B) {
7658 if (CreateMask &&
Offset != 0) {
7659 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7660 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7661 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7662 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7663 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7664 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7665 B.buildZExtOrTrunc(DstReg, ICmp);
7666 }
else if (CreateMask &&
Offset == 0) {
7667 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7668 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7669 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7670 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7671 B.buildZExtOrTrunc(DstReg, ICmp);
7672 }
else if (!CreateMask &&
Offset != 0) {
7673 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7674 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7675 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7676 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7677 B.buildZExtOrTrunc(DstReg, ICmp);
7678 }
else if (!CreateMask &&
Offset == 0) {
7679 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7680 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7681 B.buildZExtOrTrunc(DstReg, ICmp);
7689bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7695 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7707 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7713 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7714 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7715 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7716 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7727 if (LHS0 == RHS1 && LHS1 == RHS0) {
7733 if (LHS0 == RHS0 && LHS1 == RHS1) {
7737 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7739 MatchInfo = [=](MachineIRBuilder &
B) {
7744 auto False =
B.buildConstant(CmpTy, 0);
7745 B.buildZExtOrTrunc(DestReg,
False);
7752 B.buildZExtOrTrunc(DestReg,
True);
7754 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7755 B.buildZExtOrTrunc(DestReg, Cmp);
7767 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7770 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7779 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7782 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7797 bool IsSigned =
Add->isSigned();
7798 LLT DstTy =
MRI.getType(Dst);
7799 LLT CarryTy =
MRI.getType(Carry);
7802 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7805 B.buildSAddo(Dst, Carry, RHS, LHS);
7811 B.buildUAddo(Dst, Carry, RHS, LHS);
7816 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7817 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7823 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7824 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7826 B.buildConstant(Dst, Result);
7827 B.buildConstant(Carry, Overflow);
7835 B.buildCopy(Dst, LHS);
7836 B.buildConstant(Carry, 0);
7845 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
7848 std::optional<APInt> MaybeAddRHS =
7849 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7852 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7853 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7857 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7858 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7864 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7865 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7890 B.buildConstant(Carry, 0);
7897 B.buildAdd(Dst, LHS, RHS);
7898 B.buildConstant(Carry, 1);
7910 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
7913 B.buildConstant(Carry, 0);
7929 B.buildConstant(Carry, 0);
7936 B.buildAdd(Dst, LHS, RHS);
7937 B.buildConstant(Carry, 1);
7955 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
7961 auto [Dst,
Base] =
MI.getFirst2Regs();
7962 LLT Ty =
MRI.getType(Dst);
7966 Builder.buildFConstant(Dst, 1.0);
7967 MI.removeFromParent();
7979 std::optional<SrcOp> Res;
7981 while (ExpVal > 0) {
7986 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
7989 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
7996 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8000 MI.eraseFromParent();
8011 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8018 LLT DstTy =
MRI.getType(Dst);
8021 auto Const =
B.buildConstant(DstTy, C1 - C2);
8022 B.buildAdd(Dst,
A, Const);
8036 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8043 LLT DstTy =
MRI.getType(Dst);
8046 auto Const =
B.buildConstant(DstTy, C2 - C1);
8047 B.buildSub(Dst, Const,
A);
8068 LLT DstTy =
MRI.getType(Dst);
8071 auto Const =
B.buildConstant(DstTy, C1 + C2);
8072 B.buildSub(Dst,
A, Const);
8093 LLT DstTy =
MRI.getType(Dst);
8096 auto Const =
B.buildConstant(DstTy, C1 - C2);
8097 B.buildSub(Dst, Const,
A);
8111 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8118 LLT DstTy =
MRI.getType(Dst);
8121 auto Const =
B.buildConstant(DstTy, C2 - C1);
8122 B.buildAdd(Dst,
A, Const);
8166 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8174 LLT SmallBvTy = DstTy;
8178 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8183 {TargetOpcode::G_ANYEXT,
8195 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8196 Ops.push_back(AnyExt.getReg(0));
8214 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8215 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8216 const unsigned NumDstElts = OrigMask.
size();
8217 for (
unsigned i = 0; i != NumDstElts; ++i) {
8218 int Idx = OrigMask[i];
8219 if (Idx >= (
int)NumSrcElems) {
8230 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8231 std::move(NewMask));
8238 const unsigned MaskSize = Mask.size();
8239 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8244 if (Idx < (
int)NumElems)
8245 Mask[
I] = Idx + NumElems;
8247 Mask[
I] = Idx - NumElems;
8257 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8260 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8263 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8264 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8266 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8270 const unsigned NumSrcElems = Src1Ty.getNumElements();
8272 bool TouchesSrc1 =
false;
8273 bool TouchesSrc2 =
false;
8274 const unsigned NumElems = Mask.size();
8275 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8279 if (Mask[Idx] < (
int)NumSrcElems)
8285 if (TouchesSrc1 == TouchesSrc2)
8288 Register NewSrc1 = Shuffle.getSrc1Reg();
8291 NewSrc1 = Shuffle.getSrc2Reg();
8296 auto Undef =
B.buildUndef(Src1Ty);
8297 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8311 LLT DstTy =
MRI.getType(Dst);
8312 LLT CarryTy =
MRI.getType(Carry);
8334 B.buildConstant(Carry, 0);
8341 B.buildSub(Dst, LHS, RHS);
8359 B.buildConstant(Carry, 0);
8366 B.buildSub(Dst, LHS, RHS);
8383 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8384 "Expected G_CTLZ variant");
8389 LLT Ty =
MRI.getType(Dst);
8390 LLT SrcTy =
MRI.getType(Src);
8392 if (!(Ty.isValid() && Ty.isScalar()))
8401 switch (
LI->getAction(Query).Action) {
8412 bool NeedAdd =
true;
8420 unsigned BitWidth = Ty.getScalarSizeInBits();
8431 B.buildCTLS(Dst,
X);
8435 auto Ctls =
B.buildCTLS(Ty,
X);
8436 auto One =
B.buildConstant(Ty, 1);
8438 B.buildAdd(Dst, Ctls, One);
8446 return C &&
C->getValueAPF().isNaN();
8450 unsigned ZeroPoisonOpc)
const {
8451 const bool IsCtlzPair =
Opc == TargetOpcode::G_CTLZ &&
8452 ZeroPoisonOpc == TargetOpcode::G_CTLZ_ZERO_POISON;
8453 const bool IsCttzPair =
Opc == TargetOpcode::G_CTTZ &&
8454 ZeroPoisonOpc == TargetOpcode::G_CTTZ_ZERO_POISON;
8455 if (
MI.getOpcode() !=
Opc || (!IsCtlzPair && !IsCttzPair))
8461 if (!
VT->isKnownNeverZero(Src))
8464 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8465 LLT SrcTy =
MRI.getType(Src);
8471 assert((Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) &&
8472 "Expected G_AND or G_OR");
8474 ~(Opcode == TargetOpcode::G_AND ? OtherKnown.
Zero : OtherKnown.
One);
8477Register CombinerHelper::simplifyMultipleUseDemandedBits(
8479 assert(
R.isVirtual() &&
"Expected a virtual register");
8480 assert(!DemandedBits.
isZero() &&
"Zero demand is handled by the caller");
8484 [[maybe_unused]] LLT Ty =
MRI.getType(R);
8487 "DemandedBits width must match the register scalar type");
8489 MachineInstr *
DefMI =
MRI.getVRegDef(R);
8490 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8499 "Logical operands must match the result type");
8502 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8505 bool BypassToX = Opcode == TargetOpcode::G_AND
8510 simplifyMultipleUseDemandedBits(
X, DemandedBits,
Depth + 1))
8514 bool BypassToC = Opcode == TargetOpcode::G_AND
8524 return LookThrough(
RHS,
LHS);
8527bool CombinerHelper::simplifyDemandedBitsImpl(
MachineInstr &
MI,
unsigned OpNo,
8530 bool DoRewrite)
const {
8532 assert(
MI.getOperand(OpNo).isReg() && !
MI.getOperand(OpNo).isDef() &&
8533 "Expected a register use");
8534 Register OpReg =
MI.getOperand(OpNo).getReg();
8536 LLT OpTy =
MRI.getType(OpReg);
8539 "DemandedBits width must match the operand scalar type");
8541 MachineInstr *
DefMI =
MRI.getVRegDef(OpReg);
8542 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8544 auto DropPoisonFlags = [&]() {
8553 auto InvalidateDebugUses = [&](
const APInt &Demanded) {
8554 if (DoRewrite && !Demanded.isAllOnes())
8555 MRI.markUsesInDebugValueAsUndef(OpReg);
8557 auto Rewrite = [&](
Register Repl) {
8558 if (!DoRewrite || Repl == OpReg)
8559 return Repl != OpReg;
8562 InvalidateDebugUses(DemandedBits);
8571 if (DemandedBits.
isZero()) {
8576 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8581 Builder.setInsertPt(SaveMBB, SavePt);
8593 auto GiveUp = [&]() {
8606 APInt Demanded = DemandedBits;
8607 if (!
MRI.hasOneNonDBGUse(OpReg) && !Demanded.
isAllOnes()) {
8609 simplifyMultipleUseDemandedBits(OpReg, Demanded,
Depth)) {
8610 Known =
VT->getKnownBits(Repl);
8619 case TargetOpcode::G_AND:
8620 case TargetOpcode::G_OR: {
8625 "Logical operands must match the result type");
8626 auto SimplifyWithConst = [&](
Register X,
8627 Register CReg) -> std::optional<Register> {
8628 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8630 return std::nullopt;
8631 assert(
C->getBitWidth() == BW &&
"Constant width must match its type");
8633 if (Opcode == TargetOpcode::G_AND) {
8638 return std::nullopt;
8644 return std::nullopt;
8648 if (std::optional<Register> Repl = SimplifyWithConst(
LHS,
RHS)) {
8649 Known =
VT->getKnownBits(*Repl);
8653 if (std::optional<Register> Repl = SimplifyWithConst(
RHS,
LHS)) {
8654 Known =
VT->getKnownBits(*Repl);
8659 KnownBits RHSKnown(BW);
8660 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 2, Demanded,
8661 RHSKnown,
Depth + 1, DoRewrite);
8663 KnownBits LHSKnown(BW);
8664 Changed |= simplifyDemandedBitsImpl(*
DefMI, 1, LHSDemand, LHSKnown,
8665 Depth + 1, DoRewrite);
8667 !getConstantOrConstantSplatVector(
RHS)) {
8670 LHSDemand == Demanded
8676 OpTy.isFixedVector()
8680 if (RHSDemand != Demanded) {
8682 KnownBits RetryKnown(BW);
8683 Changed = simplifyDemandedBitsImpl(*
DefMI, 2, RHSDemand,
8684 RetryKnown,
Depth + 1, DoRewrite);
8689 InvalidateDebugUses(Demanded);
8691 Known = Opcode == TargetOpcode::G_AND ? LHSKnown & RHSKnown
8692 : LHSKnown | RHSKnown;
8703 unsigned Depth)
const {
8711 LLT Ty =
MRI.getType(Dst);
8712 assert(Ty.isValid() &&
"Expected a typed generic result");
8713 if (!
VT || Ty.isVector())
8718 if (!simplifyDemandedBitsImpl(
MI, OpNo, OpDemand,
Known, 0,
8729 unsigned Opcode =
MI.getOpcode();
8733 case TargetOpcode::G_AND:
8734 case TargetOpcode::G_OR: {
8739 bool RootRedundant = Opcode == TargetOpcode::G_AND
8748 if (Probe(2, RootDemand, RHSKnown))
8754 if (Probe(1, LHSDemand, LHSKnown))
8758 if (!
MRI.hasOneNonDBGUse(RHS) || getConstantOrConstantSplatVector(RHS))
8762 LHSDemand == RootDemand
8766 VT->getKnownBits(
MI.getOperand(1).getReg()));
8768 return RHSDemand != RootDemand && Probe(2, RHSDemand, RetryKnown);
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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static APInt getDemandedBitsForLogicalOp(unsigned Opcode, const APInt &Demanded, const KnownBits &OtherKnown)
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...
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
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)
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
Class for arbitrary precision integers.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
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 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.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
static bool isSameValue(const APInt &I1, const APInt &I2, bool SignedCompare=false)
Determine if two APInts have the same value, after zero-extending or sign-extending (if SignedCompare...
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
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.
LLVM_ABI void applyCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
LLVM_ABI void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
LLVM_ABI bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
LLVM_ABI bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
LLVM_ABI const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
LLVM_ABI bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
LLVM_ABI void applyUDivOrURemByConst(MachineInstr &MI) const
LLVM_ABI bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
LLVM_ABI void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
LLVM_ABI bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchFsubToFneg(MachineInstr &MI) const
LLVM_ABI bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
LLVM_ABI bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
LLVM_ABI bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
LLVM_ABI bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
LLVM_ABI bool matchSimplifyDemandedBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match demanded-bits simplification of a root's register use.
const TargetInstrInfo * TII
LLVM_ABI 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.
LLVM_ABI void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
LLVM_ABI bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
LLVM_ABI bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
LLVM_ABI 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...
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
LLVM_ABI bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI 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.
LLVM_ABI void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
LLVM_ABI void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
LLVM_ABI bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
LLVM_ABI void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
LLVM_ABI 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.
LLVM_ABI void applyCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo) const
LLVM_ABI bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
LLVM_ABI void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
LLVM_ABI bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
LLVM_ABI 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...
LLVM_ABI void applyUMulHToLShr(MachineInstr &MI) const
LLVM_ABI void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
LLVM_ABI bool isLegalOrHasFewerElements(const LegalityQuery &Query) const
LLVM_ABI bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
LLVM_ABI bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
LLVM_ABI bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
LLVM_ABI bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
LLVM_ABI bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI const TargetLowering & getTargetLowering() const
LLVM_ABI bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
LLVM_ABI void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
LLVM_ABI void applySDivByPow2(MachineInstr &MI) const
LLVM_ABI void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
LLVM_ABI bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
LLVM_ABI bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
LLVM_ABI void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
LLVM_ABI 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,...
LLVM_ABI bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
LLVM_ABI void applyCombineCopy(MachineInstr &MI) const
LLVM_ABI bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
LLVM_ABI bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
LLVM_ABI 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,...
LLVM_ABI bool matchSextTruncSextLoad(MachineInstr &MI) const
LLVM_ABI bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
LLVM_ABI bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
LLVM_ABI bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
LLVM_ABI bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
LLVM_ABI bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
LLVM_ABI bool matchCombineCopy(MachineInstr &MI) const
LLVM_ABI bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
LLVM_ABI void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
LLVM_ABI bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
LLVM_ABI bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
LLVM_ABI void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
LLVM_ABI bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchRedundantSExtInReg(MachineInstr &MI) const
LLVM_ABI void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
LLVM_ABI void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
LLVM_ABI bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
LLVM_ABI void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
LLVM_ABI bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
LLVM_ABI bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
LLVM_ABI void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
LLVM_ABI bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
LLVM_ABI void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
LLVM_ABI bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
LLVM_ABI void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
LLVM_ABI bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
LLVM_ABI bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
LLVM_ABI bool isPreLegalize() const
LLVM_ABI bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
LLVM_ABI bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI 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...
LLVM_ABI bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
LLVM_ABI bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
LLVM_ABI bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVM_ABI LLVMContext & getContext() const
LLVM_ABI void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
LLVM_ABI bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
LLVM_ABI bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
LLVM_ABI bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
LLVM_ABI bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
LLVM_ABI bool simplifyDemandedBits(MachineInstr &MI, unsigned OpNo, const APInt &DemandedBits, KnownBits &Known, unsigned Depth=0) const
Simplify a register use under DemandedBits and compute Known in the same walk.
LLVM_ABI bool matchConstantFoldUnaryIntOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold a unary integer op (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON variants,...
LLVM_ABI void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
LLVM_ABI bool isLegal(const LegalityQuery &Query) const
LLVM_ABI bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
LLVM_ABI bool matchOperandIsKnownToBeAPowerOfTwo(const MachineOperand &MO, bool OrNegative=false) const
Check if operand MO is known to be a power of 2.
LLVM_ABI bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
LLVM_ABI void eraseInst(MachineInstr &MI) const
Erase MI.
LLVM_ABI bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
LLVM_ABI void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
MachineRegisterInfo & MRI
LLVM_ABI void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
LLVM_ABI 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.
LLVM_ABI MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
LLVM_ABI void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
LLVM_ABI bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
LLVM_ABI bool isConstantNaN(Register Reg) const
LLVM_ABI bool matchPtrAddZeroVector(MachineInstr &MI) const
}
LLVM_ABI bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
LLVM_ABI bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
LLVM_ABI bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
LLVM_ABI void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
LLVM_ABI void applyRotateOutOfRange(MachineInstr &MI) const
LLVM_ABI bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
LLVM_ABI bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
LLVM_ABI bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
LLVM_ABI bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
LLVM_ABI bool isDesirableToCommuteWithShift(const MachineInstr &MI) const
LLVM_ABI 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) !...
LLVM_ABI 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...
LLVM_ABI bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
LLVM_ABI void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
LLVM_ABI bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
LLVM_ABI bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
LLVM_ABI bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
LLVM_ABI bool matchRotateOutOfRange(MachineInstr &MI) const
LLVM_ABI void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
LLVM_ABI void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
LLVM_ABI bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
LLVM_ABI void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
LLVM_ABI bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
LLVM_ABI void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applySimplifySRemByPow2(MachineInstr &MI) const
Combine G_SREM x, (+/-2^k) to a bias-and-mask sequence.
LLVM_ABI bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
LLVM_ABI bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
LLVM_ABI 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.
LLVM_ABI void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
LLVM_ABI void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
LLVM_ABI bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
LLVM_ABI bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
LLVM_ABI bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
LLVM_ABI bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
LLVM_ABI bool matchBinopWithNeg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold a bitwiseop (~b +/- c) -> a bitwiseop ~(b -/+ c)
LLVM_ABI bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
LLVM_ABI bool matchCountZeroToZeroPoison(MachineInstr &MI, unsigned Opc, unsigned ZeroPoisonOpc) const
LLVM_ABI void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
LLVM_ABI bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
LLVM_ABI bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
LLVM_ABI void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
LLVM_ABI 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.
LLVM_ABI bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
LLVM_ABI bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
LLVM_ABI bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
LLVM_ABI bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
LLVM_ABI bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
LLVM_ABI bool matchSameRegOrICstOrSplat(Register A, Register B) const
True when A and B are the same register, including through copies, or different registers holding the...
LLVM_ABI void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
LLVM_ABI bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
LLVM_ABI bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applySDivOrSRemByConst(MachineInstr &MI) const
LLVM_ABI bool matchCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo, unsigned MaxLen=0) const
LLVM_ABI 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...
LLVM_ABI bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
LLVM_ABI bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
LLVM_ABI bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
LLVM_ABI void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
LLVM_ABI void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
LLVM_ABI const MachineFunction & getMachineFunction() const
LLVM_ABI bool matchCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
Combine G_BUILD_VECTOR(G_UNMERGE(G_BITCAST), Undef) to G_BITCAST(G_BUILD_VECTOR(.....
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
LLVM_ABI void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
LLVM_ABI void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
LLVM_ABI bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
LLVM_ABI void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
LLVM_ABI bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
LLVM_ABI void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
LLVM_ABI bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
LLVM_ABI void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
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.
iterator find(const_arg_type_t< KeyT > Val)
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
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.
Register getSrcReg() const
Represents a G_CONCAT_VECTORS.
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.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr ElementCount getElementCount() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
This is an important class for using LLVM in a threaded context.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
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.
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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.
static constexpr uint32_t getPoisonGeneratingFlags()
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
mop_range uses()
Returns all operands which may be register uses.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
bool isAtomic() const
Returns true if this operation has an atomic ordering requirement of unordered or higher,...
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
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.
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
static use_instr_nodbg_iterator use_instr_nodbg_end()
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
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 bool isDesirableToCommuteWithShift(const SDNode *N, CombineLevel Level) const
Return true if it is profitable to move this shift by a constant amount through its operand,...
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.
@ 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.
GInstrBind< GBuildVector > m_GBuildVector(GBuildVector *&Inst)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
LoadOp_match< GLoad, PtrP > m_GLoad(const PtrP &Ptr)
MIFlagsRef m_MIFlags(uint32_t &Flags)
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)
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)
GInstrBind< GConcatVectors > m_GConcatVectors(GConcatVectors *&Inst)
GConstantBitsMatch m_GConstantOrFConstantBits(APInt &Bits)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP > m_GICmp(const Pred &P, const LHS &L, const RHS &R)
GInstrBind< GUnmerge > m_GUnmerge(GUnmerge *&Inst)
Instruction binders for ops with no operand-form matcher (constant-immediate or variadic-source ops).
MMORef m_MMO(const MachineMemOperand *&MMO)
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)
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT > m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
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.
LoadOp_match< GAnyLoad, PtrP > m_GAnyLoad(const PtrP &Ptr)
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)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FMUL, true > m_GFMul(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
unsigned getNumElements(Type *Ty)
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.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
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 std::optional< APFloat > isConstantOrConstantSplatVectorFP(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a float constant integer or a splat vector of float constant integers.
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...
@ Known
Known to have no common set bits.
@ 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)
@ Load
The value being inserted comes from a load (InsertElement only).
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, llvm::function_ref< 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 MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
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 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...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, AssumptionCache *AC=nullptr, const Instruction *CtxI=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 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.
constexpr unsigned MaxAnalysisRecursionDepth
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.
std::tuple< Register, Register, uint64_t, Align, bool, std::vector< LLT > > MemCpyFamilyLoweringInfo
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 bool canLowerMemCpyFamily(const MachineInstr &MI, const MachineRegisterInfo &MRI, unsigned MaxLen, Register &Dst, Register &Src, uint64_t &KnownLen, Align &Alignment, bool &DstAlignCanChange, std::vector< LLT > &MemOps)
Matcher for memcpy-like instructions.
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.
@ Fast
Assign the register banks as fast as possible (default).
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...
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 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 SmallVector< APInt > ConstantFoldUnaryIntOp(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Tries to constant fold a unary integer operation (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON vari...
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.
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.
bool isNegative() const
Returns true if this value is known to be negative.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
This class contains a discriminated union of information about pointers in memory operands,...
LLVM_ABI unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
Magic data for optimising signed division by a constant.
unsigned ShiftAmount
shift amount
static LLVM_ABI SignedDivisionByConstantInfo get(const APInt &D)
Calculate the magic numbers required to implement a signed integer division by a constant as a sequen...
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
unsigned PostShift
post-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true, bool AllowWidenOptimization=false)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...