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)");
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();
497 Register SrcVec1 = Shuffle.getSrc1Reg();
498 Register SrcVec2 = Shuffle.getSrc2Reg();
501 assert((BuildMI1 && (BuildMI2 ||
MRI.getVRegDef(SrcVec2)->getOpcode() ==
502 TargetOpcode::G_IMPLICIT_DEF)) &&
503 "Unexpected input to applyCombineShuffleOfBuildVector");
504 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
505 int NumElts =
MRI.getType(SrcVec1).getNumElements();
508 for (
int Val : Shuffle.getMask()) {
511 else if (Val < NumElts)
512 Extracts.
push_back(BuildMI1->getSourceReg(Val));
514 Extracts.
push_back(BuildMI2->getSourceReg(Val - NumElts));
519 if (Extracts.
size() == 1)
520 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
522 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
523 MI.eraseFromParent();
540 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
542 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
546 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
547 if (i + j >= Mask.size())
549 if (Mask[i + j] != -1)
553 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
556 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
557 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
558 if (i + j >= Mask.size())
560 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
577 {TargetOpcode::G_CONCAT_VECTORS,
578 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
589 SrcTy =
MRI.getType(Reg);
591 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
598 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
604 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
607 MI.eraseFromParent();
612 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
613 "Invalid instruction kind");
614 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
616 LLT SrcType =
MRI.getType(Src1);
618 unsigned DstNumElts = DstType.getNumElements();
619 unsigned SrcNumElts = SrcType.getNumElements();
636 if (DstNumElts < 2 * SrcNumElts)
641 if (DstNumElts % SrcNumElts != 0)
647 unsigned NumConcat = DstNumElts / SrcNumElts;
650 for (
unsigned i = 0; i != DstNumElts; ++i) {
657 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
658 (ConcatSrcs[i / SrcNumElts] >= 0 &&
659 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
662 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
669 for (
auto Src : ConcatSrcs) {
673 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
675 Ops.push_back(UndefReg);
688 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
696 MI.eraseFromParent();
705 const LLT TyForCandidate,
706 unsigned OpcodeForCandidate,
711 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
722 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
725 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
726 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
727 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
735 OpcodeForCandidate == TargetOpcode::G_ZEXT)
737 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
738 OpcodeForCandidate == TargetOpcode::G_SEXT)
739 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
748 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
759static void InsertInsnsWithoutSideEffectsBeforeUse(
771 InsertBB = PredBB->
getMBB();
776 if (InsertBB ==
DefMI.getParent()) {
778 Inserter(InsertBB, std::next(InsertPt), UseMO);
797 unsigned CandidateLoadOpc;
799 case TargetOpcode::G_ANYEXT:
800 CandidateLoadOpc = TargetOpcode::G_LOAD;
802 case TargetOpcode::G_SEXT:
803 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
805 case TargetOpcode::G_ZEXT:
806 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
811 return CandidateLoadOpc;
828 LLT LoadValueTy =
MRI.getType(LoadReg);
850 unsigned PreferredOpcode =
852 ? TargetOpcode::G_ANYEXT
854 Preferred = {
LLT(), PreferredOpcode,
nullptr};
855 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
856 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
857 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
858 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
859 const auto &MMO = LoadMI->
getMMO();
867 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
869 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
873 Preferred = ChoosePreferredUse(
MI, Preferred,
874 MRI.getType(
UseMI.getOperand(0).getReg()),
884 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
902 if (PreviouslyEmitted) {
909 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
910 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
912 EmittedInsns[InsertIntoBB] = NewMI;
918 MI.setDesc(
Builder.getTII().get(LoadOpc));
925 for (
auto *UseMO :
Uses) {
931 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
934 const LLT UseDstTy =
MRI.getType(UseDstReg);
935 if (UseDstReg != ChosenDstReg) {
936 if (Preferred.
Ty == UseDstTy) {
973 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
988 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
991 MI.getOperand(0).setReg(ChosenDstReg);
997 assert(
MI.getOpcode() == TargetOpcode::G_AND);
1008 if (
MRI.getType(Dst).isVector())
1016 APInt MaskVal = MaybeMask->Value;
1031 LLT RegTy =
MRI.getType(LoadReg);
1034 unsigned MaskSizeBits = MaskVal.
countr_one();
1037 !
MRI.hasOneNonDBGUse(LoadReg))
1042 if (MaskSizeBits > LoadSizeBits)
1061 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1066 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1070 B.setInstrAndDebugLoc(*LoadMI);
1071 auto &MF =
B.getMF();
1073 auto *NewMMO = MF.getMachineMemOperand(MMO, PtrInfo, MemDesc.
MemoryTy);
1074 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1084 "shouldn't consider debug uses");
1092 if (DefOrUse ==
MBB.end())
1094 return &*DefOrUse == &
DefMI;
1100 "shouldn't consider debug uses");
1103 else if (
DefMI.getParent() !=
UseMI.getParent())
1110 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1114 if (
MRI.getType(SrcReg).isVector())
1119 LoadUser = TruncSrc;
1121 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1126 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1128 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1130 if (LoadSizeBits == SizeInBits)
1137 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1138 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1141 LLT RegTy =
MRI.getType(DstReg);
1154 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1156 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1162 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1165 if (NewSizeBits < 8)
1178 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1183 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1186 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1191 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1192 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1194 unsigned ScalarSizeBits;
1195 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1204 auto &MMO = LoadDef->
getMMO();
1205 Builder.setInstrAndDebugLoc(*LoadDef);
1207 auto PtrInfo = MMO.getPointerInfo();
1208 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1209 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1212 MI.eraseFromParent();
1223 auto *MF =
MI->getMF();
1230 AM.
BaseOffs = CstOff->getSExtValue();
1235 MF->getDataLayout(), AM,
1237 MF->getFunction().getContext()),
1238 MI->getMMO().getAddrSpace());
1243 case TargetOpcode::G_LOAD:
1244 return TargetOpcode::G_INDEXED_LOAD;
1245 case TargetOpcode::G_STORE:
1246 return TargetOpcode::G_INDEXED_STORE;
1247 case TargetOpcode::G_ZEXTLOAD:
1248 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1249 case TargetOpcode::G_SEXTLOAD:
1250 return TargetOpcode::G_INDEXED_SEXTLOAD;
1256bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1266 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1267 OpTys = {PtrTy, Ty, Ty};
1269 OpTys = {Ty, PtrTy};
1271 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1277 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1278 "considered for post-indexing."));
1282 bool &RematOffset)
const {
1292 if (
MRI.hasOneNonDBGUse(Ptr))
1295 if (!isIndexedLoadStoreLegal(LdSt))
1306 unsigned NumUsesChecked = 0;
1307 for (
auto &
Use :
MRI.use_nodbg_instructions(Ptr)) {
1314 if (!PtrAdd ||
MRI.use_nodbg_empty(PtrAdd->getReg(0)))
1319 if (StoredValDef == &
Use)
1322 Offset = PtrAdd->getOffsetReg();
1324 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1332 RematOffset =
false;
1336 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1341 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1342 if (&BasePtrUse == PtrDef)
1348 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1350 isIndexedLoadStoreLegal(*BasePtrLdSt))
1356 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1357 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1360 if (BaseUseUse.getParent() != LdSt.
getParent())
1372 Addr = PtrAdd->getReg(0);
1373 Base = PtrAdd->getBaseReg();
1388 MRI.hasOneNonDBGUse(Addr))
1395 if (!isIndexedLoadStoreLegal(LdSt))
1399 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1404 if (
Base == St->getValueReg())
1409 if (St->getValueReg() == Addr)
1414 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1415 if (AddrUse.getParent() != LdSt.
getParent())
1420 bool RealUse =
false;
1421 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1439 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1449 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1456 if (!LoadMI->isSimple())
1468 const unsigned MaxIter = 20;
1470 for (
const auto &Instr :
1472 if (Instr.isLoadFoldBarrier())
1474 if (Iter++ == MaxIter)
1490 int Elt = CVal->getZExtValue();
1503 Register VecPtr = LoadMI->getPointerReg();
1504 LLT PtrTy =
MRI.getType(VecPtr);
1512 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1535 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1550 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1552 if (!MatchInfo.
IsPre &&
1553 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1563 unsigned Opcode =
MI.getOpcode();
1564 bool IsStore = Opcode == TargetOpcode::G_STORE;
1570 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1572 *OldCst->getOperand(1).getCImm());
1573 MatchInfo.
Offset = NewCst.getReg(0);
1576 auto MIB =
Builder.buildInstr(NewOpcode);
1578 MIB.addDef(MatchInfo.
Addr);
1579 MIB.addUse(
MI.getOperand(0).getReg());
1581 MIB.addDef(
MI.getOperand(0).getReg());
1582 MIB.addDef(MatchInfo.
Addr);
1585 MIB.addUse(MatchInfo.
Base);
1586 MIB.addUse(MatchInfo.
Offset);
1587 MIB.addImm(MatchInfo.
IsPre);
1588 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1589 MI.eraseFromParent();
1597 unsigned Opcode =
MI.getOpcode();
1598 bool IsDiv, IsSigned;
1603 case TargetOpcode::G_SDIV:
1604 case TargetOpcode::G_UDIV: {
1606 IsSigned = Opcode == TargetOpcode::G_SDIV;
1609 case TargetOpcode::G_SREM:
1610 case TargetOpcode::G_UREM: {
1612 IsSigned = Opcode == TargetOpcode::G_SREM;
1618 unsigned DivOpcode, RemOpcode, DivremOpcode;
1620 DivOpcode = TargetOpcode::G_SDIV;
1621 RemOpcode = TargetOpcode::G_SREM;
1622 DivremOpcode = TargetOpcode::G_SDIVREM;
1624 DivOpcode = TargetOpcode::G_UDIV;
1625 RemOpcode = TargetOpcode::G_UREM;
1626 DivremOpcode = TargetOpcode::G_UDIVREM;
1644 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1645 if (
MI.getParent() ==
UseMI.getParent() &&
1646 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1647 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1660 unsigned Opcode =
MI.getOpcode();
1661 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1664 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1665 DestDivReg =
MI.getOperand(0).getReg();
1669 DestRemReg =
MI.getOperand(0).getReg();
1673 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1680 Builder.setInstrAndDebugLoc(*FirstInst);
1682 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1683 : TargetOpcode::G_UDIVREM,
1684 {DestDivReg, DestRemReg},
1686 MI.eraseFromParent();
1692 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1709 if (BrIt ==
MBB->begin())
1711 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1713 BrCond = &*std::prev(BrIt);
1714 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1720 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1721 MBB->isLayoutSuccessor(BrCondTarget);
1727 Builder.setInstrAndDebugLoc(*BrCond);
1738 MI.getOperand(0).setMBB(FallthroughBB);
1751 unsigned MaxLen)
const {
1752 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1754 DstAlignCanChange, MemOps);
1759 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1764 DstAlignCanChange, MemOps) ==
1766 assert(
Changed &&
"expected memcpy-family instruction to lower");
1771 unsigned MaxLen)
const {
1783 switch (
MI.getOpcode()) {
1786 case TargetOpcode::G_FNEG: {
1787 Result.changeSign();
1790 case TargetOpcode::G_FABS: {
1794 case TargetOpcode::G_FCEIL:
1797 case TargetOpcode::G_FFLOOR:
1800 case TargetOpcode::G_INTRINSIC_TRUNC:
1803 case TargetOpcode::G_INTRINSIC_ROUND:
1806 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1809 case TargetOpcode::G_FRINT:
1810 case TargetOpcode::G_FNEARBYINT:
1814 case TargetOpcode::G_FPEXT:
1815 case TargetOpcode::G_FPTRUNC: {
1817 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1822 case TargetOpcode::G_FSQRT: {
1826 Result =
APFloat(sqrt(Result.convertToDouble()));
1829 case TargetOpcode::G_FLOG2: {
1849 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1850 MI.eraseFromParent();
1861 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1884 Type *AccessTy =
nullptr;
1885 auto &MF = *
MI.getMF();
1886 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1889 MF.getFunction().getContext());
1894 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1899 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1901 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1902 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1903 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1904 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1913 unsigned PtrAddFlags =
MI.getFlags();
1929 MatchInfo.
Flags = Flags;
1935 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1937 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1941 MI.getOperand(1).setReg(MatchInfo.
Base);
1942 MI.getOperand(2).setReg(NewOffset.getReg(0));
1956 unsigned Opcode =
MI.getOpcode();
1957 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1958 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1959 Opcode == TargetOpcode::G_USHLSAT) &&
1960 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1980 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1985 if (Opcode == TargetOpcode::G_USHLSAT &&
1986 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1994 unsigned Opcode =
MI.getOpcode();
1995 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1996 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1997 Opcode == TargetOpcode::G_USHLSAT) &&
1998 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
2000 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
2001 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
2002 auto Imm = MatchInfo.
Imm;
2004 if (
Imm >= ScalarSizeInBits) {
2006 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
2007 Builder.buildConstant(
MI.getOperand(0), 0);
2008 MI.eraseFromParent();
2013 Imm = ScalarSizeInBits - 1;
2016 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
2019 MI.getOperand(1).setReg(MatchInfo.
Reg);
2020 MI.getOperand(2).setReg(NewImm);
2036 unsigned ShiftOpcode =
MI.getOpcode();
2037 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2038 ShiftOpcode == TargetOpcode::G_ASHR ||
2039 ShiftOpcode == TargetOpcode::G_LSHR ||
2040 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2041 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2042 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2045 Register LogicDest =
MI.getOperand(1).getReg();
2046 if (!
MRI.hasOneNonDBGUse(LogicDest))
2052 unsigned LogicOpcode = LogicMI->
getOpcode();
2053 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2054 LogicOpcode != TargetOpcode::G_XOR)
2060 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2063 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2065 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2067 if (
MI->getOpcode() != ShiftOpcode ||
2068 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2077 ShiftVal = MaybeImmVal->Value.getSExtValue();
2091 if (matchFirstShift(LogicMIOp1, C0Val)) {
2093 MatchInfo.
Shift2 = LogicMIOp1;
2094 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2096 MatchInfo.
Shift2 = LogicMIOp2;
2100 MatchInfo.
ValSum = C0Val + C1Val;
2103 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2106 MatchInfo.
Logic = LogicMI;
2112 unsigned Opcode =
MI.getOpcode();
2113 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2114 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2115 Opcode == TargetOpcode::G_SSHLSAT) &&
2116 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2118 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2119 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2125 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2134 Register Shift2Const =
MI.getOperand(2).getReg();
2136 .buildInstr(Opcode, {DestType},
2146 MI.eraseFromParent();
2158 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2162 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2177 LLT InnerShiftTy =
MRI.getType(InnerShift);
2179 if ((N1C + N001C).ult(InnerShiftSize)) {
2185 if ((N001C + OpSizeInBits) == InnerShiftSize)
2187 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2188 MatchInfo.
Mask =
true;
2198 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2205 if (MatchInfo.
Mask ==
true) {
2213 Builder.buildTrunc(Dst, Shift);
2214 MI.eraseFromParent();
2218 unsigned &ShiftVal)
const {
2219 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2225 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2226 return (
static_cast<int32_t
>(ShiftVal) != -1);
2230 unsigned &ShiftVal)
const {
2231 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2233 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2236 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2237 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2258 auto NegCst =
B.buildConstant(Ty, -
Imm);
2260 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2261 MI.getOperand(2).setReg(NegCst.getReg(0));
2263 if (
Imm.isMinSignedValue())
2273 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2287 if (!MaybeShiftAmtVal)
2291 LLT SrcTy =
MRI.getType(ExtSrc);
2301 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2302 MatchData.
Reg = ExtSrc;
2303 MatchData.
Imm = ShiftAmt;
2305 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2306 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2307 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2313 int64_t ShiftAmtVal = MatchData.
Imm;
2315 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2316 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2318 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2319 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2320 MI.eraseFromParent();
2333 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2334 "Expected an unmerge");
2343 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2344 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2346 if (SrcMergeTy != Dst0Ty && !SameSize)
2350 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2351 Operands.push_back(SrcInstr->getSourceReg(Idx));
2357 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2358 "Expected an unmerge");
2360 "Not enough operands to replace all defs");
2361 unsigned NumElems =
MI.getNumOperands() - 1;
2364 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2365 bool CanReuseInputDirectly = DstTy == SrcTy;
2366 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2367 Register DstReg =
MI.getOperand(Idx).getReg();
2372 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2373 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2374 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2375 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2378 if (CanReuseInputDirectly)
2381 Builder.buildCast(DstReg, SrcReg);
2383 MI.eraseFromParent();
2388 unsigned SrcIdx =
MI.getNumOperands() - 1;
2389 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2395 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2398 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2400 Val = Val.
lshr(ShiftAmt);
2408 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2409 "Expected an unmerge");
2411 "Not enough operands to replace all defs");
2412 unsigned NumElems =
MI.getNumOperands() - 1;
2413 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2414 Register DstReg =
MI.getOperand(Idx).getReg();
2415 Builder.buildConstant(DstReg, Csts[Idx]);
2418 MI.eraseFromParent();
2424 unsigned SrcIdx =
MI.getNumOperands() - 1;
2425 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2427 unsigned NumElems =
MI.getNumOperands() - 1;
2428 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2429 Register DstReg =
MI.getOperand(Idx).getReg();
2430 B.buildUndef(DstReg);
2438 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2439 "Expected an unmerge");
2440 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2441 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2444 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2445 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2453 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2454 Register Dst0Reg =
MI.getOperand(0).getReg();
2455 Builder.buildTrunc(Dst0Reg, SrcReg);
2456 MI.eraseFromParent();
2460 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2461 "Expected an unmerge");
2462 Register Dst0Reg =
MI.getOperand(0).getReg();
2463 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2469 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2470 LLT SrcTy =
MRI.getType(SrcReg);
2471 if (SrcTy.isVector())
2481 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2486 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2487 "Expected an unmerge");
2489 Register Dst0Reg =
MI.getOperand(0).getReg();
2494 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2495 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2498 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2501 "ZExt src doesn't fit in destination");
2506 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2508 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2511 MI.eraseFromParent();
2515 unsigned TargetShiftSize,
2516 unsigned &ShiftVal)
const {
2517 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2518 MI.getOpcode() == TargetOpcode::G_LSHR ||
2519 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2521 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2526 unsigned Size = Ty.getSizeInBits();
2527 if (
Size <= TargetShiftSize)
2535 ShiftVal = MaybeImmVal->Value.getSExtValue();
2536 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2543 LLT Ty =
MRI.getType(SrcReg);
2544 unsigned Size = Ty.getSizeInBits();
2545 unsigned HalfSize =
Size / 2;
2546 assert(ShiftVal >= HalfSize);
2550 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2551 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2553 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2554 Register Narrowed = Unmerge.getReg(1);
2561 if (NarrowShiftAmt != 0) {
2562 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2563 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2566 auto Zero =
Builder.buildConstant(HalfTy, 0);
2567 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2568 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2569 Register Narrowed = Unmerge.getReg(0);
2574 if (NarrowShiftAmt != 0) {
2575 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2576 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2579 auto Zero =
Builder.buildConstant(HalfTy, 0);
2580 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2582 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2584 HalfTy, Unmerge.getReg(1),
2585 Builder.buildConstant(HalfTy, HalfSize - 1));
2587 if (ShiftVal == HalfSize) {
2590 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2591 }
else if (ShiftVal ==
Size - 1) {
2599 HalfTy, Unmerge.getReg(1),
2600 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2608 MI.eraseFromParent();
2624 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2629 SrcReg = OriginalSrcReg;
2630 LLT DstTy =
MRI.getType(DstReg);
2638 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2641 LLT DstTy =
MRI.getType(DstReg);
2646 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2647 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2657 if (ShiftSize > 32 && TruncSize < 32)
2670 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2671 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2675 if (!
MRI.hasOneNonDBGUse(SrcReg))
2678 LLT SrcTy =
MRI.getType(SrcReg);
2679 LLT DstTy =
MRI.getType(DstReg);
2688 case TargetOpcode::G_SHL: {
2697 case TargetOpcode::G_LSHR:
2698 case TargetOpcode::G_ASHR: {
2704 for (
auto &
User :
MRI.use_instructions(DstReg))
2705 if (
User.getOpcode() == TargetOpcode::G_STORE)
2709 if (NewShiftTy == SrcTy)
2723 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2726 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2731 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2733 LLT NewShiftTy = MatchInfo.second;
2736 LLT DstTy =
MRI.getType(Dst);
2740 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2743 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2744 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2745 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2749 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2752 if (NewShiftTy == DstTy)
2755 Builder.buildTrunc(Dst, NewShift);
2762 return !MO.isReg() ||
2763 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2768 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2770 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2775 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2776 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2777 "Expected an insert/extract element op");
2778 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2783 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2831 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2858 return MO.isReg() && MO.getReg().isPhysical();
2868 return I1->isIdenticalTo(*I2);
2876 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2883 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2904 std::optional<FPValueAndVReg> MaybeCst;
2908 return MaybeCst->Value.isExactlyValue(
C);
2912 unsigned OpIdx)
const {
2913 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2915 Register Replacement =
MI.getOperand(OpIdx).getReg();
2918 MI.eraseFromParent();
2923 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2927 MI.eraseFromParent();
2931 unsigned ConstIdx)
const {
2932 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2933 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2945 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2946 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2947 "This is not a funnel shift operation");
2949 Register ConstReg =
MI.getOperand(3).getReg();
2950 LLT ConstTy =
MRI.getType(ConstReg);
2951 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2954 assert((VRegAndVal) &&
"Value is not a constant");
2957 APInt NewConst = VRegAndVal->Value.
urem(
2962 MI.getOpcode(), {MI.getOperand(0)},
2963 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2965 MI.eraseFromParent();
2969 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2983 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2985 MI.eraseFromParent();
2990 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2992 MI.eraseFromParent();
2996 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2998 MI.eraseFromParent();
3003 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3005 MI.eraseFromParent();
3009 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3011 MI.eraseFromParent();
3016 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3019 LLT DstTy =
MRI.getType(DstReg);
3028 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3029 TargetOpcode::G_INSERT_VECTOR_ELT)
3035 MatchInfo.
resize(NumElts);
3039 if (IntImm >= NumElts || IntImm < 0)
3041 if (!MatchInfo[IntImm])
3042 MatchInfo[IntImm] = TmpReg;
3046 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3048 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3057 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3064 auto GetUndef = [&]() {
3067 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3075 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3076 MI.eraseFromParent();
3089 unsigned InnerOpc = InnerDef->
getOpcode();
3090 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3093 if (!
MRI.hasOneNonDBGUse(MInner))
3104 if (!
MRI.hasOneNonDBGUse(MaybeNot))
3114 if (!TryMatch(InnerLHS, InnerRHS) &&
3115 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3119 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3120 : TargetOpcode::G_ADD;
3123 MatchInfo = [=](MachineIRBuilder &
Builder) {
3124 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3125 auto NewNot =
Builder.buildNot(Ty, NewInner);
3126 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3138 unsigned RootOpc =
MI.getOpcode();
3140 LLT Ty =
MRI.getType(Dst);
3145 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3146 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3157 unsigned LogicOpcode =
MI.getOpcode();
3158 assert(LogicOpcode == TargetOpcode::G_AND ||
3159 LogicOpcode == TargetOpcode::G_OR ||
3160 LogicOpcode == TargetOpcode::G_XOR);
3167 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3173 if (!LeftHandInst || !RightHandInst)
3175 unsigned HandOpcode = LeftHandInst->
getOpcode();
3176 if (HandOpcode != RightHandInst->
getOpcode())
3190 if (!XTy.
isValid() || XTy != YTy)
3195 switch (HandOpcode) {
3198 case TargetOpcode::G_ANYEXT:
3199 case TargetOpcode::G_SEXT:
3200 case TargetOpcode::G_ZEXT: {
3204 case TargetOpcode::G_TRUNC: {
3209 LLT DstTy =
MRI.getType(Dst);
3218 case TargetOpcode::G_AND:
3219 case TargetOpcode::G_ASHR:
3220 case TargetOpcode::G_LSHR:
3221 case TargetOpcode::G_SHL: {
3226 ExtraHandOpSrcReg = ZOp.
getReg();
3237 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3248 if (ExtraHandOpSrcReg.
isValid())
3260 "Expected at least one instr to build?");
3262 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3263 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3265 for (
auto &OperandFn : InstrToBuild.OperandFns)
3268 MI.eraseFromParent();
3272 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3273 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3274 int64_t ShlCst, AshrCst;
3280 if (ShlCst != AshrCst)
3283 {TargetOpcode::G_SEXT_INREG,
3286 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3288 MatchInfo = std::make_tuple(Src, ShlCst);
3293 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3294 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3297 std::tie(Src, ShiftAmt) = MatchInfo;
3298 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3299 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3300 MI.eraseFromParent();
3307 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3310 LLT Ty =
MRI.getType(Dst);
3322 B.buildAnd(Dst, R,
B.buildConstant(Ty,
C1 & C2));
3325 auto Zero =
B.buildConstant(Ty, 0);
3348 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3372 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3379 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3396 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3414 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3421 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3432 unsigned ExtBits =
MI.getOperand(2).getImm();
3433 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3434 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3438 int64_t Cst,
bool IsVector,
bool IsFP) {
3440 return (ScalarSizeBits == 1 && Cst == -1) ||
3462 unsigned BuildUseCount = BV.getNumSources();
3463 if (BuildUseCount % 2 != 0)
3466 unsigned NumUnmerge = BuildUseCount / 2;
3472 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3475 UnmergeSrc = Unmerge->getSourceReg();
3477 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3478 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3485 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3490 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3491 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3494 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3497 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3502 if (Unmerge->getNumDefs() != NumUnmerge)
3506 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3509 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3520 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3521 B.setInstrAndDebugLoc(
MI);
3523 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3524 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3526 MI.eraseFromParent();
3548 unsigned NumOperands =
BuildMI->getNumSources();
3558 for (
I = 0;
I < NumOperands; ++
I) {
3570 UnmergeMI != UnmergeSrcMI)
3581 for (;
I < NumOperands; ++
I) {
3588 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3598 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3599 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3607 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3610 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3622 LLT DstTy =
MRI.getType(DstReg);
3623 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3628 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3633 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3637 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3640 Builder.buildTrunc(DstReg, MidReg);
3641 MI.eraseFromParent();
3646 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3647 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3648 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3656 if (!
MRI.hasOneNonDBGUse(XorSrc))
3666 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3668 if (!
MRI.hasOneNonDBGUse(Reg))
3673 switch (Def->getOpcode()) {
3678 case TargetOpcode::G_ICMP:
3684 case TargetOpcode::G_FCMP:
3690 case TargetOpcode::G_AND:
3691 case TargetOpcode::G_OR:
3697 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3698 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3706 if (Ty.isVector()) {
3710 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), SplatCst,
true, IsFP))
3724 for (
Register Reg : RegsToNegate) {
3729 switch (Def->getOpcode()) {
3732 case TargetOpcode::G_ICMP:
3733 case TargetOpcode::G_FCMP: {
3740 case TargetOpcode::G_AND:
3741 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3743 case TargetOpcode::G_OR:
3744 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3751 MI.eraseFromParent();
3755 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3757 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3761 Register SharedReg =
MI.getOperand(2).getReg();
3775 if (!
MRI.hasOneNonDBGUse(AndReg))
3782 return Y == SharedReg;
3786 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3789 std::tie(
X,
Y) = MatchInfo;
3792 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3793 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3794 MI.getOperand(2).setReg(
Y);
3800 Register DstReg = PtrAdd.getReg(0);
3801 LLT Ty =
MRI.getType(DstReg);
3804 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3819 Register Pow2Src1 =
MI.getOperand(2).getReg();
3820 LLT Ty =
MRI.getType(DstReg);
3823 auto NegOne =
Builder.buildConstant(Ty, -1);
3824 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3826 MI.eraseFromParent();
3830 unsigned &SelectOpNo)
const {
3842 !
MRI.hasOneNonDBGUse(LHS)) {
3843 OtherOperandReg = LHS;
3847 !
MRI.hasOneNonDBGUse(RHS))
3865 unsigned BinOpcode =
MI.getOpcode();
3870 bool CanFoldNonConst =
3871 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3876 if (CanFoldNonConst)
3901 LLT Ty =
MRI.getType(Dst);
3902 unsigned BinOpcode =
MI.getOpcode();
3909 if (SelectOperand == 1) {
3913 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3915 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3917 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3919 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3922 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3923 MI.eraseFromParent();
3926std::optional<SmallVector<Register, 8>>
3927CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3928 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3957 const unsigned MaxIter =
3959 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3967 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
3968 return std::nullopt;
3984 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3985 return std::nullopt;
3997static std::optional<std::pair<GZExtLoad *, int64_t>>
4001 "Expected Reg to only have one non-debug use?");
4010 if (Shift % MemSizeInBits != 0)
4011 return std::nullopt;
4016 return std::nullopt;
4018 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
4019 return std::nullopt;
4021 return std::make_pair(
Load, Shift / MemSizeInBits);
4024std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4025CombinerHelper::findLoadOffsetsForLoadOrCombine(
4028 const unsigned MemSizeInBits)
const {
4031 SmallSetVector<const MachineInstr *, 8> Loads;
4037 GZExtLoad *LowestIdxLoad =
nullptr;
4040 SmallSet<int64_t, 8> SeenIdx;
4044 MachineBasicBlock *
MBB =
nullptr;
4045 const MachineMemOperand *MMO =
nullptr;
4048 GZExtLoad *EarliestLoad =
nullptr;
4051 GZExtLoad *LatestLoad =
nullptr;
4060 for (
auto Reg : RegsToVisit) {
4065 return std::nullopt;
4068 std::tie(
Load, DstPos) = *LoadAndPos;
4072 MachineBasicBlock *LoadMBB =
Load->getParent();
4076 return std::nullopt;
4079 auto &LoadMMO =
Load->getMMO();
4083 return std::nullopt;
4090 LoadPtr =
Load->getOperand(1).getReg();
4095 if (!SeenIdx.
insert(Idx).second)
4096 return std::nullopt;
4103 if (BasePtr != LoadPtr)
4104 return std::nullopt;
4106 if (Idx < LowestIdx) {
4108 LowestIdxLoad =
Load;
4115 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4116 return std::nullopt;
4125 EarliestLoad =
Load;
4133 "Expected to find a load for each register?");
4134 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4135 LatestLoad &&
"Expected at least two loads?");
4144 const unsigned MaxIter = 20;
4150 if (
MI.isLoadFoldBarrier())
4151 return std::nullopt;
4152 if (Iter++ == MaxIter)
4153 return std::nullopt;
4156 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4162 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4175 LLT Ty =
MRI.getType(Dst);
4181 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4182 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4186 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4193 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4194 if (NarrowMemSizeInBits % 8 != 0)
4207 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4208 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4211 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4218 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4221 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4233 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4234 const unsigned ZeroByteOffset =
4238 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4239 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4240 ZeroOffsetIdx->second != LowestIdx)
4250 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4264 MIB.setInstrAndDebugLoc(*LatestLoad);
4265 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4266 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4268 MIB.buildBSwap(Dst, LoadDst);
4280 if (
MRI.getType(DstReg).isVector())
4284 if (!
MRI.hasOneNonDBGUse(DstReg))
4286 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4288 case TargetOpcode::G_ANYEXT:
4290 case TargetOpcode::G_ZEXT:
4291 case TargetOpcode::G_SEXT:
4298 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4305 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4307 switch (
DefMI->getOpcode()) {
4308 case TargetOpcode::G_LOAD:
4309 case TargetOpcode::G_TRUNC:
4310 case TargetOpcode::G_SEXT:
4311 case TargetOpcode::G_ZEXT:
4312 case TargetOpcode::G_ANYEXT:
4313 case TargetOpcode::G_CONSTANT:
4317 if (InSrcs.
size() > 2)
4331 LLT ExtTy =
MRI.getType(DstReg);
4338 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4339 auto SrcReg =
PHI.getIncomingValue(
I);
4343 if (!SrcMIs.
insert(SrcMI))
4349 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4350 InsertPt =
MBB->getFirstNonPHI();
4355 OldToNewSrcMap[SrcMI] = NewExt;
4360 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4361 NewPhi.addDef(DstReg);
4364 NewPhi.addMBB(MO.getMBB());
4367 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4368 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4376 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4380 LLT SrcTy =
MRI.getType(SrcVec);
4381 if (SrcTy.isScalableVector())
4385 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4388 unsigned VecIdx = Cst->Value.getZExtValue();
4400 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4401 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4405 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4417 LLT ScalarTy =
MRI.getType(Reg);
4419 LLT DstTy =
MRI.getType(DstReg);
4421 if (ScalarTy != DstTy) {
4423 Builder.buildTrunc(DstReg, Reg);
4424 MI.eraseFromParent();
4432 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4433 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4451 LLT DstTy =
MRI.getType(DstReg);
4456 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4461 unsigned Idx = Cst->getZExtValue();
4464 ExtractedElts.
set(Idx);
4465 SrcDstPairs.emplace_back(
4466 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4469 return ExtractedElts.
all();
4474 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4475 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4476 for (
auto &Pair : SrcDstPairs) {
4477 auto *ExtMI = Pair.second;
4479 ExtMI->eraseFromParent();
4481 MI.eraseFromParent();
4488 MI.eraseFromParent();
4498 bool AllowScalarConstants,
4500 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4503 LLT Ty =
MRI.getType(Dst);
4504 unsigned BitWidth = Ty.getScalarSizeInBits();
4506 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4507 unsigned FshOpc = 0;
4518 int64_t CstShlAmt = 0, CstLShrAmt;
4521 CstShlAmt + CstLShrAmt ==
BitWidth) {
4522 FshOpc = TargetOpcode::G_FSHR;
4528 FshOpc = TargetOpcode::G_FSHL;
4533 FshOpc = TargetOpcode::G_FSHR;
4538 LLT AmtTy =
MRI.getType(Amt);
4540 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4544 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4551 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4552 MI.getOpcode() == TargetOpcode::G_ROTR);
4554 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4556 bool OutOfRange =
false;
4557 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4559 OutOfRange |= CI->getValue().uge(Bitsize);
4566 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4567 MI.getOpcode() == TargetOpcode::G_ROTR);
4569 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4571 LLT AmtTy =
MRI.getType(Amt);
4572 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4573 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4575 MI.getOperand(2).setReg(Amt);
4580 int64_t &MatchInfo)
const {
4581 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4592 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4593 if (KnownRHS.isUnknown())
4596 std::optional<bool> KnownVal;
4597 if (KnownRHS.isZero()) {
4607 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4617 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4626 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4642 LLT DstTy =
MRI.getType(Dst);
4650 auto KnownLHS =
VT->getKnownBits(LHS);
4651 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4654 LLT LHSTy =
MRI.getType(LHS);
4657 unsigned Op = TargetOpcode::COPY;
4658 if (DstSize != LHSSize)
4659 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4670 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4674 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4680 int64_t AndMaskBits;
4688 if (AndMaskBits & OrMaskBits)
4694 if (
MI.getOperand(1).getReg() == AndMaskReg)
4695 MI.getOperand(2).setReg(AndMaskReg);
4696 MI.getOperand(1).setReg(Src);
4706 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4709 LLT Ty =
MRI.getType(Src);
4711 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4713 int64_t Width =
MI.getOperand(2).getImm();
4721 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4725 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4726 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4727 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4737 LLT Ty =
MRI.getType(Dst);
4741 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4744 int64_t AndImm, LSBImm;
4746 const unsigned Size = Ty.getScalarSizeInBits();
4754 uint64_t MaybeMask =
static_cast<uint64_t
>(AndImm);
4759 if (MaybeMask & (MaybeMask + 1))
4763 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4771 if (
static_cast<uint64_t
>(LSBImm) + Width >
Size)
4775 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4776 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4777 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4785 const unsigned Opcode =
MI.getOpcode();
4786 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4788 const Register Dst =
MI.getOperand(0).getReg();
4790 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4791 ? TargetOpcode::G_SBFX
4792 : TargetOpcode::G_UBFX;
4795 LLT Ty =
MRI.getType(Dst);
4797 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4803 const unsigned Size = Ty.getScalarSizeInBits();
4813 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4817 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4821 const int64_t Pos = ShrAmt - ShlAmt;
4822 const int64_t Width =
Size - ShrAmt;
4825 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4826 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4827 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4835 const unsigned Opcode =
MI.getOpcode();
4836 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4838 const Register Dst =
MI.getOperand(0).getReg();
4839 LLT Ty =
MRI.getType(Dst);
4841 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4854 const unsigned Size = Ty.getScalarSizeInBits();
4855 if (ShrAmt < 0 || ShrAmt >=
Size)
4859 if (0 == (SMask >> ShrAmt)) {
4861 B.buildConstant(Dst, 0);
4874 const int64_t Pos = ShrAmt;
4879 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4883 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4884 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4885 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4890bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4894 Register Src1Reg = PtrAdd.getBaseReg();
4899 Register Src2Reg = PtrAdd.getOffsetReg();
4901 if (
MRI.hasOneNonDBGUse(Src1Reg))
4911 const APInt &C1APIntVal = *
C1;
4912 const APInt &C2APIntVal = *C2;
4913 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4915 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4918 MachineInstr *ConvUseMI = &
UseMI;
4919 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4920 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4921 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4923 if (!
MRI.hasOneNonDBGUse(DefReg))
4925 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4934 TargetLoweringBase::AddrMode AM;
4937 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4939 PtrAdd.getMF()->getFunction().getContext());
4940 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4941 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4947 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4959 Register Src1Reg =
MI.getOperand(1).getReg();
4960 if (RHS->getOpcode() != TargetOpcode::G_ADD)
4972 unsigned PtrAddFlags =
MI.getFlags();
4973 unsigned AddFlags = RHS->getFlags();
4986 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
4989 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
4991 MI.getOperand(1).setReg(NewBase.getReg(0));
4992 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
4996 return !reassociationCanBreakAddressingModePattern(
MI);
5006 std::optional<ValueAndVReg> LHSCstOff;
5016 unsigned PtrAddFlags =
MI.getFlags();
5017 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5019 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5021 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5035 LHSPtrAdd->moveBefore(&
MI);
5038 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5040 MI.getOperand(2).setReg(NewCst.getReg(0));
5043 Observer.changingInstr(*LHSPtrAdd);
5044 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5045 LHSPtrAdd->setFlags(Flags);
5048 return !reassociationCanBreakAddressingModePattern(
MI);
5059 Register Src2Reg =
MI.getOperand(2).getReg();
5060 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5061 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5074 unsigned PtrAddFlags =
MI.getFlags();
5075 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5088 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *
C1 + *C2);
5090 MI.getOperand(1).setReg(LHSSrc1);
5091 MI.getOperand(2).setReg(NewCst.getReg(0));
5095 return !reassociationCanBreakAddressingModePattern(
MI);
5135 LLT OpRHSTy =
MRI.getType(OpRHS);
5152 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5153 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5161 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5162 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5175 unsigned Opc =
MI.getOpcode();
5188 APInt &MatchInfo)
const {
5189 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5193 MatchInfo = *MaybeCst;
5204 MI.getOperand(1).getReg(),
MRI);
5209 if (Csts.size() == 1)
5210 B.buildConstant(Dst, Csts[0]);
5212 B.buildBuildVectorConstant(Dst, Csts);
5218 APInt &MatchInfo)
const {
5224 MatchInfo = *MaybeCst;
5236 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5242 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5243 MI.getOpcode() == TargetOpcode::G_FMAD);
5244 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5261 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5284 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5288 LLT WideTy =
MRI.getType(Dst);
5292 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5308 case TargetOpcode::G_ADD:
5309 case TargetOpcode::G_SUB:
5310 case TargetOpcode::G_MUL:
5311 case TargetOpcode::G_AND:
5312 case TargetOpcode::G_OR:
5313 case TargetOpcode::G_XOR:
5321 auto Mask = Cst->Value;
5326 unsigned NarrowWidth = Mask.countr_one();
5332 auto &MF = *
MI.getMF();
5335 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5336 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5344 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5345 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5347 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5348 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5350 MI.getOperand(1).setReg(Ext.getReg(0));
5359 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5360 MI.getOpcode() == TargetOpcode::G_SMULO);
5369 B.buildConstant(Dst, 0);
5370 B.buildConstant(Carry, 0);
5378 if (SrcA.
isValid() && SrcA == SrcB)
5386 unsigned Opcode =
MI.getOpcode();
5387 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5389 Register Dst = UDivorRem.getReg(0);
5390 Register LHS = UDivorRem.getReg(1);
5391 Register RHS = UDivorRem.getReg(2);
5392 LLT Ty =
MRI.getType(Dst);
5400 bool UseSRL =
false;
5405 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5407 if (IsSplat && !Factors.
empty()) {
5414 APInt Divisor = CI->getValue();
5423 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5424 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5434 if (Ty.isVector()) {
5435 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5436 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5439 Factor = Factors[0];
5447 return MIB.buildMul(Ty, Res, Factor);
5450 unsigned KnownLeadingZeros =
5451 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5453 bool UseNPQ =
false;
5455 auto BuildUDIVPattern = [&](
const Constant *
C) {
5457 const APInt &Divisor = CI->getValue();
5459 bool SelNPQ =
false;
5461 unsigned PreShift = 0, PostShift = 0;
5466 if (!Divisor.
isOne()) {
5472 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5474 Magic = std::move(magics.
Magic);
5477 "We shouldn't generate an undefined shift!");
5479 "We shouldn't generate an undefined shift!");
5483 SelNPQ = magics.
IsAdd;
5487 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5488 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5490 MIB.buildConstant(ScalarTy,
5495 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5503 assert(Matched &&
"Expected unary predicate match to succeed");
5505 Register PreShift, PostShift, MagicFactor, NPQFactor;
5508 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5509 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5510 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5511 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5514 "Non-build_vector operation should have been a scalar");
5515 PreShift = PreShifts[0];
5516 MagicFactor = MagicFactors[0];
5517 PostShift = PostShifts[0];
5521 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5524 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5527 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5532 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5534 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5536 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5539 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5540 auto One = MIB.buildConstant(Ty, 1);
5541 auto IsOne = MIB.buildICmp(
5545 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5547 if (Opcode == TargetOpcode::G_UREM) {
5548 auto Prod = MIB.buildMul(Ty, ret, RHS);
5549 return MIB.buildSub(Ty, LHS, Prod);
5555 unsigned Opcode =
MI.getOpcode();
5556 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5559 LLT DstTy =
MRI.getType(Dst);
5561 auto &MF = *
MI.getMF();
5571 if (MF.getFunction().hasMinSize())
5574 if (Opcode == TargetOpcode::G_UDIV &&
5577 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5592 {TargetOpcode::G_ICMP,
5596 if (Opcode == TargetOpcode::G_UREM &&
5602 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5611 unsigned Opcode =
MI.getOpcode();
5612 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5615 LLT DstTy =
MRI.getType(Dst);
5619 auto &MF = *
MI.getMF();
5629 if (MF.getFunction().hasMinSize())
5633 if (Opcode == TargetOpcode::G_SDIV &&
5636 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5648 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5651 if (Opcode == TargetOpcode::G_SREM &&
5657 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5666 unsigned Opcode =
MI.getOpcode();
5667 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5668 Opcode == TargetOpcode::G_SREM);
5670 Register Dst = SDivorRem.getReg(0);
5671 Register LHS = SDivorRem.getReg(1);
5672 Register RHS = SDivorRem.getReg(2);
5673 LLT Ty =
MRI.getType(Dst);
5680 bool UseSRA =
false;
5686 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5688 if (IsSplat && !ExactFactors.
empty()) {
5690 ExactFactors.
push_back(ExactFactors[0]);
5695 APInt Divisor = CI->getValue();
5705 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5706 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5714 assert(Matched &&
"Expected unary predicate match to succeed");
5717 if (Ty.isVector()) {
5718 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5719 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5721 Shift = ExactShifts[0];
5722 Factor = ExactFactors[0];
5730 return MIB.buildMul(Ty, Res, Factor);
5735 auto BuildSDIVPattern = [&](
const Constant *
C) {
5737 const APInt &Divisor = CI->getValue();
5741 int NumeratorFactor = 0;
5752 NumeratorFactor = 1;
5755 NumeratorFactor = -1;
5758 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5759 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5761 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5762 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5770 assert(Matched &&
"Expected unary predicate match to succeed");
5772 Register MagicFactor, Factor, Shift, ShiftMask;
5775 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5776 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5777 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5778 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5781 "Non-build_vector operation should have been a scalar");
5782 MagicFactor = MagicFactors[0];
5783 Factor = Factors[0];
5785 ShiftMask = ShiftMasks[0];
5789 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5792 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5793 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5796 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5799 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5800 auto T = MIB.buildLShr(Ty, Q, SignShift);
5801 T = MIB.buildAnd(Ty,
T, ShiftMask);
5802 auto ret = MIB.buildAdd(Ty, Q,
T);
5804 if (Opcode == TargetOpcode::G_SREM) {
5805 auto Prod = MIB.buildMul(Ty, ret, RHS);
5806 return MIB.buildSub(Ty, LHS, Prod);
5812 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5813 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5814 "Expected SDIV or UDIV");
5817 auto MatchPow2 = [&](
const Constant *
C) {
5819 return CI && (CI->getValue().isPowerOf2() ||
5820 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5826 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5831 LLT Ty =
MRI.getType(Dst);
5851 unsigned BitWidth = Ty.getScalarSizeInBits();
5852 auto Zero =
Builder.buildConstant(Ty, 0);
5855 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5856 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits,
C1);
5858 auto Sign =
Builder.buildAShr(
5862 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5868 auto One =
Builder.buildConstant(Ty, 1);
5869 auto MinusOne =
Builder.buildConstant(Ty, -1);
5873 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5874 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5878 auto Neg =
Builder.buildNeg(Ty, AShr);
5880 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5881 MI.eraseFromParent();
5885 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5890 LLT Ty =
MRI.getType(Dst);
5893 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5894 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS,
C1);
5895 MI.eraseFromParent();
5899 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
5904 LLT Ty =
MRI.getType(Dst);
5923 unsigned BitWidth = Ty.getScalarSizeInBits();
5924 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
5925 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
5927 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
5928 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
5929 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
5932 MI.eraseFromParent();
5936 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5939 LLT Ty =
MRI.getType(Dst);
5940 LLT RHSTy =
MRI.getType(RHS);
5942 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5944 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
5959 LLT Ty =
MRI.getType(Dst);
5965 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
5966 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
5967 Builder.buildLShr(Dst, LHS, Trunc);
5968 MI.eraseFromParent();
5975 LLT DstTy =
MRI.getType(Dst);
5976 LLT SrcTy =
MRI.getType(Src);
5978 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
5979 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
5982 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6011 Builder.buildTruncSSatS(Dst, MatchInfo);
6012 MI.eraseFromParent();
6019 LLT DstTy =
MRI.getType(Dst);
6020 LLT SrcTy =
MRI.getType(Src);
6022 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6023 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6026 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6044 Builder.buildTruncSSatU(Dst, MatchInfo);
6045 MI.eraseFromParent();
6052 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6053 LLT SrcTy =
MRI.getType(Val);
6055 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6056 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6059 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6068 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6076 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6079 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6081 const auto LHSCst = Ty.isVector()
6095 if (LHSCst->Value.isNegZero())
6099 if (LHSCst->Value.isPosZero())
6108 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6116 MRI.use_instr_nodbg_end()) >
6118 MRI.use_instr_nodbg_end());
6122 bool &AllowFusionGlobally,
6124 bool CanReassociate)
const {
6126 auto *MF =
MI.getMF();
6127 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6128 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6136 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6139 if (!HasFMAD && !HasFMA)
6144 AllowFusionGlobally = HasFMAD;
6149 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6156 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6158 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6170 unsigned PreferredFusedOpcode =
6171 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6184 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6186 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6187 {LHS.MI->getOperand(1).getReg(),
6188 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6197 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6199 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6200 {RHS.MI->getOperand(1).getReg(),
6201 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6213 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6215 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6219 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6228 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6230 unsigned PreferredFusedOpcode =
6231 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6234 bool LHSContractable =
6237 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6240 bool RHSContractable =
6243 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6247 if (LHSContractable || RHSContractable) {
6250 if (!LHSContractable ||
6251 (RHSContractable &&
hasMoreUses(*LHSFpExtSrc, *RHSFpExtSrc,
MRI))) {
6253 LHSFpExtSrc = RHSFpExtSrc;
6256 unsigned Flags =
MI.getFlags() & LHSFpExtSrc->
getFlags();
6260 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6261 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6272 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6274 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6286 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6288 unsigned PreferredFusedOpcode =
6289 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6294 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6297 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6298 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6303 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6306 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6307 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6316 Register X = FMA->getOperand(1).getReg();
6317 Register Y = FMA->getOperand(2).getReg();
6320 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6321 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6324 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6325 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6326 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6327 {
X,
Y, InnerFMA}, OuterFlags);
6338 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6340 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6347 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6348 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6358 unsigned PreferredFusedOpcode =
6359 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6373 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6374 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6375 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6376 {FpExtU, FpExtV, Z}, InnerFlags)
6378 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6379 {
X,
Y, InnerFMA}, OuterFlags);
6385 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6389 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6391 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6392 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6396 LHS.MI->getOperand(1).getReg(),
6397 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6408 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6413 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6415 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6416 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6420 X =
B.buildFPExt(DstType,
X).getReg(0);
6421 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6424 InnerFlags, OuterFlags,
B);
6433 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6437 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6439 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6440 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6444 RHS.MI->getOperand(1).getReg(),
6445 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6456 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6461 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6463 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6464 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6468 X =
B.buildFPExt(DstType,
X).getReg(0);
6469 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6472 InnerFlags, OuterFlags,
B);
6484 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6486 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6498 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6502 int FirstMulHasFewerUses =
true;
6506 FirstMulHasFewerUses =
false;
6508 unsigned PreferredFusedOpcode =
6509 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6512 if (FirstMulHasFewerUses &&
6515 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6517 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6518 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6519 {LHS.MI->getOperand(1).getReg(),
6520 LHS.MI->getOperand(2).getReg(), NegZ},
6528 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6531 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6532 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6533 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6544 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6546 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6552 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6554 unsigned PreferredFusedOpcode =
6555 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6563 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6567 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6568 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6579 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6581 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6595 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6597 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6603 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6605 unsigned PreferredFusedOpcode =
6606 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6613 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6619 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6620 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6621 {FpExtX, FpExtY, NegZ}, Flags);
6630 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6634 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6637 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6638 {NegY, FpExtZ, LHSReg}, Flags);
6649 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6651 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6655 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6656 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6660 unsigned PreferredFusedOpcode =
6661 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6665 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6666 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6667 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
6678 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6680 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6682 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6685 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6695 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6697 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6713 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6723 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
6740 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6741 if (&U == &
MI || U.getParent() !=
MI.getParent())
6743 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6744 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
6745 !IsOne(U.getOperand(1).getReg())) {
6758 return MatchInfo.
size() >= MinUses;
6766 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6767 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6768 MatchInfo[0]->getOperand(2).getReg(),
6769 MatchInfo[0]->getFlags());
6774 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6775 Div->getOperand(0).getReg(),
MI->getFlags());
6776 MI->eraseFromParent();
6798 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6807 return MRI.getType(MatchInfo) == DstVecTy;
6810 std::optional<ValueAndVReg> ShiftAmount;
6819 return MRI.getType(MatchInfo) == DstVecTy;
6834 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6841 std::optional<ValueAndVReg> ShiftAmt;
6847 LLT MatchTy =
MRI.getType(MatchInfo);
6848 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6849 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6852unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6854 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6855 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6856 "Expected a NaN behaviour?");
6866 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6867 return TargetOpcode::G_FMAXNUM;
6868 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6869 return TargetOpcode::G_FMAXIMUM;
6870 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6871 return TargetOpcode::G_FMAXNUM;
6872 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6873 return TargetOpcode::G_FMAXIMUM;
6879 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6880 return TargetOpcode::G_FMINNUM;
6881 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6882 return TargetOpcode::G_FMINIMUM;
6883 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6884 return TargetOpcode::G_FMINNUM;
6885 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6887 return TargetOpcode::G_FMINIMUM;
6891CombinerHelper::SelectPatternNaNBehaviour
6893 bool IsOrderedComparison)
const {
6894 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
6895 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
6897 if (!LHSSafe && !RHSSafe)
6898 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6899 if (LHSSafe && RHSSafe)
6900 return SelectPatternNaNBehaviour::RETURNS_ANY;
6903 if (IsOrderedComparison)
6904 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6905 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6908 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6909 : SelectPatternNaNBehaviour::RETURNS_NAN;
6918 LLT DstTy =
MRI.getType(Dst);
6931 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6933 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6935 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6938 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6939 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6940 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6941 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6943 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6946 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6951 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
6956 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
6958 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
6962 MatchInfo = [=](MachineIRBuilder &
B) {
6963 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
6971 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
6978 Register TrueVal =
MI.getOperand(2).getReg();
6979 Register FalseVal =
MI.getOperand(3).getReg();
6980 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
6985 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
6998 if (MatchedSub &&
X != OpLHS)
7006 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7009 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7010 B.buildICmp(Pred, Dst,
Y, Zero);
7017static std::optional<unsigned>
7019 std::optional<int64_t> &Result) {
7020 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7021 Opcode == TargetOpcode::G_ASHR) &&
7022 "Expect G_SHL, G_LSHR or G_ASHR.");
7023 auto SignificantBits = 0;
7025 case TargetOpcode::G_SHL:
7029 case TargetOpcode::G_LSHR:
7033 case TargetOpcode::G_ASHR:
7042 Result = std::nullopt;
7053 Register ShiftVal =
MI.getOperand(1).getReg();
7054 Register ShiftReg =
MI.getOperand(2).getReg();
7055 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7056 auto IsShiftTooBig = [&](
const Constant *
C) {
7061 MatchInfo = std::nullopt;
7065 MI.getOpcode(), MatchInfo);
7066 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7072 unsigned LHSOpndIdx = 1;
7073 unsigned RHSOpndIdx = 2;
7074 switch (
MI.getOpcode()) {
7075 case TargetOpcode::G_UADDO:
7076 case TargetOpcode::G_SADDO:
7077 case TargetOpcode::G_UMULO:
7078 case TargetOpcode::G_SMULO:
7085 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7086 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7096 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7100 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7107 std::optional<FPValueAndVReg> ValAndVReg;
7113bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7114 LLT SrcTy =
MRI.getType(Src);
7115 if (SrcTy.isFixedVector())
7117 if (SrcTy.isScalar()) {
7121 return IConstant && IConstant->Value == 1;
7126bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7127 LLT SrcTy =
MRI.getType(Src);
7129 return isConstantSplatVector(Src, 0, AllowUndefs);
7134 return IConstant && IConstant->Value == 0;
7141bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7142 bool AllowUndefs)
const {
7148 for (
unsigned I = 0;
I < NumSources; ++
I) {
7149 GImplicitDef *ImplicitDef =
7151 if (ImplicitDef && AllowUndefs)
7153 if (ImplicitDef && !AllowUndefs)
7155 std::optional<ValueAndVReg> IConstant =
7157 if (IConstant && IConstant->Value == SplatValue)
7167CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7170 return IConstant->Value;
7174 return std::nullopt;
7177 std::optional<APInt>
Value = std::nullopt;
7178 for (
unsigned I = 0;
I < NumSources; ++
I) {
7179 std::optional<ValueAndVReg> IConstant =
7182 return std::nullopt;
7184 Value = IConstant->Value;
7185 else if (*
Value != IConstant->Value)
7186 return std::nullopt;
7192bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7202 for (
unsigned I = 0;
I < NumSources; ++
I) {
7203 std::optional<ValueAndVReg> IConstant =
7212bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7219 LLT CondTy =
MRI.getType(
Select->getCondReg());
7220 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7230 std::optional<ValueAndVReg> TrueOpt =
7232 std::optional<ValueAndVReg> FalseOpt =
7235 if (!TrueOpt || !FalseOpt)
7238 APInt TrueValue = TrueOpt->Value;
7239 APInt FalseValue = FalseOpt->Value;
7243 MatchInfo = [=](MachineIRBuilder &
B) {
7244 B.setInstrAndDebugLoc(*
Select);
7245 B.buildZExtOrTrunc(Dest,
Cond);
7252 MatchInfo = [=](MachineIRBuilder &
B) {
7253 B.setInstrAndDebugLoc(*
Select);
7254 B.buildSExtOrTrunc(Dest,
Cond);
7261 MatchInfo = [=](MachineIRBuilder &
B) {
7262 B.setInstrAndDebugLoc(*
Select);
7263 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7264 B.buildNot(Inner,
Cond);
7265 B.buildZExtOrTrunc(Dest, Inner);
7272 MatchInfo = [=](MachineIRBuilder &
B) {
7273 B.setInstrAndDebugLoc(*
Select);
7274 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7275 B.buildNot(Inner,
Cond);
7276 B.buildSExtOrTrunc(Dest, Inner);
7282 if (TrueValue - 1 == FalseValue) {
7283 MatchInfo = [=](MachineIRBuilder &
B) {
7284 B.setInstrAndDebugLoc(*
Select);
7285 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7286 B.buildZExtOrTrunc(Inner,
Cond);
7287 B.buildAdd(Dest, Inner,
False);
7293 if (TrueValue + 1 == FalseValue) {
7294 MatchInfo = [=](MachineIRBuilder &
B) {
7295 B.setInstrAndDebugLoc(*
Select);
7296 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7297 B.buildSExtOrTrunc(Inner,
Cond);
7298 B.buildAdd(Dest, Inner,
False);
7305 MatchInfo = [=](MachineIRBuilder &
B) {
7306 B.setInstrAndDebugLoc(*
Select);
7307 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7308 B.buildZExtOrTrunc(Inner,
Cond);
7311 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7312 B.buildShl(Dest, Inner, ShAmtC, Flags);
7319 MatchInfo = [=](MachineIRBuilder &
B) {
7320 B.setInstrAndDebugLoc(*
Select);
7322 B.buildNot(Not,
Cond);
7323 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7324 B.buildZExtOrTrunc(Inner, Not);
7327 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7328 B.buildShl(Dest, Inner, ShAmtC, Flags);
7335 MatchInfo = [=](MachineIRBuilder &
B) {
7336 B.setInstrAndDebugLoc(*
Select);
7337 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7338 B.buildSExtOrTrunc(Inner,
Cond);
7339 B.buildOr(Dest, Inner,
False, Flags);
7346 MatchInfo = [=](MachineIRBuilder &
B) {
7347 B.setInstrAndDebugLoc(*
Select);
7349 B.buildNot(Not,
Cond);
7350 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7351 B.buildSExtOrTrunc(Inner, Not);
7352 B.buildOr(Dest, Inner,
True, Flags);
7361bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7368 LLT CondTy =
MRI.getType(
Select->getCondReg());
7369 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7378 if (CondTy != TrueTy)
7384 MatchInfo = [=](MachineIRBuilder &
B) {
7385 B.setInstrAndDebugLoc(*
Select);
7386 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7387 B.buildZExtOrTrunc(Ext,
Cond);
7388 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7389 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7397 MatchInfo = [=](MachineIRBuilder &
B) {
7398 B.setInstrAndDebugLoc(*
Select);
7399 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7400 B.buildZExtOrTrunc(Ext,
Cond);
7401 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7402 B.buildAnd(DstReg, Ext, FreezeTrue);
7408 if (isOneOrOneSplat(
False,
true)) {
7409 MatchInfo = [=](MachineIRBuilder &
B) {
7410 B.setInstrAndDebugLoc(*
Select);
7412 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7413 B.buildNot(Inner,
Cond);
7415 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7416 B.buildZExtOrTrunc(Ext, Inner);
7417 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7418 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7424 if (isZeroOrZeroSplat(
True,
true)) {
7425 MatchInfo = [=](MachineIRBuilder &
B) {
7426 B.setInstrAndDebugLoc(*
Select);
7428 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7429 B.buildNot(Inner,
Cond);
7431 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7432 B.buildZExtOrTrunc(Ext, Inner);
7433 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7434 B.buildAnd(DstReg, Ext, FreezeFalse);
7456 LLT DstTy =
MRI.getType(DstReg);
7461 if (!
MRI.hasOneNonDBGUse(CondReg))
7470 if (
True == CmpRHS &&
False == CmpLHS) {
7518 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7519 Register DestReg =
MI.getOperand(0).getReg();
7520 LLT DestTy =
MRI.getType(DestReg);
7534 if (
isLegal({NewOpc, {DestTy}})) {
7536 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7548 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7551 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7561bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7563 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7564 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7568 unsigned Flags = Logic->
getFlags();
7581 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7587 std::optional<ValueAndVReg> MaybeC1 =
7591 C1 = MaybeC1->Value;
7593 std::optional<ValueAndVReg> MaybeC2 =
7597 C2 = MaybeC2->Value;
7604 LLT CmpOperandTy =
MRI.getType(R1);
7618 std::optional<APInt> Offset1;
7619 std::optional<APInt> Offset2;
7622 std::optional<ValueAndVReg> MaybeOffset1 =
7625 R1 =
Add->getLHSReg();
7626 Offset1 = MaybeOffset1->Value;
7630 std::optional<ValueAndVReg> MaybeOffset2 =
7633 R2 =
Add->getLHSReg();
7634 Offset2 = MaybeOffset2->Value;
7653 bool CreateMask =
false;
7666 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7679 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7688 MatchInfo = [=](MachineIRBuilder &
B) {
7689 if (CreateMask &&
Offset != 0) {
7690 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7691 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7692 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7693 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7694 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7695 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7696 B.buildZExtOrTrunc(DstReg, ICmp);
7697 }
else if (CreateMask &&
Offset == 0) {
7698 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7699 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7700 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7701 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7702 B.buildZExtOrTrunc(DstReg, ICmp);
7703 }
else if (!CreateMask &&
Offset != 0) {
7704 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7705 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7706 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7707 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7708 B.buildZExtOrTrunc(DstReg, ICmp);
7709 }
else if (!CreateMask &&
Offset == 0) {
7710 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7711 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7712 B.buildZExtOrTrunc(DstReg, ICmp);
7720bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7726 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7738 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7744 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7745 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7746 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7747 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7758 if (LHS0 == RHS1 && LHS1 == RHS0) {
7764 if (LHS0 == RHS0 && LHS1 == RHS1) {
7768 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7770 MatchInfo = [=](MachineIRBuilder &
B) {
7775 auto False =
B.buildConstant(CmpTy, 0);
7776 B.buildZExtOrTrunc(DestReg,
False);
7783 B.buildZExtOrTrunc(DestReg,
True);
7785 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7786 B.buildZExtOrTrunc(DestReg, Cmp);
7798 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7801 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7810 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7813 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7828 bool IsSigned =
Add->isSigned();
7829 LLT DstTy =
MRI.getType(Dst);
7830 LLT CarryTy =
MRI.getType(Carry);
7833 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7836 B.buildSAddo(Dst, Carry, RHS, LHS);
7842 B.buildUAddo(Dst, Carry, RHS, LHS);
7847 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7848 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7854 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7855 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7857 B.buildConstant(Dst, Result);
7858 B.buildConstant(Carry, Overflow);
7866 B.buildCopy(Dst, LHS);
7867 B.buildConstant(Carry, 0);
7876 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
7879 std::optional<APInt> MaybeAddRHS =
7880 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7883 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7884 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7888 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7889 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7895 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7896 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7921 B.buildConstant(Carry, 0);
7928 B.buildAdd(Dst, LHS, RHS);
7929 B.buildConstant(Carry, 1);
7941 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
7944 B.buildConstant(Carry, 0);
7960 B.buildConstant(Carry, 0);
7967 B.buildAdd(Dst, LHS, RHS);
7968 B.buildConstant(Carry, 1);
7986 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
7992 auto [Dst,
Base] =
MI.getFirst2Regs();
7993 LLT Ty =
MRI.getType(Dst);
7997 Builder.buildFConstant(Dst, 1.0);
7998 MI.removeFromParent();
8010 std::optional<SrcOp> Res;
8012 while (ExpVal > 0) {
8017 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8020 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8027 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8031 MI.eraseFromParent();
8042 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8049 LLT DstTy =
MRI.getType(Dst);
8052 auto Const =
B.buildConstant(DstTy,
C1 - C2);
8053 B.buildAdd(Dst,
A, Const);
8067 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8074 LLT DstTy =
MRI.getType(Dst);
8077 auto Const =
B.buildConstant(DstTy, C2 -
C1);
8078 B.buildSub(Dst, Const,
A);
8099 LLT DstTy =
MRI.getType(Dst);
8102 auto Const =
B.buildConstant(DstTy,
C1 + C2);
8103 B.buildSub(Dst,
A, Const);
8124 LLT DstTy =
MRI.getType(Dst);
8127 auto Const =
B.buildConstant(DstTy,
C1 - C2);
8128 B.buildSub(Dst, Const,
A);
8142 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8149 LLT DstTy =
MRI.getType(Dst);
8152 auto Const =
B.buildConstant(DstTy, C2 -
C1);
8153 B.buildAdd(Dst,
A, Const);
8197 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8205 LLT SmallBvTy = DstTy;
8209 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8214 {TargetOpcode::G_ANYEXT,
8226 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8227 Ops.push_back(AnyExt.getReg(0));
8245 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8246 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8247 const unsigned NumDstElts = OrigMask.
size();
8248 for (
unsigned i = 0; i != NumDstElts; ++i) {
8249 int Idx = OrigMask[i];
8250 if (Idx >= (
int)NumSrcElems) {
8261 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8262 std::move(NewMask));
8269 const unsigned MaskSize = Mask.size();
8270 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8275 if (Idx < (
int)NumElems)
8276 Mask[
I] = Idx + NumElems;
8278 Mask[
I] = Idx - NumElems;
8288 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8291 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8294 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8295 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8297 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8301 const unsigned NumSrcElems = Src1Ty.getNumElements();
8303 bool TouchesSrc1 =
false;
8304 bool TouchesSrc2 =
false;
8305 const unsigned NumElems = Mask.size();
8306 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8310 if (Mask[Idx] < (
int)NumSrcElems)
8316 if (TouchesSrc1 == TouchesSrc2)
8319 Register NewSrc1 = Shuffle.getSrc1Reg();
8322 NewSrc1 = Shuffle.getSrc2Reg();
8327 auto Undef =
B.buildUndef(Src1Ty);
8328 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8342 LLT DstTy =
MRI.getType(Dst);
8343 LLT CarryTy =
MRI.getType(Carry);
8365 B.buildConstant(Carry, 0);
8372 B.buildSub(Dst, LHS, RHS);
8390 B.buildConstant(Carry, 0);
8397 B.buildSub(Dst, LHS, RHS);
8414 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8415 "Expected G_CTLZ variant");
8420 LLT Ty =
MRI.getType(Dst);
8421 LLT SrcTy =
MRI.getType(Src);
8423 if (!(Ty.isValid() && Ty.isScalar()))
8432 switch (
LI->getAction(Query).Action) {
8443 bool NeedAdd =
true;
8451 unsigned BitWidth = Ty.getScalarSizeInBits();
8462 B.buildCTLS(Dst,
X);
8466 auto Ctls =
B.buildCTLS(Ty,
X);
8467 auto One =
B.buildConstant(Ty, 1);
8469 B.buildAdd(Dst, Ctls, One);
8477 return C &&
C->getValueAPF().isNaN();
8481 unsigned ZeroPoisonOpc)
const {
8482 const bool IsCtlzPair =
Opc == TargetOpcode::G_CTLZ &&
8483 ZeroPoisonOpc == TargetOpcode::G_CTLZ_ZERO_POISON;
8484 const bool IsCttzPair =
Opc == TargetOpcode::G_CTTZ &&
8485 ZeroPoisonOpc == TargetOpcode::G_CTTZ_ZERO_POISON;
8486 if (
MI.getOpcode() !=
Opc || (!IsCtlzPair && !IsCttzPair))
8492 if (!
VT->isKnownNeverZero(Src))
8495 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8496 LLT SrcTy =
MRI.getType(Src);
8502 assert((Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) &&
8503 "Expected G_AND or G_OR");
8505 ~(Opcode == TargetOpcode::G_AND ? OtherKnown.
Zero : OtherKnown.
One);
8508static std::optional<unsigned>
8510 if (!Amt || Amt->uge(BW))
8511 return std::nullopt;
8512 return Amt->getZExtValue();
8519 "shift amount must be less than the bit width");
8521 case TargetOpcode::G_SHL:
8523 case TargetOpcode::G_LSHR:
8525 case TargetOpcode::G_ASHR: {
8536Register CombinerHelper::simplifyMultipleUseDemandedBits(
8538 assert(
R.isVirtual() &&
"Expected a virtual register");
8539 assert(!DemandedBits.
isZero() &&
"Zero demand is handled by the caller");
8543 [[maybe_unused]] LLT Ty =
MRI.getType(R);
8546 "DemandedBits width must match the register scalar type");
8548 MachineInstr *
DefMI =
MRI.getVRegDef(R);
8549 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8558 "Logical operands must match the result type");
8561 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8564 bool BypassToX = Opcode == TargetOpcode::G_AND
8569 simplifyMultipleUseDemandedBits(
X, DemandedBits,
Depth + 1))
8573 bool BypassToC = Opcode == TargetOpcode::G_AND
8583 return LookThrough(
RHS,
LHS);
8586bool CombinerHelper::simplifyDemandedBitsImpl(
MachineInstr &
MI,
unsigned OpNo,
8589 bool DoRewrite)
const {
8591 assert(
MI.getOperand(OpNo).isReg() && !
MI.getOperand(OpNo).isDef() &&
8592 "Expected a register use");
8593 Register OpReg =
MI.getOperand(OpNo).getReg();
8595 LLT OpTy =
MRI.getType(OpReg);
8598 "DemandedBits width must match the operand scalar type");
8600 MachineInstr *
DefMI =
MRI.getVRegDef(OpReg);
8601 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8603 auto DropPoisonFlags = [&]() {
8612 auto InvalidateDebugUses = [&](
const APInt &Demanded) {
8613 if (DoRewrite && !Demanded.isAllOnes())
8614 MRI.markUsesInDebugValueAsUndef(OpReg);
8616 auto Rewrite = [&](
Register Repl) {
8617 if (!DoRewrite || Repl == OpReg)
8618 return Repl != OpReg;
8621 InvalidateDebugUses(DemandedBits);
8630 if (DemandedBits.
isZero()) {
8635 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8640 Builder.setInsertPt(SaveMBB, SavePt);
8652 auto GiveUp = [&]() {
8665 APInt Demanded = DemandedBits;
8666 if (!
MRI.hasOneNonDBGUse(OpReg) && !Demanded.
isAllOnes()) {
8668 simplifyMultipleUseDemandedBits(OpReg, Demanded,
Depth)) {
8669 Known =
VT->getKnownBits(Repl);
8678 case TargetOpcode::G_AND:
8679 case TargetOpcode::G_OR: {
8684 "Logical operands must match the result type");
8685 auto SimplifyWithConst = [&](
Register X,
8686 Register CReg) -> std::optional<Register> {
8687 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8689 return std::nullopt;
8690 assert(
C->getBitWidth() == BW &&
"Constant width must match its type");
8692 if (Opcode == TargetOpcode::G_AND) {
8697 return std::nullopt;
8703 return std::nullopt;
8707 if (std::optional<Register> Repl = SimplifyWithConst(
LHS,
RHS)) {
8708 Known =
VT->getKnownBits(*Repl);
8712 if (std::optional<Register> Repl = SimplifyWithConst(
RHS,
LHS)) {
8713 Known =
VT->getKnownBits(*Repl);
8718 KnownBits RHSKnown(BW);
8719 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 2, Demanded,
8720 RHSKnown,
Depth + 1, DoRewrite);
8722 KnownBits LHSKnown(BW);
8723 Changed |= simplifyDemandedBitsImpl(*
DefMI, 1, LHSDemand, LHSKnown,
8724 Depth + 1, DoRewrite);
8726 !getConstantOrConstantSplatVector(
RHS)) {
8729 LHSDemand == Demanded
8735 OpTy.isFixedVector()
8739 if (RHSDemand != Demanded) {
8741 KnownBits RetryKnown(BW);
8742 Changed = simplifyDemandedBitsImpl(*
DefMI, 2, RHSDemand,
8743 RetryKnown,
Depth + 1, DoRewrite);
8748 InvalidateDebugUses(Demanded);
8750 Known = Opcode == TargetOpcode::G_AND ? LHSKnown & RHSKnown
8751 : LHSKnown | RHSKnown;
8754 case TargetOpcode::G_SHL:
8755 case TargetOpcode::G_LSHR:
8756 case TargetOpcode::G_ASHR: {
8763 KnownBits SrcKnown(BW);
8764 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 1, SrcDemand,
8765 SrcKnown,
Depth + 1, DoRewrite);
8768 InvalidateDebugUses(Demanded);
8772 case TargetOpcode::G_SHL:
8775 case TargetOpcode::G_LSHR:
8778 case TargetOpcode::G_ASHR: {
8782 isLegal({TargetOpcode::G_LSHR, {OpTy, AmtTy}});
8784 SrcKnown.isNonNegative()) &&
8787 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8793 Builder.setInsertPt(SaveMBB, SavePt);
8795 Rewrite(Lshr.getReg(0));
8814 unsigned Depth)
const {
8822 LLT Ty =
MRI.getType(Dst);
8823 assert(Ty.isValid() &&
"Expected a typed generic result");
8824 if (!
VT || Ty.isVector())
8829 if (!simplifyDemandedBitsImpl(
MI, OpNo, OpDemand,
Known, 0,
8840 unsigned Opcode =
MI.getOpcode();
8842 case TargetOpcode::G_SHL:
8843 case TargetOpcode::G_LSHR:
8844 case TargetOpcode::G_ASHR: {
8846 getConstantOrConstantSplatVector(
MI.getOperand(2).getReg()),
8853 return Probe(1, SrcDemand, SrcKnown);
8857 case TargetOpcode::G_AND:
8858 case TargetOpcode::G_OR: {
8863 bool RootRedundant = Opcode == TargetOpcode::G_AND
8872 if (Probe(2, RootDemand, RHSKnown))
8878 if (Probe(1, LHSDemand, LHSKnown))
8882 if (!
MRI.hasOneNonDBGUse(RHS) || getConstantOrConstantSplatVector(RHS))
8886 LHSDemand == RootDemand
8890 VT->getKnownBits(
MI.getOperand(1).getReg()));
8892 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 std::optional< unsigned > getValidConstShiftAmt(const std::optional< APInt > &Amt, unsigned BW)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static APInt getDemandedSrcBitsForShiftConst(unsigned Opcode, const APInt &DemandedBits, unsigned ShAmt)
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
MachineBasicBlock * Folded
SmallVector< MachineOperand, 4 > Cond
MachineRegisterInfo & MRI
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.
unsigned countLeadingZeros() const
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 shuffle 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 void applyCombineShuffleOfBuildVector(MachineInstr &MI) const
Replace shuffle of build_vector with a build_vector.
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)
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,...
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.
static KnownBits makeConstant(const APInt &C)
Create known bits from a known constant.
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.
static LLVM_ABI KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS, bool ShAmtNonZero=false, bool Exact=false)
Compute known bits for ashr(LHS, RHS).
bool isUnknown() const
Returns true if we don't know any bits.
unsigned getBitWidth() const
Get the bit width of this value.
static LLVM_ABI KnownBits lshr(const KnownBits &LHS, const KnownBits &RHS, bool ShAmtNonZero=false, bool Exact=false)
Compute known bits for lshr(LHS, RHS).
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
bool isNegative() const
Returns true if this value is known to be negative.
static LLVM_ABI KnownBits shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW=false, bool NSW=false, bool ShAmtNonZero=false)
Compute known bits for shl(LHS, RHS).
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...