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();
5909 return CI && CI->getValue().isPowerOf2();
5913 LLT Ty =
MRI.getType(Dst);
5914 LLT ShiftTy =
MRI.getType(Shift);
5927 auto Amount =
B.buildAdd(ShiftTy, Shift,
Log2);
5928 B.buildLShr(Dst, LHS, Amount, Flags);
5938 if (!
VT || !
VT->signBitIsZero(LHS) || !
VT->signBitIsZero(RHS))
5941 LLT Ty =
MRI.getType(Dst);
5946 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
5951 LLT Ty =
MRI.getType(Dst);
5970 unsigned BitWidth = Ty.getScalarSizeInBits();
5971 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
5972 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
5974 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
5975 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
5976 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
5979 MI.eraseFromParent();
5983 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5986 LLT Ty =
MRI.getType(Dst);
5987 LLT RHSTy =
MRI.getType(RHS);
5989 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
5991 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6006 LLT Ty =
MRI.getType(Dst);
6012 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6013 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6014 Builder.buildLShr(Dst, LHS, Trunc);
6015 MI.eraseFromParent();
6022 LLT DstTy =
MRI.getType(Dst);
6023 LLT SrcTy =
MRI.getType(Src);
6025 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6026 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6029 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6058 Builder.buildTruncSSatS(Dst, MatchInfo);
6059 MI.eraseFromParent();
6066 LLT DstTy =
MRI.getType(Dst);
6067 LLT SrcTy =
MRI.getType(Src);
6069 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6070 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6073 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6091 Builder.buildTruncSSatU(Dst, MatchInfo);
6092 MI.eraseFromParent();
6099 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6100 LLT SrcTy =
MRI.getType(Val);
6102 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6103 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6106 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6115 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6123 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6126 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6128 const auto LHSCst = Ty.isVector()
6142 if (LHSCst->Value.isNegZero())
6146 if (LHSCst->Value.isPosZero())
6155 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6163 MRI.use_instr_nodbg_end()) >
6165 MRI.use_instr_nodbg_end());
6169 bool &AllowFusionGlobally,
6171 bool CanReassociate)
const {
6173 auto *MF =
MI.getMF();
6174 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6175 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6183 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6186 if (!HasFMAD && !HasFMA)
6191 AllowFusionGlobally = HasFMAD;
6196 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6203 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6205 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6217 unsigned PreferredFusedOpcode =
6218 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6231 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6233 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6234 {LHS.MI->getOperand(1).getReg(),
6235 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6244 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6246 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6247 {RHS.MI->getOperand(1).getReg(),
6248 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6260 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6262 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6266 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6275 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6277 unsigned PreferredFusedOpcode =
6278 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6281 bool LHSContractable =
6284 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6287 bool RHSContractable =
6290 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6294 if (LHSContractable || RHSContractable) {
6297 if (!LHSContractable ||
6298 (RHSContractable &&
hasMoreUses(*LHSFpExtSrc, *RHSFpExtSrc,
MRI))) {
6300 LHSFpExtSrc = RHSFpExtSrc;
6303 unsigned Flags =
MI.getFlags() & LHSFpExtSrc->
getFlags();
6307 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6308 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6319 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6321 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6333 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6335 unsigned PreferredFusedOpcode =
6336 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6341 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6344 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6345 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6350 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6353 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6354 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6363 Register X = FMA->getOperand(1).getReg();
6364 Register Y = FMA->getOperand(2).getReg();
6367 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6368 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6371 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6372 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6373 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6374 {
X,
Y, InnerFMA}, OuterFlags);
6385 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6387 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6394 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6395 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6405 unsigned PreferredFusedOpcode =
6406 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6420 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6421 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6422 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6423 {FpExtU, FpExtV, Z}, InnerFlags)
6425 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6426 {
X,
Y, InnerFMA}, OuterFlags);
6432 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6436 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6438 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6439 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6443 LHS.MI->getOperand(1).getReg(),
6444 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6455 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6460 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6462 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6463 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6467 X =
B.buildFPExt(DstType,
X).getReg(0);
6468 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6471 InnerFlags, OuterFlags,
B);
6480 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6484 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6486 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6487 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6491 RHS.MI->getOperand(1).getReg(),
6492 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6503 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6508 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6510 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6511 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6515 X =
B.buildFPExt(DstType,
X).getReg(0);
6516 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6519 InnerFlags, OuterFlags,
B);
6531 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6533 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6545 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6549 int FirstMulHasFewerUses =
true;
6553 FirstMulHasFewerUses =
false;
6555 unsigned PreferredFusedOpcode =
6556 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6559 if (FirstMulHasFewerUses &&
6562 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6564 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6565 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6566 {LHS.MI->getOperand(1).getReg(),
6567 LHS.MI->getOperand(2).getReg(), NegZ},
6575 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6578 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6579 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6580 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6591 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6593 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6599 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6601 unsigned PreferredFusedOpcode =
6602 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6610 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6614 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6615 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6626 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6628 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6642 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6644 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6650 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6652 unsigned PreferredFusedOpcode =
6653 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6660 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6666 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6667 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6668 {FpExtX, FpExtY, NegZ}, Flags);
6677 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6681 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6684 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6685 {NegY, FpExtZ, LHSReg}, Flags);
6696 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6698 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6702 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6703 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6707 unsigned PreferredFusedOpcode =
6708 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6712 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6713 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6714 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
6725 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6727 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6729 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6732 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6742 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6744 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6760 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6770 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
6787 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6788 if (&U == &
MI || U.getParent() !=
MI.getParent())
6790 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6791 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
6792 !IsOne(U.getOperand(1).getReg())) {
6805 return MatchInfo.
size() >= MinUses;
6813 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6814 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6815 MatchInfo[0]->getOperand(2).getReg(),
6816 MatchInfo[0]->getFlags());
6821 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6822 Div->getOperand(0).getReg(),
MI->getFlags());
6823 MI->eraseFromParent();
6845 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6854 return MRI.getType(MatchInfo) == DstVecTy;
6857 std::optional<ValueAndVReg> ShiftAmount;
6866 return MRI.getType(MatchInfo) == DstVecTy;
6881 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6888 std::optional<ValueAndVReg> ShiftAmt;
6894 LLT MatchTy =
MRI.getType(MatchInfo);
6895 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6896 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6899unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6901 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6902 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6903 "Expected a NaN behaviour?");
6913 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6914 return TargetOpcode::G_FMAXNUM;
6915 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6916 return TargetOpcode::G_FMAXIMUM;
6917 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6918 return TargetOpcode::G_FMAXNUM;
6919 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6920 return TargetOpcode::G_FMAXIMUM;
6926 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6927 return TargetOpcode::G_FMINNUM;
6928 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6929 return TargetOpcode::G_FMINIMUM;
6930 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6931 return TargetOpcode::G_FMINNUM;
6932 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6934 return TargetOpcode::G_FMINIMUM;
6938CombinerHelper::SelectPatternNaNBehaviour
6940 bool IsOrderedComparison)
const {
6941 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
6942 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
6944 if (!LHSSafe && !RHSSafe)
6945 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6946 if (LHSSafe && RHSSafe)
6947 return SelectPatternNaNBehaviour::RETURNS_ANY;
6950 if (IsOrderedComparison)
6951 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6952 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6955 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6956 : SelectPatternNaNBehaviour::RETURNS_NAN;
6965 LLT DstTy =
MRI.getType(Dst);
6978 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
6980 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
6982 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
6985 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
6986 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
6987 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
6988 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
6990 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
6993 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
6998 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7003 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7005 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7009 MatchInfo = [=](MachineIRBuilder &
B) {
7010 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7018 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7025 Register TrueVal =
MI.getOperand(2).getReg();
7026 Register FalseVal =
MI.getOperand(3).getReg();
7027 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7032 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7045 if (MatchedSub &&
X != OpLHS)
7053 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7056 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7057 B.buildICmp(Pred, Dst,
Y, Zero);
7064static std::optional<unsigned>
7066 std::optional<int64_t> &Result) {
7067 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7068 Opcode == TargetOpcode::G_ASHR) &&
7069 "Expect G_SHL, G_LSHR or G_ASHR.");
7070 auto SignificantBits = 0;
7072 case TargetOpcode::G_SHL:
7076 case TargetOpcode::G_LSHR:
7080 case TargetOpcode::G_ASHR:
7089 Result = std::nullopt;
7100 Register ShiftVal =
MI.getOperand(1).getReg();
7101 Register ShiftReg =
MI.getOperand(2).getReg();
7102 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7103 auto IsShiftTooBig = [&](
const Constant *
C) {
7108 MatchInfo = std::nullopt;
7112 MI.getOpcode(), MatchInfo);
7113 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7119 unsigned LHSOpndIdx = 1;
7120 unsigned RHSOpndIdx = 2;
7121 switch (
MI.getOpcode()) {
7122 case TargetOpcode::G_UADDO:
7123 case TargetOpcode::G_SADDO:
7124 case TargetOpcode::G_UMULO:
7125 case TargetOpcode::G_SMULO:
7132 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7133 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7143 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7147 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7154 std::optional<FPValueAndVReg> ValAndVReg;
7160bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7161 LLT SrcTy =
MRI.getType(Src);
7162 if (SrcTy.isFixedVector())
7164 if (SrcTy.isScalar()) {
7168 return IConstant && IConstant->Value == 1;
7173bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7174 LLT SrcTy =
MRI.getType(Src);
7176 return isConstantSplatVector(Src, 0, AllowUndefs);
7181 return IConstant && IConstant->Value == 0;
7188bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7189 bool AllowUndefs)
const {
7195 for (
unsigned I = 0;
I < NumSources; ++
I) {
7196 GImplicitDef *ImplicitDef =
7198 if (ImplicitDef && AllowUndefs)
7200 if (ImplicitDef && !AllowUndefs)
7202 std::optional<ValueAndVReg> IConstant =
7204 if (IConstant && IConstant->Value == SplatValue)
7214CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7217 return IConstant->Value;
7221 return std::nullopt;
7224 std::optional<APInt>
Value = std::nullopt;
7225 for (
unsigned I = 0;
I < NumSources; ++
I) {
7226 std::optional<ValueAndVReg> IConstant =
7229 return std::nullopt;
7231 Value = IConstant->Value;
7232 else if (*
Value != IConstant->Value)
7233 return std::nullopt;
7239bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7249 for (
unsigned I = 0;
I < NumSources; ++
I) {
7250 std::optional<ValueAndVReg> IConstant =
7259bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7266 LLT CondTy =
MRI.getType(
Select->getCondReg());
7267 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7277 std::optional<ValueAndVReg> TrueOpt =
7279 std::optional<ValueAndVReg> FalseOpt =
7282 if (!TrueOpt || !FalseOpt)
7285 APInt TrueValue = TrueOpt->Value;
7286 APInt FalseValue = FalseOpt->Value;
7290 MatchInfo = [=](MachineIRBuilder &
B) {
7291 B.setInstrAndDebugLoc(*
Select);
7292 B.buildZExtOrTrunc(Dest,
Cond);
7299 MatchInfo = [=](MachineIRBuilder &
B) {
7300 B.setInstrAndDebugLoc(*
Select);
7301 B.buildSExtOrTrunc(Dest,
Cond);
7308 MatchInfo = [=](MachineIRBuilder &
B) {
7309 B.setInstrAndDebugLoc(*
Select);
7310 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7311 B.buildNot(Inner,
Cond);
7312 B.buildZExtOrTrunc(Dest, Inner);
7319 MatchInfo = [=](MachineIRBuilder &
B) {
7320 B.setInstrAndDebugLoc(*
Select);
7321 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7322 B.buildNot(Inner,
Cond);
7323 B.buildSExtOrTrunc(Dest, Inner);
7329 if (TrueValue - 1 == FalseValue) {
7330 MatchInfo = [=](MachineIRBuilder &
B) {
7331 B.setInstrAndDebugLoc(*
Select);
7332 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7333 B.buildZExtOrTrunc(Inner,
Cond);
7334 B.buildAdd(Dest, Inner,
False);
7340 if (TrueValue + 1 == FalseValue) {
7341 MatchInfo = [=](MachineIRBuilder &
B) {
7342 B.setInstrAndDebugLoc(*
Select);
7343 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7344 B.buildSExtOrTrunc(Inner,
Cond);
7345 B.buildAdd(Dest, Inner,
False);
7352 MatchInfo = [=](MachineIRBuilder &
B) {
7353 B.setInstrAndDebugLoc(*
Select);
7354 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7355 B.buildZExtOrTrunc(Inner,
Cond);
7358 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7359 B.buildShl(Dest, Inner, ShAmtC, Flags);
7366 MatchInfo = [=](MachineIRBuilder &
B) {
7367 B.setInstrAndDebugLoc(*
Select);
7369 B.buildNot(Not,
Cond);
7370 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7371 B.buildZExtOrTrunc(Inner, Not);
7374 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7375 B.buildShl(Dest, Inner, ShAmtC, Flags);
7382 MatchInfo = [=](MachineIRBuilder &
B) {
7383 B.setInstrAndDebugLoc(*
Select);
7384 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7385 B.buildSExtOrTrunc(Inner,
Cond);
7386 B.buildOr(Dest, Inner,
False, Flags);
7393 MatchInfo = [=](MachineIRBuilder &
B) {
7394 B.setInstrAndDebugLoc(*
Select);
7396 B.buildNot(Not,
Cond);
7397 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7398 B.buildSExtOrTrunc(Inner, Not);
7399 B.buildOr(Dest, Inner,
True, Flags);
7408bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7415 LLT CondTy =
MRI.getType(
Select->getCondReg());
7416 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7425 if (CondTy != TrueTy)
7431 MatchInfo = [=](MachineIRBuilder &
B) {
7432 B.setInstrAndDebugLoc(*
Select);
7433 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7434 B.buildZExtOrTrunc(Ext,
Cond);
7435 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7436 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7444 MatchInfo = [=](MachineIRBuilder &
B) {
7445 B.setInstrAndDebugLoc(*
Select);
7446 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7447 B.buildZExtOrTrunc(Ext,
Cond);
7448 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7449 B.buildAnd(DstReg, Ext, FreezeTrue);
7455 if (isOneOrOneSplat(
False,
true)) {
7456 MatchInfo = [=](MachineIRBuilder &
B) {
7457 B.setInstrAndDebugLoc(*
Select);
7459 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7460 B.buildNot(Inner,
Cond);
7462 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7463 B.buildZExtOrTrunc(Ext, Inner);
7464 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7465 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7471 if (isZeroOrZeroSplat(
True,
true)) {
7472 MatchInfo = [=](MachineIRBuilder &
B) {
7473 B.setInstrAndDebugLoc(*
Select);
7475 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7476 B.buildNot(Inner,
Cond);
7478 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7479 B.buildZExtOrTrunc(Ext, Inner);
7480 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7481 B.buildAnd(DstReg, Ext, FreezeFalse);
7503 LLT DstTy =
MRI.getType(DstReg);
7508 if (!
MRI.hasOneNonDBGUse(CondReg))
7517 if (
True == CmpRHS &&
False == CmpLHS) {
7565 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7566 Register DestReg =
MI.getOperand(0).getReg();
7567 LLT DestTy =
MRI.getType(DestReg);
7581 if (
isLegal({NewOpc, {DestTy}})) {
7583 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7595 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7598 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7608bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7610 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7611 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7615 unsigned Flags = Logic->
getFlags();
7628 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7634 std::optional<ValueAndVReg> MaybeC1 =
7638 C1 = MaybeC1->Value;
7640 std::optional<ValueAndVReg> MaybeC2 =
7644 C2 = MaybeC2->Value;
7651 LLT CmpOperandTy =
MRI.getType(R1);
7665 std::optional<APInt> Offset1;
7666 std::optional<APInt> Offset2;
7669 std::optional<ValueAndVReg> MaybeOffset1 =
7672 R1 =
Add->getLHSReg();
7673 Offset1 = MaybeOffset1->Value;
7677 std::optional<ValueAndVReg> MaybeOffset2 =
7680 R2 =
Add->getLHSReg();
7681 Offset2 = MaybeOffset2->Value;
7700 bool CreateMask =
false;
7713 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7726 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7735 MatchInfo = [=](MachineIRBuilder &
B) {
7736 if (CreateMask &&
Offset != 0) {
7737 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7738 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7739 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7740 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7741 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7742 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7743 B.buildZExtOrTrunc(DstReg, ICmp);
7744 }
else if (CreateMask &&
Offset == 0) {
7745 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7746 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7747 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7748 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7749 B.buildZExtOrTrunc(DstReg, ICmp);
7750 }
else if (!CreateMask &&
Offset != 0) {
7751 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7752 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7753 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7754 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7755 B.buildZExtOrTrunc(DstReg, ICmp);
7756 }
else if (!CreateMask &&
Offset == 0) {
7757 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7758 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7759 B.buildZExtOrTrunc(DstReg, ICmp);
7767bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7773 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7785 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7791 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7792 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7793 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7794 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7805 if (LHS0 == RHS1 && LHS1 == RHS0) {
7811 if (LHS0 == RHS0 && LHS1 == RHS1) {
7815 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7817 MatchInfo = [=](MachineIRBuilder &
B) {
7822 auto False =
B.buildConstant(CmpTy, 0);
7823 B.buildZExtOrTrunc(DestReg,
False);
7830 B.buildZExtOrTrunc(DestReg,
True);
7832 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7833 B.buildZExtOrTrunc(DestReg, Cmp);
7845 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7848 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7857 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7860 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7875 bool IsSigned =
Add->isSigned();
7876 LLT DstTy =
MRI.getType(Dst);
7877 LLT CarryTy =
MRI.getType(Carry);
7880 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7883 B.buildSAddo(Dst, Carry, RHS, LHS);
7889 B.buildUAddo(Dst, Carry, RHS, LHS);
7894 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7895 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7901 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7902 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7904 B.buildConstant(Dst, Result);
7905 B.buildConstant(Carry, Overflow);
7913 B.buildCopy(Dst, LHS);
7914 B.buildConstant(Carry, 0);
7923 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
7926 std::optional<APInt> MaybeAddRHS =
7927 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7930 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7931 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
7935 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7936 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7942 auto ConstRHS =
B.buildConstant(DstTy, NewC);
7943 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
7968 B.buildConstant(Carry, 0);
7975 B.buildAdd(Dst, LHS, RHS);
7976 B.buildConstant(Carry, 1);
7988 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
7991 B.buildConstant(Carry, 0);
8007 B.buildConstant(Carry, 0);
8014 B.buildAdd(Dst, LHS, RHS);
8015 B.buildConstant(Carry, 1);
8033 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8039 auto [Dst,
Base] =
MI.getFirst2Regs();
8040 LLT Ty =
MRI.getType(Dst);
8044 Builder.buildFConstant(Dst, 1.0);
8045 MI.removeFromParent();
8057 std::optional<SrcOp> Res;
8059 while (ExpVal > 0) {
8064 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8067 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8074 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8078 MI.eraseFromParent();
8089 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8096 LLT DstTy =
MRI.getType(Dst);
8099 auto Const =
B.buildConstant(DstTy,
C1 - C2);
8100 B.buildAdd(Dst,
A, Const);
8114 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8121 LLT DstTy =
MRI.getType(Dst);
8124 auto Const =
B.buildConstant(DstTy, C2 -
C1);
8125 B.buildSub(Dst, Const,
A);
8146 LLT DstTy =
MRI.getType(Dst);
8149 auto Const =
B.buildConstant(DstTy,
C1 + C2);
8150 B.buildSub(Dst,
A, Const);
8171 LLT DstTy =
MRI.getType(Dst);
8174 auto Const =
B.buildConstant(DstTy,
C1 - C2);
8175 B.buildSub(Dst, Const,
A);
8189 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8196 LLT DstTy =
MRI.getType(Dst);
8199 auto Const =
B.buildConstant(DstTy, C2 -
C1);
8200 B.buildAdd(Dst,
A, Const);
8244 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8252 LLT SmallBvTy = DstTy;
8256 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8261 {TargetOpcode::G_ANYEXT,
8273 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8274 Ops.push_back(AnyExt.getReg(0));
8292 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8293 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8294 const unsigned NumDstElts = OrigMask.
size();
8295 for (
unsigned i = 0; i != NumDstElts; ++i) {
8296 int Idx = OrigMask[i];
8297 if (Idx >= (
int)NumSrcElems) {
8308 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8309 std::move(NewMask));
8316 const unsigned MaskSize = Mask.size();
8317 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8322 if (Idx < (
int)NumElems)
8323 Mask[
I] = Idx + NumElems;
8325 Mask[
I] = Idx - NumElems;
8335 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8338 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8341 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8342 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8344 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8348 const unsigned NumSrcElems = Src1Ty.getNumElements();
8350 bool TouchesSrc1 =
false;
8351 bool TouchesSrc2 =
false;
8352 const unsigned NumElems = Mask.size();
8353 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8357 if (Mask[Idx] < (
int)NumSrcElems)
8363 if (TouchesSrc1 == TouchesSrc2)
8366 Register NewSrc1 = Shuffle.getSrc1Reg();
8369 NewSrc1 = Shuffle.getSrc2Reg();
8374 auto Undef =
B.buildUndef(Src1Ty);
8375 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8389 LLT DstTy =
MRI.getType(Dst);
8390 LLT CarryTy =
MRI.getType(Carry);
8412 B.buildConstant(Carry, 0);
8419 B.buildSub(Dst, LHS, RHS);
8437 B.buildConstant(Carry, 0);
8444 B.buildSub(Dst, LHS, RHS);
8461 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8462 "Expected G_CTLZ variant");
8467 LLT Ty =
MRI.getType(Dst);
8468 LLT SrcTy =
MRI.getType(Src);
8470 if (!(Ty.isValid() && Ty.isScalar()))
8479 switch (
LI->getAction(Query).Action) {
8490 bool NeedAdd =
true;
8498 unsigned BitWidth = Ty.getScalarSizeInBits();
8509 B.buildCTLS(Dst,
X);
8513 auto Ctls =
B.buildCTLS(Ty,
X);
8514 auto One =
B.buildConstant(Ty, 1);
8516 B.buildAdd(Dst, Ctls, One);
8524 return C &&
C->getValueAPF().isNaN();
8528 unsigned ZeroPoisonOpc)
const {
8529 const bool IsCtlzPair =
Opc == TargetOpcode::G_CTLZ &&
8530 ZeroPoisonOpc == TargetOpcode::G_CTLZ_ZERO_POISON;
8531 const bool IsCttzPair =
Opc == TargetOpcode::G_CTTZ &&
8532 ZeroPoisonOpc == TargetOpcode::G_CTTZ_ZERO_POISON;
8533 if (
MI.getOpcode() !=
Opc || (!IsCtlzPair && !IsCttzPair))
8539 if (!
VT->isKnownNeverZero(Src))
8542 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8543 LLT SrcTy =
MRI.getType(Src);
8549 assert((Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) &&
8550 "Expected G_AND or G_OR");
8552 ~(Opcode == TargetOpcode::G_AND ? OtherKnown.
Zero : OtherKnown.
One);
8555static std::optional<unsigned>
8557 if (!Amt || Amt->uge(BW))
8558 return std::nullopt;
8559 return Amt->getZExtValue();
8566 "shift amount must be less than the bit width");
8568 case TargetOpcode::G_SHL:
8570 case TargetOpcode::G_LSHR:
8572 case TargetOpcode::G_ASHR: {
8583Register CombinerHelper::simplifyMultipleUseDemandedBits(
8585 assert(
R.isVirtual() &&
"Expected a virtual register");
8586 assert(!DemandedBits.
isZero() &&
"Zero demand is handled by the caller");
8590 [[maybe_unused]] LLT Ty =
MRI.getType(R);
8593 "DemandedBits width must match the register scalar type");
8595 MachineInstr *
DefMI =
MRI.getVRegDef(R);
8596 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8605 "Logical operands must match the result type");
8608 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8611 bool BypassToX = Opcode == TargetOpcode::G_AND
8616 simplifyMultipleUseDemandedBits(
X, DemandedBits,
Depth + 1))
8620 bool BypassToC = Opcode == TargetOpcode::G_AND
8630 return LookThrough(
RHS,
LHS);
8633bool CombinerHelper::simplifyDemandedBitsImpl(
MachineInstr &
MI,
unsigned OpNo,
8636 bool DoRewrite)
const {
8638 assert(
MI.getOperand(OpNo).isReg() && !
MI.getOperand(OpNo).isDef() &&
8639 "Expected a register use");
8640 Register OpReg =
MI.getOperand(OpNo).getReg();
8642 LLT OpTy =
MRI.getType(OpReg);
8645 "DemandedBits width must match the operand scalar type");
8647 MachineInstr *
DefMI =
MRI.getVRegDef(OpReg);
8648 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8650 auto DropPoisonFlags = [&]() {
8659 auto InvalidateDebugUses = [&](
const APInt &Demanded) {
8660 if (DoRewrite && !Demanded.isAllOnes())
8661 MRI.markUsesInDebugValueAsUndef(OpReg);
8663 auto Rewrite = [&](
Register Repl) {
8664 if (!DoRewrite || Repl == OpReg)
8665 return Repl != OpReg;
8668 InvalidateDebugUses(DemandedBits);
8677 if (DemandedBits.
isZero()) {
8682 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8687 Builder.setInsertPt(SaveMBB, SavePt);
8699 auto GiveUp = [&]() {
8712 APInt Demanded = DemandedBits;
8713 if (!
MRI.hasOneNonDBGUse(OpReg) && !Demanded.
isAllOnes()) {
8715 simplifyMultipleUseDemandedBits(OpReg, Demanded,
Depth)) {
8716 Known =
VT->getKnownBits(Repl);
8725 case TargetOpcode::G_AND:
8726 case TargetOpcode::G_OR: {
8731 "Logical operands must match the result type");
8732 auto SimplifyWithConst = [&](
Register X,
8733 Register CReg) -> std::optional<Register> {
8734 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8736 return std::nullopt;
8737 assert(
C->getBitWidth() == BW &&
"Constant width must match its type");
8739 if (Opcode == TargetOpcode::G_AND) {
8744 return std::nullopt;
8750 return std::nullopt;
8754 if (std::optional<Register> Repl = SimplifyWithConst(
LHS,
RHS)) {
8755 Known =
VT->getKnownBits(*Repl);
8759 if (std::optional<Register> Repl = SimplifyWithConst(
RHS,
LHS)) {
8760 Known =
VT->getKnownBits(*Repl);
8765 KnownBits RHSKnown(BW);
8766 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 2, Demanded,
8767 RHSKnown,
Depth + 1, DoRewrite);
8769 KnownBits LHSKnown(BW);
8770 Changed |= simplifyDemandedBitsImpl(*
DefMI, 1, LHSDemand, LHSKnown,
8771 Depth + 1, DoRewrite);
8773 !getConstantOrConstantSplatVector(
RHS)) {
8776 LHSDemand == Demanded
8782 OpTy.isFixedVector()
8786 if (RHSDemand != Demanded) {
8788 KnownBits RetryKnown(BW);
8789 Changed = simplifyDemandedBitsImpl(*
DefMI, 2, RHSDemand,
8790 RetryKnown,
Depth + 1, DoRewrite);
8795 InvalidateDebugUses(Demanded);
8797 Known = Opcode == TargetOpcode::G_AND ? LHSKnown & RHSKnown
8798 : LHSKnown | RHSKnown;
8801 case TargetOpcode::G_SHL:
8802 case TargetOpcode::G_LSHR:
8803 case TargetOpcode::G_ASHR: {
8810 KnownBits SrcKnown(BW);
8811 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 1, SrcDemand,
8812 SrcKnown,
Depth + 1, DoRewrite);
8815 InvalidateDebugUses(Demanded);
8819 case TargetOpcode::G_SHL:
8822 case TargetOpcode::G_LSHR:
8825 case TargetOpcode::G_ASHR: {
8829 isLegal({TargetOpcode::G_LSHR, {OpTy, AmtTy}});
8831 SrcKnown.isNonNegative()) &&
8834 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8840 Builder.setInsertPt(SaveMBB, SavePt);
8842 Rewrite(Lshr.getReg(0));
8861 unsigned Depth)
const {
8869 LLT Ty =
MRI.getType(Dst);
8870 assert(Ty.isValid() &&
"Expected a typed generic result");
8871 if (!
VT || Ty.isVector())
8876 if (!simplifyDemandedBitsImpl(
MI, OpNo, OpDemand,
Known, 0,
8887 unsigned Opcode =
MI.getOpcode();
8889 case TargetOpcode::G_SHL:
8890 case TargetOpcode::G_LSHR:
8891 case TargetOpcode::G_ASHR: {
8893 getConstantOrConstantSplatVector(
MI.getOperand(2).getReg()),
8900 return Probe(1, SrcDemand, SrcKnown);
8904 case TargetOpcode::G_AND:
8905 case TargetOpcode::G_OR: {
8910 bool RootRedundant = Opcode == TargetOpcode::G_AND
8919 if (Probe(2, RootDemand, RHSKnown))
8925 if (Probe(1, LHSDemand, LHSKnown))
8929 if (!
MRI.hasOneNonDBGUse(RHS) || getConstantOrConstantSplatVector(RHS))
8933 LHSDemand == RootDemand
8937 VT->getKnownBits(
MI.getOperand(1).getReg()));
8939 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 matchUDivByShiftedPow2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine unsigned division by a shifted power of two into a right shift.
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 matchSignedDivRemToUnsigned(MachineInstr &MI, unsigned UnsignedOpcode) const
Convert signed division or remainder of nonnegative operands to unsigned.
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.
unsigned Log2_64_Ceil(uint64_t Value)
Return the ceil log base 2 of the specified value, 64 if the value is zero.
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...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
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...
unsigned Log2(Align A)
Returns the log2 of the alignment.
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...