45#define DEBUG_TYPE "gi-combiner"
54 cl::desc(
"Force all indexed operations to be "
55 "legal for the GlobalISel combiner"));
64 TII(
Builder.getMF().getSubtarget().getInstrInfo()),
65 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
66 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
71 return *
Builder.getMF().getSubtarget().getTargetLowering();
89 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
97 LLT Ty = MRI.getType(V);
108 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
109 return ByteWidth -
I - 1;
129static std::optional<bool>
133 unsigned Width = MemOffset2Idx.
size();
136 bool BigEndian =
true, LittleEndian =
true;
137 for (
unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
138 auto MemOffsetAndIdx = MemOffset2Idx.
find(MemOffset);
139 if (MemOffsetAndIdx == MemOffset2Idx.
end())
141 const int64_t Idx = MemOffsetAndIdx->second - LowestIdx;
142 assert(Idx >= 0 &&
"Expected non-negative byte offset?");
145 if (!BigEndian && !LittleEndian)
149 assert((BigEndian != LittleEndian) &&
150 "Pattern cannot be both big and little endian!");
157 assert(
LI &&
"Must have LegalizerInfo to query isLegal!");
185 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
186 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
193 if (
MRI.constrainRegAttrs(ToReg, FromReg))
194 MRI.replaceRegWith(FromReg, ToReg);
196 Builder.buildCopy(FromReg, ToReg);
198 Observer.finishedChangingAllUsesOfReg();
213 unsigned ToOpcode)
const {
228 MRI.setRegBank(Reg, *RegBank);
239 if (
MI.getOpcode() != TargetOpcode::COPY)
249 MI.eraseFromParent();
254 assert(
MI.getOpcode() == TargetOpcode::G_FREEZE &&
"Invalid instruction");
260 if (!
MRI.hasOneNonDBGUse(OrigOp))
281 std::optional<MachineOperand> MaybePoisonOperand;
283 if (!Operand.isReg())
289 if (!MaybePoisonOperand)
290 MaybePoisonOperand = Operand;
299 if (!MaybePoisonOperand) {
304 B.buildCopy(
DstOp, OrigOp);
309 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
310 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
313 {TargetOpcode::G_FREEZE, {MaybePoisonOperandRegTy}}))
321 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
332 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
333 "Invalid instruction");
345 if (!
MRI.hasOneNonDBGUse(Reg))
347 switch (Def->getOpcode()) {
348 case TargetOpcode::G_BUILD_VECTOR:
353 Ops.push_back(BuildVecMO.getReg());
355 case TargetOpcode::G_IMPLICIT_DEF: {
356 LLT OpType =
MRI.getType(Reg);
363 OpType.getScalarType() &&
364 "All undefs should have the same type");
367 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
368 EltIdx != EltEnd; ++EltIdx)
369 Ops.push_back(
Undef->getOperand(0).getReg());
378 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
380 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
395 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
408 MI.eraseFromParent();
417 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
422 LLT InputTy =
MRI.getType(BCSrc);
424 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
429 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
433 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
449 Ops.push_back(BCSrc);
470 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
471 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
472 MI.eraseFromParent();
478 Register SrcVec1 = Shuffle.getSrc1Reg();
479 Register SrcVec2 = Shuffle.getSrc2Reg();
480 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
481 int Width =
MRI.getType(SrcVec1).getNumElements();
483 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
484 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
488 for (
int Val : Shuffle.getMask()) {
491 else if (Val < Width)
492 Extracts.
push_back(Unmerge1.getReg(Val));
494 Extracts.
push_back(Unmerge2.getReg(Val - Width));
496 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
497 if (Extracts.
size() == 1)
498 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
500 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
501 MI.eraseFromParent();
518 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
520 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
524 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
525 if (i + j >= Mask.size())
527 if (Mask[i + j] != -1)
531 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
534 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
535 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
536 if (i + j >= Mask.size())
538 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
555 {TargetOpcode::G_CONCAT_VECTORS,
556 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
567 SrcTy =
MRI.getType(Reg);
569 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
576 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
582 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
585 MI.eraseFromParent();
590 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
591 "Invalid instruction kind");
592 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
594 LLT SrcType =
MRI.getType(Src1);
596 unsigned DstNumElts = DstType.getNumElements();
597 unsigned SrcNumElts = SrcType.getNumElements();
614 if (DstNumElts < 2 * SrcNumElts)
619 if (DstNumElts % SrcNumElts != 0)
625 unsigned NumConcat = DstNumElts / SrcNumElts;
628 for (
unsigned i = 0; i != DstNumElts; ++i) {
635 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
636 (ConcatSrcs[i / SrcNumElts] >= 0 &&
637 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
640 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
647 for (
auto Src : ConcatSrcs) {
651 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
653 Ops.push_back(UndefReg);
666 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
674 MI.eraseFromParent();
683 const LLT TyForCandidate,
684 unsigned OpcodeForCandidate,
689 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
700 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
703 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
704 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
705 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
713 OpcodeForCandidate == TargetOpcode::G_ZEXT)
715 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
716 OpcodeForCandidate == TargetOpcode::G_SEXT)
717 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
726 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
737static void InsertInsnsWithoutSideEffectsBeforeUse(
749 InsertBB = PredBB->
getMBB();
754 if (InsertBB ==
DefMI.getParent()) {
756 Inserter(InsertBB, std::next(InsertPt), UseMO);
775 unsigned CandidateLoadOpc;
777 case TargetOpcode::G_ANYEXT:
778 CandidateLoadOpc = TargetOpcode::G_LOAD;
780 case TargetOpcode::G_SEXT:
781 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
783 case TargetOpcode::G_ZEXT:
784 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
789 return CandidateLoadOpc;
806 LLT LoadValueTy =
MRI.getType(LoadReg);
828 unsigned PreferredOpcode =
830 ? TargetOpcode::G_ANYEXT
832 Preferred = {
LLT(), PreferredOpcode,
nullptr};
833 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
834 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
835 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
836 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
837 const auto &MMO = LoadMI->
getMMO();
845 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
847 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
851 Preferred = ChoosePreferredUse(
MI, Preferred,
852 MRI.getType(
UseMI.getOperand(0).getReg()),
862 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
880 if (PreviouslyEmitted) {
887 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
888 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
890 EmittedInsns[InsertIntoBB] = NewMI;
896 MI.setDesc(
Builder.getTII().get(LoadOpc));
903 for (
auto *UseMO :
Uses) {
909 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
912 const LLT UseDstTy =
MRI.getType(UseDstReg);
913 if (UseDstReg != ChosenDstReg) {
914 if (Preferred.
Ty == UseDstTy) {
951 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
966 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
969 MI.getOperand(0).setReg(ChosenDstReg);
975 assert(
MI.getOpcode() == TargetOpcode::G_AND);
986 if (
MRI.getType(Dst).isVector())
994 APInt MaskVal = MaybeMask->Value;
1009 LLT RegTy =
MRI.getType(LoadReg);
1012 unsigned MaskSizeBits = MaskVal.
countr_one();
1015 !
MRI.hasOneNonDBGUse(LoadReg))
1020 if (MaskSizeBits > LoadSizeBits)
1039 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1044 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1048 B.setInstrAndDebugLoc(*LoadMI);
1049 auto &MF =
B.getMF();
1051 auto *NewMMO = MF.getMachineMemOperand(MMO, PtrInfo, MemDesc.
MemoryTy);
1052 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1062 "shouldn't consider debug uses");
1070 if (DefOrUse ==
MBB.end())
1072 return &*DefOrUse == &
DefMI;
1078 "shouldn't consider debug uses");
1081 else if (
DefMI.getParent() !=
UseMI.getParent())
1088 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1092 if (
MRI.getType(SrcReg).isVector())
1097 LoadUser = TruncSrc;
1099 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1104 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1106 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1108 if (LoadSizeBits == SizeInBits)
1115 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1116 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1119 LLT RegTy =
MRI.getType(DstReg);
1132 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1134 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1140 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1143 if (NewSizeBits < 8)
1156 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1161 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1164 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1169 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1170 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1172 unsigned ScalarSizeBits;
1173 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1182 auto &MMO = LoadDef->
getMMO();
1183 Builder.setInstrAndDebugLoc(*LoadDef);
1185 auto PtrInfo = MMO.getPointerInfo();
1186 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1187 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1190 MI.eraseFromParent();
1201 auto *MF =
MI->getMF();
1208 AM.
BaseOffs = CstOff->getSExtValue();
1213 MF->getDataLayout(), AM,
1215 MF->getFunction().getContext()),
1216 MI->getMMO().getAddrSpace());
1221 case TargetOpcode::G_LOAD:
1222 return TargetOpcode::G_INDEXED_LOAD;
1223 case TargetOpcode::G_STORE:
1224 return TargetOpcode::G_INDEXED_STORE;
1225 case TargetOpcode::G_ZEXTLOAD:
1226 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1227 case TargetOpcode::G_SEXTLOAD:
1228 return TargetOpcode::G_INDEXED_SEXTLOAD;
1234bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1244 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1245 OpTys = {PtrTy, Ty, Ty};
1247 OpTys = {Ty, PtrTy};
1249 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1255 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1256 "considered for post-indexing."));
1260 bool &RematOffset)
const {
1273 if (!isIndexedLoadStoreLegal(LdSt))
1284 unsigned NumUsesChecked = 0;
1297 if (StoredValDef == &
Use)
1300 Offset = PtrAdd->getOffsetReg();
1302 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1310 RematOffset =
false;
1314 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1319 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1320 if (&BasePtrUse == PtrDef)
1326 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1328 isIndexedLoadStoreLegal(*BasePtrLdSt))
1334 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1335 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1338 if (BaseUseUse.getParent() != LdSt.
getParent())
1350 Addr = PtrAdd->getReg(0);
1351 Base = PtrAdd->getBaseReg();
1366 MRI.hasOneNonDBGUse(Addr))
1373 if (!isIndexedLoadStoreLegal(LdSt))
1377 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1382 if (
Base == St->getValueReg())
1387 if (St->getValueReg() == Addr)
1392 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1393 if (AddrUse.getParent() != LdSt.
getParent())
1398 bool RealUse =
false;
1399 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1417 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1427 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1434 if (!LoadMI->isSimple())
1446 const unsigned MaxIter = 20;
1449 if (
II->isLoadFoldBarrier())
1451 if (Iter++ == MaxIter)
1467 int Elt = CVal->getZExtValue();
1480 Register VecPtr = LoadMI->getPointerReg();
1481 LLT PtrTy =
MRI.getType(VecPtr);
1489 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1512 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1527 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1529 if (!MatchInfo.
IsPre &&
1530 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1540 unsigned Opcode =
MI.getOpcode();
1541 bool IsStore = Opcode == TargetOpcode::G_STORE;
1547 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1549 *OldCst->getOperand(1).getCImm());
1550 MatchInfo.
Offset = NewCst.getReg(0);
1553 auto MIB =
Builder.buildInstr(NewOpcode);
1555 MIB.addDef(MatchInfo.
Addr);
1556 MIB.addUse(
MI.getOperand(0).getReg());
1558 MIB.addDef(
MI.getOperand(0).getReg());
1559 MIB.addDef(MatchInfo.
Addr);
1562 MIB.addUse(MatchInfo.
Base);
1563 MIB.addUse(MatchInfo.
Offset);
1564 MIB.addImm(MatchInfo.
IsPre);
1565 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1566 MI.eraseFromParent();
1574 unsigned Opcode =
MI.getOpcode();
1575 bool IsDiv, IsSigned;
1580 case TargetOpcode::G_SDIV:
1581 case TargetOpcode::G_UDIV: {
1583 IsSigned = Opcode == TargetOpcode::G_SDIV;
1586 case TargetOpcode::G_SREM:
1587 case TargetOpcode::G_UREM: {
1589 IsSigned = Opcode == TargetOpcode::G_SREM;
1595 unsigned DivOpcode, RemOpcode, DivremOpcode;
1597 DivOpcode = TargetOpcode::G_SDIV;
1598 RemOpcode = TargetOpcode::G_SREM;
1599 DivremOpcode = TargetOpcode::G_SDIVREM;
1601 DivOpcode = TargetOpcode::G_UDIV;
1602 RemOpcode = TargetOpcode::G_UREM;
1603 DivremOpcode = TargetOpcode::G_UDIVREM;
1621 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1622 if (
MI.getParent() ==
UseMI.getParent() &&
1623 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1624 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1637 unsigned Opcode =
MI.getOpcode();
1638 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1641 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1642 DestDivReg =
MI.getOperand(0).getReg();
1646 DestRemReg =
MI.getOperand(0).getReg();
1650 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1657 Builder.setInstrAndDebugLoc(*FirstInst);
1659 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1660 : TargetOpcode::G_UDIVREM,
1661 {DestDivReg, DestRemReg},
1663 MI.eraseFromParent();
1669 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1686 if (BrIt ==
MBB->begin())
1688 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1690 BrCond = &*std::prev(BrIt);
1691 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1697 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1698 MBB->isLayoutSuccessor(BrCondTarget);
1704 Builder.setInstrAndDebugLoc(*BrCond);
1709 auto True =
Builder.buildConstant(
1715 MI.getOperand(0).setMBB(FallthroughBB);
1728 unsigned MaxLen)
const {
1729 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1731 DstAlignCanChange, MemOps);
1736 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1741 DstAlignCanChange, MemOps) ==
1743 assert(
Changed &&
"expected memcpy-family instruction to lower");
1748 unsigned MaxLen)
const {
1760 switch (
MI.getOpcode()) {
1763 case TargetOpcode::G_FNEG: {
1764 Result.changeSign();
1767 case TargetOpcode::G_FABS: {
1771 case TargetOpcode::G_FCEIL:
1774 case TargetOpcode::G_FFLOOR:
1777 case TargetOpcode::G_INTRINSIC_TRUNC:
1780 case TargetOpcode::G_INTRINSIC_ROUND:
1783 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1786 case TargetOpcode::G_FRINT:
1787 case TargetOpcode::G_FNEARBYINT:
1791 case TargetOpcode::G_FPEXT:
1792 case TargetOpcode::G_FPTRUNC: {
1799 case TargetOpcode::G_FSQRT: {
1803 Result =
APFloat(sqrt(Result.convertToDouble()));
1806 case TargetOpcode::G_FLOG2: {
1826 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1827 MI.eraseFromParent();
1838 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1861 Type *AccessTy =
nullptr;
1862 auto &MF = *
MI.getMF();
1863 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1866 MF.getFunction().getContext());
1871 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1876 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1878 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1879 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1880 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1881 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1890 unsigned PtrAddFlags =
MI.getFlags();
1906 MatchInfo.
Flags = Flags;
1912 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1914 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1918 MI.getOperand(1).setReg(MatchInfo.
Base);
1919 MI.getOperand(2).setReg(NewOffset.getReg(0));
1933 unsigned Opcode =
MI.getOpcode();
1934 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1935 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1936 Opcode == TargetOpcode::G_USHLSAT) &&
1937 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1957 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1962 if (Opcode == TargetOpcode::G_USHLSAT &&
1963 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1971 unsigned Opcode =
MI.getOpcode();
1972 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1973 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1974 Opcode == TargetOpcode::G_USHLSAT) &&
1975 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1977 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1978 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1979 auto Imm = MatchInfo.
Imm;
1981 if (
Imm >= ScalarSizeInBits) {
1983 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1984 Builder.buildConstant(
MI.getOperand(0), 0);
1985 MI.eraseFromParent();
1990 Imm = ScalarSizeInBits - 1;
1993 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1996 MI.getOperand(1).setReg(MatchInfo.
Reg);
1997 MI.getOperand(2).setReg(NewImm);
2013 unsigned ShiftOpcode =
MI.getOpcode();
2014 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2015 ShiftOpcode == TargetOpcode::G_ASHR ||
2016 ShiftOpcode == TargetOpcode::G_LSHR ||
2017 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2018 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2019 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2022 Register LogicDest =
MI.getOperand(1).getReg();
2023 if (!
MRI.hasOneNonDBGUse(LogicDest))
2029 unsigned LogicOpcode = LogicMI->
getOpcode();
2030 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2031 LogicOpcode != TargetOpcode::G_XOR)
2035 const Register C1 =
MI.getOperand(2).getReg();
2037 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2040 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2042 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2044 if (
MI->getOpcode() != ShiftOpcode ||
2045 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2054 ShiftVal = MaybeImmVal->Value.getSExtValue();
2068 if (matchFirstShift(LogicMIOp1, C0Val)) {
2070 MatchInfo.
Shift2 = LogicMIOp1;
2071 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2073 MatchInfo.
Shift2 = LogicMIOp2;
2077 MatchInfo.
ValSum = C0Val + C1Val;
2080 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2083 MatchInfo.
Logic = LogicMI;
2089 unsigned Opcode =
MI.getOpcode();
2090 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2091 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2092 Opcode == TargetOpcode::G_SSHLSAT) &&
2093 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2095 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2096 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2102 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2111 Register Shift2Const =
MI.getOperand(2).getReg();
2113 .buildInstr(Opcode, {DestType},
2123 MI.eraseFromParent();
2135 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2139 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2154 LLT InnerShiftTy =
MRI.getType(InnerShift);
2156 if ((N1C + N001C).ult(InnerShiftSize)) {
2162 if ((N001C + OpSizeInBits) == InnerShiftSize)
2164 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2165 MatchInfo.
Mask =
true;
2175 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2182 if (MatchInfo.
Mask ==
true) {
2190 Builder.buildTrunc(Dst, Shift);
2191 MI.eraseFromParent();
2195 unsigned &ShiftVal)
const {
2196 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2202 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2203 return (
static_cast<int32_t
>(ShiftVal) != -1);
2207 unsigned &ShiftVal)
const {
2208 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2210 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2213 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2214 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2235 auto NegCst =
B.buildConstant(Ty, -
Imm);
2237 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2238 MI.getOperand(2).setReg(NegCst.getReg(0));
2240 if (
Imm.isMinSignedValue())
2250 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2264 if (!MaybeShiftAmtVal)
2268 LLT SrcTy =
MRI.getType(ExtSrc);
2278 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2279 MatchData.
Reg = ExtSrc;
2280 MatchData.
Imm = ShiftAmt;
2282 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2283 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2284 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2290 int64_t ShiftAmtVal = MatchData.
Imm;
2292 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2293 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2295 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2296 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2297 MI.eraseFromParent();
2304 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2308 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2311 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2312 if (MergedValues[
I] != Unmerge->getReg(
I))
2315 MatchInfo = Unmerge->getSourceReg();
2329 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2330 "Expected an unmerge");
2339 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2340 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2342 if (SrcMergeTy != Dst0Ty && !SameSize)
2346 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2347 Operands.push_back(SrcInstr->getSourceReg(Idx));
2353 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2354 "Expected an unmerge");
2356 "Not enough operands to replace all defs");
2357 unsigned NumElems =
MI.getNumOperands() - 1;
2360 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2361 bool CanReuseInputDirectly = DstTy == SrcTy;
2362 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2363 Register DstReg =
MI.getOperand(Idx).getReg();
2368 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2369 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2370 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2371 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2374 if (CanReuseInputDirectly)
2377 Builder.buildCast(DstReg, SrcReg);
2379 MI.eraseFromParent();
2384 unsigned SrcIdx =
MI.getNumOperands() - 1;
2385 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2391 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2394 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2396 Val = Val.
lshr(ShiftAmt);
2404 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2405 "Expected an unmerge");
2407 "Not enough operands to replace all defs");
2408 unsigned NumElems =
MI.getNumOperands() - 1;
2409 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2410 Register DstReg =
MI.getOperand(Idx).getReg();
2411 Builder.buildConstant(DstReg, Csts[Idx]);
2414 MI.eraseFromParent();
2420 unsigned SrcIdx =
MI.getNumOperands() - 1;
2421 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2423 unsigned NumElems =
MI.getNumOperands() - 1;
2424 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2425 Register DstReg =
MI.getOperand(Idx).getReg();
2426 B.buildUndef(DstReg);
2434 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2435 "Expected an unmerge");
2436 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2437 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2440 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2441 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2449 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2450 Register Dst0Reg =
MI.getOperand(0).getReg();
2451 Builder.buildTrunc(Dst0Reg, SrcReg);
2452 MI.eraseFromParent();
2456 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2457 "Expected an unmerge");
2458 Register Dst0Reg =
MI.getOperand(0).getReg();
2459 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2465 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2466 LLT SrcTy =
MRI.getType(SrcReg);
2467 if (SrcTy.isVector())
2477 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2482 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2483 "Expected an unmerge");
2485 Register Dst0Reg =
MI.getOperand(0).getReg();
2490 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2491 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2494 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2497 "ZExt src doesn't fit in destination");
2502 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2504 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2507 MI.eraseFromParent();
2511 unsigned TargetShiftSize,
2512 unsigned &ShiftVal)
const {
2513 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2514 MI.getOpcode() == TargetOpcode::G_LSHR ||
2515 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2517 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2522 unsigned Size = Ty.getSizeInBits();
2523 if (
Size <= TargetShiftSize)
2531 ShiftVal = MaybeImmVal->Value.getSExtValue();
2532 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2539 LLT Ty =
MRI.getType(SrcReg);
2540 unsigned Size = Ty.getSizeInBits();
2541 unsigned HalfSize =
Size / 2;
2542 assert(ShiftVal >= HalfSize);
2546 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2547 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2549 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2550 Register Narrowed = Unmerge.getReg(1);
2557 if (NarrowShiftAmt != 0) {
2558 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2559 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2562 auto Zero =
Builder.buildConstant(HalfTy, 0);
2563 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2564 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2565 Register Narrowed = Unmerge.getReg(0);
2570 if (NarrowShiftAmt != 0) {
2571 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2572 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2575 auto Zero =
Builder.buildConstant(HalfTy, 0);
2576 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2578 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2580 HalfTy, Unmerge.getReg(1),
2581 Builder.buildConstant(HalfTy, HalfSize - 1));
2583 if (ShiftVal == HalfSize) {
2586 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2587 }
else if (ShiftVal ==
Size - 1) {
2595 HalfTy, Unmerge.getReg(1),
2596 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2604 MI.eraseFromParent();
2620 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2622 Builder.buildZExtOrTrunc(DstReg, Reg);
2623 MI.eraseFromParent();
2628 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2631 LLT IntTy =
MRI.getType(LHS);
2635 PtrReg.second =
false;
2636 for (
Register SrcReg : {LHS, RHS}) {
2640 LLT PtrTy =
MRI.getType(PtrReg.first);
2645 PtrReg.second =
true;
2657 const bool DoCommute = PtrReg.second;
2662 LLT PtrTy =
MRI.getType(LHS);
2664 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2665 Builder.buildPtrToInt(Dst, PtrAdd);
2666 MI.eraseFromParent();
2670 APInt &NewCst)
const {
2672 Register LHS = PtrAdd.getBaseReg();
2673 Register RHS = PtrAdd.getOffsetReg();
2679 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2682 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2691 APInt &NewCst)
const {
2695 Builder.buildConstant(Dst, NewCst);
2696 PtrAdd.eraseFromParent();
2701 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2706 SrcReg = OriginalSrcReg;
2707 LLT DstTy =
MRI.getType(DstReg);
2715 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2718 LLT DstTy =
MRI.getType(DstReg);
2723 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2724 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2734 if (ShiftSize > 32 && TruncSize < 32)
2747 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2748 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2752 if (!
MRI.hasOneNonDBGUse(SrcReg))
2755 LLT SrcTy =
MRI.getType(SrcReg);
2756 LLT DstTy =
MRI.getType(DstReg);
2765 case TargetOpcode::G_SHL: {
2774 case TargetOpcode::G_LSHR:
2775 case TargetOpcode::G_ASHR: {
2781 for (
auto &
User :
MRI.use_instructions(DstReg))
2782 if (
User.getOpcode() == TargetOpcode::G_STORE)
2786 if (NewShiftTy == SrcTy)
2800 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2803 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2808 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2810 LLT NewShiftTy = MatchInfo.second;
2813 LLT DstTy =
MRI.getType(Dst);
2817 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2820 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2821 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2822 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2826 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2829 if (NewShiftTy == DstTy)
2832 Builder.buildTrunc(Dst, NewShift);
2839 return !MO.isReg() ||
2840 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2845 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2847 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2851 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2852 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2857 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2858 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2864 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2865 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2866 "Expected an insert/extract element op");
2867 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2872 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2880 unsigned &OpIdx)
const {
2885 OpIdx = Cst->isZero() ? 3 : 2;
2930 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2957 return MO.isReg() && MO.getReg().isPhysical();
2967 return I1->isIdenticalTo(*I2);
2975 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2982 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2993 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2994 MaybeCst->getSExtValue() ==
C;
3001 std::optional<FPValueAndVReg> MaybeCst;
3005 return MaybeCst->Value.isExactlyValue(
C);
3009 unsigned OpIdx)
const {
3010 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3012 Register Replacement =
MI.getOperand(OpIdx).getReg();
3015 MI.eraseFromParent();
3020 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3024 MI.eraseFromParent();
3028 unsigned ConstIdx)
const {
3029 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3030 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3042 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3043 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3044 "This is not a funnel shift operation");
3046 Register ConstReg =
MI.getOperand(3).getReg();
3047 LLT ConstTy =
MRI.getType(ConstReg);
3048 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3051 assert((VRegAndVal) &&
"Value is not a constant");
3054 APInt NewConst = VRegAndVal->Value.
urem(
3059 MI.getOpcode(), {MI.getOperand(0)},
3060 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3062 MI.eraseFromParent();
3066 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3080 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3082 MI.eraseFromParent();
3087 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3089 MI.eraseFromParent();
3093 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3095 MI.eraseFromParent();
3100 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3102 MI.eraseFromParent();
3106 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3108 MI.eraseFromParent();
3112 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3115 Register &NewLHS = std::get<0>(MatchInfo);
3116 Register &NewRHS = std::get<1>(MatchInfo);
3124 NewLHS = MaybeNewLHS;
3128 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3133 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3136 LLT DstTy =
MRI.getType(DstReg);
3145 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3146 TargetOpcode::G_INSERT_VECTOR_ELT)
3152 MatchInfo.
resize(NumElts);
3156 if (IntImm >= NumElts || IntImm < 0)
3158 if (!MatchInfo[IntImm])
3159 MatchInfo[IntImm] = TmpReg;
3163 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3165 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3174 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3181 auto GetUndef = [&]() {
3184 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3192 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3193 MI.eraseFromParent();
3197 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3199 std::tie(SubLHS, SubRHS) = MatchInfo;
3200 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3201 MI.eraseFromParent();
3214 unsigned InnerOpc = InnerDef->
getOpcode();
3215 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3239 if (!TryMatch(InnerLHS, InnerRHS) &&
3240 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3244 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3245 : TargetOpcode::G_ADD;
3248 MatchInfo = [=](MachineIRBuilder &
Builder) {
3249 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3250 auto NewNot =
Builder.buildNot(Ty, NewInner);
3251 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3263 unsigned RootOpc =
MI.getOpcode();
3265 LLT Ty =
MRI.getType(Dst);
3270 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3271 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3282 unsigned LogicOpcode =
MI.getOpcode();
3283 assert(LogicOpcode == TargetOpcode::G_AND ||
3284 LogicOpcode == TargetOpcode::G_OR ||
3285 LogicOpcode == TargetOpcode::G_XOR);
3292 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3298 if (!LeftHandInst || !RightHandInst)
3300 unsigned HandOpcode = LeftHandInst->
getOpcode();
3301 if (HandOpcode != RightHandInst->
getOpcode())
3315 if (!XTy.
isValid() || XTy != YTy)
3320 switch (HandOpcode) {
3323 case TargetOpcode::G_ANYEXT:
3324 case TargetOpcode::G_SEXT:
3325 case TargetOpcode::G_ZEXT: {
3329 case TargetOpcode::G_TRUNC: {
3334 LLT DstTy =
MRI.getType(Dst);
3343 case TargetOpcode::G_AND:
3344 case TargetOpcode::G_ASHR:
3345 case TargetOpcode::G_LSHR:
3346 case TargetOpcode::G_SHL: {
3351 ExtraHandOpSrcReg = ZOp.
getReg();
3362 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3373 if (ExtraHandOpSrcReg.
isValid())
3385 "Expected at least one instr to build?");
3387 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3388 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3390 for (
auto &OperandFn : InstrToBuild.OperandFns)
3393 MI.eraseFromParent();
3397 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3398 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3399 int64_t ShlCst, AshrCst;
3405 if (ShlCst != AshrCst)
3408 {TargetOpcode::G_SEXT_INREG,
3411 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3413 MatchInfo = std::make_tuple(Src, ShlCst);
3418 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3419 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3422 std::tie(Src, ShiftAmt) = MatchInfo;
3423 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3424 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3425 MI.eraseFromParent();
3432 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3435 LLT Ty =
MRI.getType(Dst);
3447 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3450 auto Zero =
B.buildConstant(Ty, 0);
3473 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3497 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3504 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3521 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3539 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3546 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3557 unsigned ExtBits =
MI.getOperand(2).getImm();
3558 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3559 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3563 int64_t Cst,
bool IsVector,
bool IsFP) {
3565 return (ScalarSizeBits == 1 && Cst == -1) ||
3587 unsigned BuildUseCount = BV.getNumSources();
3588 if (BuildUseCount % 2 != 0)
3591 unsigned NumUnmerge = BuildUseCount / 2;
3597 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3600 UnmergeSrc = Unmerge->getSourceReg();
3602 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3603 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3610 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3615 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3616 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3619 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3622 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3627 if (Unmerge->getNumDefs() != NumUnmerge)
3631 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3634 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3645 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3646 B.setInstrAndDebugLoc(
MI);
3648 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3649 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3651 MI.eraseFromParent();
3673 unsigned NumOperands =
BuildMI->getNumSources();
3683 for (
I = 0;
I < NumOperands; ++
I) {
3695 UnmergeMI != UnmergeSrcMI)
3706 for (;
I < NumOperands; ++
I) {
3713 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3720 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3721 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3729 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3732 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3744 LLT DstTy =
MRI.getType(DstReg);
3745 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3750 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3755 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3759 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3762 Builder.buildTrunc(DstReg, MidReg);
3763 MI.eraseFromParent();
3768 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3769 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3770 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3778 if (!
MRI.hasOneNonDBGUse(XorSrc))
3788 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3790 if (!
MRI.hasOneNonDBGUse(Reg))
3795 switch (Def->getOpcode()) {
3800 case TargetOpcode::G_ICMP:
3806 case TargetOpcode::G_FCMP:
3812 case TargetOpcode::G_AND:
3813 case TargetOpcode::G_OR:
3819 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3820 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3828 if (Ty.isVector()) {
3832 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), SplatCst,
true, IsFP))
3846 for (
Register Reg : RegsToNegate) {
3851 switch (Def->getOpcode()) {
3854 case TargetOpcode::G_ICMP:
3855 case TargetOpcode::G_FCMP: {
3862 case TargetOpcode::G_AND:
3863 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3865 case TargetOpcode::G_OR:
3866 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3873 MI.eraseFromParent();
3877 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3879 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3883 Register SharedReg =
MI.getOperand(2).getReg();
3897 if (!
MRI.hasOneNonDBGUse(AndReg))
3904 return Y == SharedReg;
3908 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3911 std::tie(
X,
Y) = MatchInfo;
3914 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3915 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3916 MI.getOperand(2).setReg(
Y);
3922 Register DstReg = PtrAdd.getReg(0);
3923 LLT Ty =
MRI.getType(DstReg);
3926 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3929 if (Ty.isPointer()) {
3931 return ConstVal && *ConstVal == 0;
3934 assert(Ty.isVector() &&
"Expecting a vector type");
3945 Register Pow2Src1 =
MI.getOperand(2).getReg();
3946 LLT Ty =
MRI.getType(DstReg);
3949 auto NegOne =
Builder.buildConstant(Ty, -1);
3950 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3952 MI.eraseFromParent();
3956 unsigned &SelectOpNo)
const {
3968 !
MRI.hasOneNonDBGUse(LHS)) {
3969 OtherOperandReg = LHS;
3973 !
MRI.hasOneNonDBGUse(RHS))
3991 unsigned BinOpcode =
MI.getOpcode();
3996 bool CanFoldNonConst =
3997 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4002 if (CanFoldNonConst)
4027 LLT Ty =
MRI.getType(Dst);
4028 unsigned BinOpcode =
MI.getOpcode();
4035 if (SelectOperand == 1) {
4039 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4041 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4043 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4045 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4048 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4049 MI.eraseFromParent();
4052std::optional<SmallVector<Register, 8>>
4053CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4054 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4083 const unsigned MaxIter =
4085 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4094 return std::nullopt;
4110 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4111 return std::nullopt;
4123static std::optional<std::pair<GZExtLoad *, int64_t>>
4127 "Expected Reg to only have one non-debug use?");
4136 if (Shift % MemSizeInBits != 0)
4137 return std::nullopt;
4142 return std::nullopt;
4144 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
4145 return std::nullopt;
4147 return std::make_pair(
Load, Shift / MemSizeInBits);
4150std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4151CombinerHelper::findLoadOffsetsForLoadOrCombine(
4154 const unsigned MemSizeInBits)
const {
4157 SmallSetVector<const MachineInstr *, 8> Loads;
4163 GZExtLoad *LowestIdxLoad =
nullptr;
4166 SmallSet<int64_t, 8> SeenIdx;
4170 MachineBasicBlock *
MBB =
nullptr;
4171 const MachineMemOperand *MMO =
nullptr;
4174 GZExtLoad *EarliestLoad =
nullptr;
4177 GZExtLoad *LatestLoad =
nullptr;
4186 for (
auto Reg : RegsToVisit) {
4191 return std::nullopt;
4194 std::tie(
Load, DstPos) = *LoadAndPos;
4198 MachineBasicBlock *LoadMBB =
Load->getParent();
4202 return std::nullopt;
4205 auto &LoadMMO =
Load->getMMO();
4209 return std::nullopt;
4216 LoadPtr =
Load->getOperand(1).getReg();
4221 if (!SeenIdx.
insert(Idx).second)
4222 return std::nullopt;
4229 if (BasePtr != LoadPtr)
4230 return std::nullopt;
4232 if (Idx < LowestIdx) {
4234 LowestIdxLoad =
Load;
4241 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4242 return std::nullopt;
4251 EarliestLoad =
Load;
4259 "Expected to find a load for each register?");
4260 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4261 LatestLoad &&
"Expected at least two loads?");
4270 const unsigned MaxIter = 20;
4276 if (
MI.isLoadFoldBarrier())
4277 return std::nullopt;
4278 if (Iter++ == MaxIter)
4279 return std::nullopt;
4282 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4288 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4301 LLT Ty =
MRI.getType(Dst);
4307 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4308 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4312 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4319 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4320 if (NarrowMemSizeInBits % 8 != 0)
4333 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4334 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4337 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4344 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4347 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4359 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4360 const unsigned ZeroByteOffset =
4364 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4365 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4366 ZeroOffsetIdx->second != LowestIdx)
4376 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4390 MIB.setInstrAndDebugLoc(*LatestLoad);
4391 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4392 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4394 MIB.buildBSwap(Dst, LoadDst);
4406 if (
MRI.getType(DstReg).isVector())
4410 if (!
MRI.hasOneNonDBGUse(DstReg))
4412 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4414 case TargetOpcode::G_ANYEXT:
4416 case TargetOpcode::G_ZEXT:
4417 case TargetOpcode::G_SEXT:
4424 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4431 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4433 switch (
DefMI->getOpcode()) {
4434 case TargetOpcode::G_LOAD:
4435 case TargetOpcode::G_TRUNC:
4436 case TargetOpcode::G_SEXT:
4437 case TargetOpcode::G_ZEXT:
4438 case TargetOpcode::G_ANYEXT:
4439 case TargetOpcode::G_CONSTANT:
4443 if (InSrcs.
size() > 2)
4457 LLT ExtTy =
MRI.getType(DstReg);
4464 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4465 auto SrcReg =
PHI.getIncomingValue(
I);
4469 if (!SrcMIs.
insert(SrcMI))
4475 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4476 InsertPt =
MBB->getFirstNonPHI();
4481 OldToNewSrcMap[SrcMI] = NewExt;
4486 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4487 NewPhi.addDef(DstReg);
4490 NewPhi.addMBB(MO.getMBB());
4493 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4494 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4502 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4506 LLT SrcTy =
MRI.getType(SrcVec);
4507 if (SrcTy.isScalableVector())
4511 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4514 unsigned VecIdx = Cst->Value.getZExtValue();
4526 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4527 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4531 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4543 LLT ScalarTy =
MRI.getType(Reg);
4545 LLT DstTy =
MRI.getType(DstReg);
4547 if (ScalarTy != DstTy) {
4549 Builder.buildTrunc(DstReg, Reg);
4550 MI.eraseFromParent();
4558 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4559 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4577 LLT DstTy =
MRI.getType(DstReg);
4582 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4587 unsigned Idx = Cst->getZExtValue();
4590 ExtractedElts.
set(Idx);
4591 SrcDstPairs.emplace_back(
4592 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4595 return ExtractedElts.
all();
4600 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4601 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4602 for (
auto &Pair : SrcDstPairs) {
4603 auto *ExtMI = Pair.second;
4605 ExtMI->eraseFromParent();
4607 MI.eraseFromParent();
4614 MI.eraseFromParent();
4624 bool AllowScalarConstants,
4626 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4629 LLT Ty =
MRI.getType(Dst);
4630 unsigned BitWidth = Ty.getScalarSizeInBits();
4632 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4633 unsigned FshOpc = 0;
4644 int64_t CstShlAmt = 0, CstLShrAmt;
4647 CstShlAmt + CstLShrAmt ==
BitWidth) {
4648 FshOpc = TargetOpcode::G_FSHR;
4654 FshOpc = TargetOpcode::G_FSHL;
4659 FshOpc = TargetOpcode::G_FSHR;
4664 LLT AmtTy =
MRI.getType(Amt);
4666 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4670 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4677 unsigned Opc =
MI.getOpcode();
4678 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4683 unsigned RotateOpc =
4684 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4689 unsigned Opc =
MI.getOpcode();
4690 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4691 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4693 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4694 : TargetOpcode::G_ROTR));
4695 MI.removeOperand(2);
4701 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4702 MI.getOpcode() == TargetOpcode::G_ROTR);
4704 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4706 bool OutOfRange =
false;
4707 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4709 OutOfRange |= CI->getValue().uge(Bitsize);
4716 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4717 MI.getOpcode() == TargetOpcode::G_ROTR);
4719 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4721 LLT AmtTy =
MRI.getType(Amt);
4722 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4723 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4725 MI.getOperand(2).setReg(Amt);
4730 int64_t &MatchInfo)
const {
4731 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4742 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4743 if (KnownRHS.isUnknown())
4746 std::optional<bool> KnownVal;
4747 if (KnownRHS.isZero()) {
4757 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4767 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4776 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4792 LLT DstTy =
MRI.getType(Dst);
4800 auto KnownLHS =
VT->getKnownBits(LHS);
4801 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4804 LLT LHSTy =
MRI.getType(LHS);
4807 unsigned Op = TargetOpcode::COPY;
4808 if (DstSize != LHSSize)
4809 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4820 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4824 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4830 int64_t AndMaskBits;
4838 if (AndMaskBits & OrMaskBits)
4844 if (
MI.getOperand(1).getReg() == AndMaskReg)
4845 MI.getOperand(2).setReg(AndMaskReg);
4846 MI.getOperand(1).setReg(Src);
4856 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4859 LLT Ty =
MRI.getType(Src);
4861 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4863 int64_t Width =
MI.getOperand(2).getImm();
4871 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4875 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4876 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4877 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4887 LLT Ty =
MRI.getType(Dst);
4891 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4894 int64_t AndImm, LSBImm;
4896 const unsigned Size = Ty.getScalarSizeInBits();
4904 uint64_t MaybeMask =
static_cast<uint64_t
>(AndImm);
4909 if (MaybeMask & (MaybeMask + 1))
4913 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4921 if (
static_cast<uint64_t
>(LSBImm) + Width >
Size)
4925 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4926 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4927 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4935 const unsigned Opcode =
MI.getOpcode();
4936 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4938 const Register Dst =
MI.getOperand(0).getReg();
4940 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4941 ? TargetOpcode::G_SBFX
4942 : TargetOpcode::G_UBFX;
4945 LLT Ty =
MRI.getType(Dst);
4947 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4953 const unsigned Size = Ty.getScalarSizeInBits();
4963 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4967 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4971 const int64_t Pos = ShrAmt - ShlAmt;
4972 const int64_t Width =
Size - ShrAmt;
4975 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4976 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4977 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4985 const unsigned Opcode =
MI.getOpcode();
4986 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4988 const Register Dst =
MI.getOperand(0).getReg();
4989 LLT Ty =
MRI.getType(Dst);
4991 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
5004 const unsigned Size = Ty.getScalarSizeInBits();
5005 if (ShrAmt < 0 || ShrAmt >=
Size)
5009 if (0 == (SMask >> ShrAmt)) {
5011 B.buildConstant(Dst, 0);
5024 const int64_t Pos = ShrAmt;
5029 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5033 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5034 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5035 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5040bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5044 Register Src1Reg = PtrAdd.getBaseReg();
5049 Register Src2Reg = PtrAdd.getOffsetReg();
5051 if (
MRI.hasOneNonDBGUse(Src1Reg))
5061 const APInt &C1APIntVal = *C1;
5062 const APInt &C2APIntVal = *C2;
5063 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5065 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5068 MachineInstr *ConvUseMI = &
UseMI;
5069 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5070 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5071 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5073 if (!
MRI.hasOneNonDBGUse(DefReg))
5075 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5084 TargetLoweringBase::AddrMode AM;
5087 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5089 PtrAdd.getMF()->getFunction().getContext());
5090 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5091 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5097 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5109 Register Src1Reg =
MI.getOperand(1).getReg();
5110 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5122 unsigned PtrAddFlags =
MI.getFlags();
5123 unsigned AddFlags = RHS->getFlags();
5136 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5139 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5141 MI.getOperand(1).setReg(NewBase.getReg(0));
5142 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5146 return !reassociationCanBreakAddressingModePattern(
MI);
5156 std::optional<ValueAndVReg> LHSCstOff;
5166 unsigned PtrAddFlags =
MI.getFlags();
5167 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5169 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5171 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5185 LHSPtrAdd->moveBefore(&
MI);
5188 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5190 MI.getOperand(2).setReg(NewCst.getReg(0));
5193 Observer.changingInstr(*LHSPtrAdd);
5194 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5195 LHSPtrAdd->setFlags(Flags);
5198 return !reassociationCanBreakAddressingModePattern(
MI);
5209 Register Src2Reg =
MI.getOperand(2).getReg();
5210 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5211 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5224 unsigned PtrAddFlags =
MI.getFlags();
5225 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5238 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5240 MI.getOperand(1).setReg(LHSSrc1);
5241 MI.getOperand(2).setReg(NewCst.getReg(0));
5245 return !reassociationCanBreakAddressingModePattern(
MI);
5285 LLT OpRHSTy =
MRI.getType(OpRHS);
5302 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5303 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5311 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5312 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5325 unsigned Opc =
MI.getOpcode();
5338 APInt &MatchInfo)
const {
5339 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5343 MatchInfo = *MaybeCst;
5354 MI.getOperand(1).getReg(),
MRI);
5359 if (Csts.size() == 1)
5360 B.buildConstant(Dst, Csts[0]);
5362 B.buildBuildVectorConstant(Dst, Csts);
5368 APInt &MatchInfo)
const {
5374 MatchInfo = *MaybeCst;
5386 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5392 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5393 MI.getOpcode() == TargetOpcode::G_FMAD);
5394 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5411 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5434 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5438 LLT WideTy =
MRI.getType(Dst);
5442 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5458 case TargetOpcode::G_ADD:
5459 case TargetOpcode::G_SUB:
5460 case TargetOpcode::G_MUL:
5461 case TargetOpcode::G_AND:
5462 case TargetOpcode::G_OR:
5463 case TargetOpcode::G_XOR:
5471 auto Mask = Cst->Value;
5476 unsigned NarrowWidth = Mask.countr_one();
5482 auto &MF = *
MI.getMF();
5485 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5486 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5494 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5495 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5497 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5498 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5500 MI.getOperand(1).setReg(Ext.getReg(0));
5508 unsigned Opc =
MI.getOpcode();
5509 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5516 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5517 : TargetOpcode::G_SADDO;
5518 MI.setDesc(
Builder.getTII().get(NewOpc));
5519 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5528 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5529 MI.getOpcode() == TargetOpcode::G_SMULO);
5538 B.buildConstant(Dst, 0);
5539 B.buildConstant(Carry, 0);
5548 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5549 MI.getOpcode() == TargetOpcode::G_SADDE ||
5550 MI.getOpcode() == TargetOpcode::G_USUBE ||
5551 MI.getOpcode() == TargetOpcode::G_SSUBE);
5556 switch (
MI.getOpcode()) {
5557 case TargetOpcode::G_UADDE:
5558 NewOpcode = TargetOpcode::G_UADDO;
5560 case TargetOpcode::G_SADDE:
5561 NewOpcode = TargetOpcode::G_SADDO;
5563 case TargetOpcode::G_USUBE:
5564 NewOpcode = TargetOpcode::G_USUBO;
5566 case TargetOpcode::G_SSUBE:
5567 NewOpcode = TargetOpcode::G_SSUBO;
5571 MI.setDesc(
B.getTII().get(NewOpcode));
5572 MI.removeOperand(4);
5580 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5613 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5614 B.buildSub(Dst, Zero, ReplaceReg);
5623 unsigned Opcode =
MI.getOpcode();
5624 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5626 Register Dst = UDivorRem.getReg(0);
5627 Register LHS = UDivorRem.getReg(1);
5628 Register RHS = UDivorRem.getReg(2);
5629 LLT Ty =
MRI.getType(Dst);
5637 bool UseSRL =
false;
5642 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5644 if (IsSplat && !Factors.
empty()) {
5651 APInt Divisor = CI->getValue();
5660 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5661 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5671 if (Ty.isVector()) {
5672 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5673 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5676 Factor = Factors[0];
5684 return MIB.buildMul(Ty, Res, Factor);
5687 unsigned KnownLeadingZeros =
5688 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5690 bool UseNPQ =
false;
5692 auto BuildUDIVPattern = [&](
const Constant *
C) {
5694 const APInt &Divisor = CI->getValue();
5696 bool SelNPQ =
false;
5698 unsigned PreShift = 0, PostShift = 0;
5703 if (!Divisor.
isOne()) {
5709 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5711 Magic = std::move(magics.
Magic);
5714 "We shouldn't generate an undefined shift!");
5716 "We shouldn't generate an undefined shift!");
5720 SelNPQ = magics.
IsAdd;
5724 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5725 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5727 MIB.buildConstant(ScalarTy,
5732 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5740 assert(Matched &&
"Expected unary predicate match to succeed");
5742 Register PreShift, PostShift, MagicFactor, NPQFactor;
5745 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5746 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5747 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5748 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5751 "Non-build_vector operation should have been a scalar");
5752 PreShift = PreShifts[0];
5753 MagicFactor = MagicFactors[0];
5754 PostShift = PostShifts[0];
5758 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5761 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5764 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5769 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5771 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5773 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5776 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5777 auto One = MIB.buildConstant(Ty, 1);
5778 auto IsOne = MIB.buildICmp(
5782 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5784 if (Opcode == TargetOpcode::G_UREM) {
5785 auto Prod = MIB.buildMul(Ty, ret, RHS);
5786 return MIB.buildSub(Ty, LHS, Prod);
5792 unsigned Opcode =
MI.getOpcode();
5793 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5796 LLT DstTy =
MRI.getType(Dst);
5798 auto &MF = *
MI.getMF();
5799 AttributeList Attr = MF.getFunction().getAttributes();
5808 if (MF.getFunction().hasMinSize())
5811 if (Opcode == TargetOpcode::G_UDIV &&
5814 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5829 {TargetOpcode::G_ICMP,
5833 if (Opcode == TargetOpcode::G_UREM &&
5839 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5848 unsigned Opcode =
MI.getOpcode();
5849 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5852 LLT DstTy =
MRI.getType(Dst);
5856 auto &MF = *
MI.getMF();
5857 AttributeList Attr = MF.getFunction().getAttributes();
5866 if (MF.getFunction().hasMinSize())
5870 if (Opcode == TargetOpcode::G_SDIV &&
5873 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5885 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5888 if (Opcode == TargetOpcode::G_SREM &&
5894 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5903 unsigned Opcode =
MI.getOpcode();
5904 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5905 Opcode == TargetOpcode::G_SREM);
5907 Register Dst = SDivorRem.getReg(0);
5908 Register LHS = SDivorRem.getReg(1);
5909 Register RHS = SDivorRem.getReg(2);
5910 LLT Ty =
MRI.getType(Dst);
5917 bool UseSRA =
false;
5923 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5925 if (IsSplat && !ExactFactors.
empty()) {
5927 ExactFactors.
push_back(ExactFactors[0]);
5932 APInt Divisor = CI->getValue();
5942 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5943 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5951 assert(Matched &&
"Expected unary predicate match to succeed");
5954 if (Ty.isVector()) {
5955 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5956 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5958 Shift = ExactShifts[0];
5959 Factor = ExactFactors[0];
5967 return MIB.buildMul(Ty, Res, Factor);
5972 auto BuildSDIVPattern = [&](
const Constant *
C) {
5974 const APInt &Divisor = CI->getValue();
5978 int NumeratorFactor = 0;
5989 NumeratorFactor = 1;
5992 NumeratorFactor = -1;
5995 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5996 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5998 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5999 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
6007 assert(Matched &&
"Expected unary predicate match to succeed");
6009 Register MagicFactor, Factor, Shift, ShiftMask;
6012 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
6013 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
6014 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
6015 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
6018 "Non-build_vector operation should have been a scalar");
6019 MagicFactor = MagicFactors[0];
6020 Factor = Factors[0];
6022 ShiftMask = ShiftMasks[0];
6026 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6029 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6030 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6033 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6036 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6037 auto T = MIB.buildLShr(Ty, Q, SignShift);
6038 T = MIB.buildAnd(Ty,
T, ShiftMask);
6039 auto ret = MIB.buildAdd(Ty, Q,
T);
6041 if (Opcode == TargetOpcode::G_SREM) {
6042 auto Prod = MIB.buildMul(Ty, ret, RHS);
6043 return MIB.buildSub(Ty, LHS, Prod);
6049 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6050 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6051 "Expected SDIV or UDIV");
6054 auto MatchPow2 = [&](
const Constant *
C) {
6056 return CI && (CI->getValue().isPowerOf2() ||
6057 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6063 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6068 LLT Ty =
MRI.getType(Dst);
6088 unsigned BitWidth = Ty.getScalarSizeInBits();
6089 auto Zero =
Builder.buildConstant(Ty, 0);
6092 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6093 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6095 auto Sign =
Builder.buildAShr(
6099 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6105 auto One =
Builder.buildConstant(Ty, 1);
6106 auto MinusOne =
Builder.buildConstant(Ty, -1);
6110 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6111 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6115 auto Neg =
Builder.buildNeg(Ty, AShr);
6117 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6118 MI.eraseFromParent();
6122 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6127 LLT Ty =
MRI.getType(Dst);
6130 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6131 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6132 MI.eraseFromParent();
6136 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6141 LLT Ty =
MRI.getType(Dst);
6160 unsigned BitWidth = Ty.getScalarSizeInBits();
6161 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6162 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6164 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6165 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6166 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6169 MI.eraseFromParent();
6173 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6176 LLT Ty =
MRI.getType(Dst);
6177 LLT RHSTy =
MRI.getType(RHS);
6179 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6181 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6196 LLT Ty =
MRI.getType(Dst);
6202 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6203 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6204 Builder.buildLShr(Dst, LHS, Trunc);
6205 MI.eraseFromParent();
6212 LLT DstTy =
MRI.getType(Dst);
6213 LLT SrcTy =
MRI.getType(Src);
6215 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6216 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6219 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6248 Builder.buildTruncSSatS(Dst, MatchInfo);
6249 MI.eraseFromParent();
6256 LLT DstTy =
MRI.getType(Dst);
6257 LLT SrcTy =
MRI.getType(Src);
6259 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6260 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6263 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6281 Builder.buildTruncSSatU(Dst, MatchInfo);
6282 MI.eraseFromParent();
6289 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6290 LLT SrcTy =
MRI.getType(Val);
6292 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6293 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6296 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6305 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6314 unsigned Opc =
MI.getOpcode();
6315 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB);
6327 Opc = TargetOpcode::G_FSUB;
6332 Opc = TargetOpcode::G_FADD;
6338 MI.setDesc(
B.getTII().get(
Opc));
6339 MI.getOperand(1).setReg(
X);
6340 MI.getOperand(2).setReg(
Y);
6348 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6351 MatchInfo =
MI.getOperand(2).getReg();
6352 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6354 const auto LHSCst = Ty.isVector()
6361 if (LHSCst->Value.isNegZero())
6365 if (LHSCst->Value.isPosZero())
6375 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6382 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6396 bool &AllowFusionGlobally,
6398 bool CanReassociate)
const {
6400 auto *MF =
MI.getMF();
6401 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6403 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6411 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6414 if (!HasFMAD && !HasFMA)
6422 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6429 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6431 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6443 unsigned PreferredFusedOpcode =
6444 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6457 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6459 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6460 {LHS.MI->getOperand(1).getReg(),
6461 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6470 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6472 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6473 {RHS.MI->getOperand(1).getReg(),
6474 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6486 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6488 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6492 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6501 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6503 unsigned PreferredFusedOpcode =
6504 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6507 bool LHSContractable =
6510 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6513 bool RHSContractable =
6516 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6520 if (LHSContractable || RHSContractable) {
6523 if (!LHSContractable ||
6524 (RHSContractable &&
hasMoreUses(*LHSFpExtSrc, *RHSFpExtSrc,
MRI))) {
6526 LHSFpExtSrc = RHSFpExtSrc;
6529 unsigned Flags =
MI.getFlags() & LHSFpExtSrc->
getFlags();
6533 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6534 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6545 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6547 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6559 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6561 unsigned PreferredFusedOpcode =
6562 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6567 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6570 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6571 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6576 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6579 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6580 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6589 Register X = FMA->getOperand(1).getReg();
6590 Register Y = FMA->getOperand(2).getReg();
6593 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6594 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6597 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6598 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6599 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6600 {
X,
Y, InnerFMA}, OuterFlags);
6611 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6613 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6620 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6621 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6631 unsigned PreferredFusedOpcode =
6632 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6646 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6647 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6648 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6649 {FpExtU, FpExtV, Z}, InnerFlags)
6651 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6652 {
X,
Y, InnerFMA}, OuterFlags);
6658 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6662 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6664 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6665 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6669 LHS.MI->getOperand(1).getReg(),
6670 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6681 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6686 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6688 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6689 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6693 X =
B.buildFPExt(DstType,
X).getReg(0);
6694 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6697 InnerFlags, OuterFlags,
B);
6706 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6710 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6712 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6713 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6717 RHS.MI->getOperand(1).getReg(),
6718 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6729 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6734 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6736 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6737 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6741 X =
B.buildFPExt(DstType,
X).getReg(0);
6742 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6745 InnerFlags, OuterFlags,
B);
6757 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6759 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6771 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6775 int FirstMulHasFewerUses =
true;
6779 FirstMulHasFewerUses =
false;
6781 unsigned PreferredFusedOpcode =
6782 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6785 if (FirstMulHasFewerUses &&
6788 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6790 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6791 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6792 {LHS.MI->getOperand(1).getReg(),
6793 LHS.MI->getOperand(2).getReg(), NegZ},
6801 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6804 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6805 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6806 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6817 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6819 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6825 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6827 unsigned PreferredFusedOpcode =
6828 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6836 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6840 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6841 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6852 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6854 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6868 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6870 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6876 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6878 unsigned PreferredFusedOpcode =
6879 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6886 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6892 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6893 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6894 {FpExtX, FpExtY, NegZ}, Flags);
6903 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6907 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6910 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6911 {NegY, FpExtZ, LHSReg}, Flags);
6922 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6924 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6928 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6929 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6933 unsigned PreferredFusedOpcode =
6934 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6938 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6939 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6940 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
6951 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6953 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6955 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6958 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6968 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6970 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6982 unsigned &IdxToPropagate)
const {
6984 switch (
MI.getOpcode()) {
6987 case TargetOpcode::G_FMINNUM:
6988 case TargetOpcode::G_FMAXNUM:
6989 PropagateNaN =
false;
6991 case TargetOpcode::G_FMINIMUM:
6992 case TargetOpcode::G_FMAXIMUM:
6993 PropagateNaN =
true;
6997 auto MatchNaN = [&](
unsigned Idx) {
6998 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
7002 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
7006 return MatchNaN(1) || MatchNaN(2);
7014 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
7024 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
7041 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
7042 if (&U == &
MI || U.getParent() !=
MI.getParent())
7044 if (U.getOpcode() == TargetOpcode::G_FDIV &&
7045 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
7046 !IsOne(U.getOperand(1).getReg())) {
7059 return MatchInfo.
size() >= MinUses;
7067 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7068 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7069 MatchInfo[0]->getOperand(2).getReg(),
7070 MatchInfo[0]->getFlags());
7075 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7076 Div->getOperand(0).getReg(),
MI->getFlags());
7077 MI->eraseFromParent();
7082 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7092 Reg == MaybeSameReg;
7094 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7115 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7124 return MRI.getType(MatchInfo) == DstVecTy;
7127 std::optional<ValueAndVReg> ShiftAmount;
7136 return MRI.getType(MatchInfo) == DstVecTy;
7151 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7158 std::optional<ValueAndVReg> ShiftAmt;
7164 LLT MatchTy =
MRI.getType(MatchInfo);
7165 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7166 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7169unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7171 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7172 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7173 "Expected a NaN behaviour?");
7183 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7184 return TargetOpcode::G_FMAXNUM;
7185 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7186 return TargetOpcode::G_FMAXIMUM;
7187 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7188 return TargetOpcode::G_FMAXNUM;
7189 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7190 return TargetOpcode::G_FMAXIMUM;
7196 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7197 return TargetOpcode::G_FMINNUM;
7198 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7199 return TargetOpcode::G_FMINIMUM;
7200 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7201 return TargetOpcode::G_FMINNUM;
7202 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7204 return TargetOpcode::G_FMINIMUM;
7208CombinerHelper::SelectPatternNaNBehaviour
7210 bool IsOrderedComparison)
const {
7211 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7212 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7214 if (!LHSSafe && !RHSSafe)
7215 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7216 if (LHSSafe && RHSSafe)
7217 return SelectPatternNaNBehaviour::RETURNS_ANY;
7220 if (IsOrderedComparison)
7221 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7222 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7225 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7226 : SelectPatternNaNBehaviour::RETURNS_NAN;
7235 LLT DstTy =
MRI.getType(Dst);
7248 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7250 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7252 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7255 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7256 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7257 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7258 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7260 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7263 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7268 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7273 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7275 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7279 MatchInfo = [=](MachineIRBuilder &
B) {
7280 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7288 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7295 Register TrueVal =
MI.getOperand(2).getReg();
7296 Register FalseVal =
MI.getOperand(3).getReg();
7297 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7302 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7315 if (MatchedSub &&
X != OpLHS)
7323 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7326 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7327 B.buildICmp(Pred, Dst,
Y, Zero);
7334static std::optional<unsigned>
7336 std::optional<int64_t> &Result) {
7337 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7338 Opcode == TargetOpcode::G_ASHR) &&
7339 "Expect G_SHL, G_LSHR or G_ASHR.");
7340 auto SignificantBits = 0;
7342 case TargetOpcode::G_SHL:
7346 case TargetOpcode::G_LSHR:
7350 case TargetOpcode::G_ASHR:
7359 Result = std::nullopt;
7370 Register ShiftVal =
MI.getOperand(1).getReg();
7371 Register ShiftReg =
MI.getOperand(2).getReg();
7372 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7373 auto IsShiftTooBig = [&](
const Constant *
C) {
7378 MatchInfo = std::nullopt;
7382 MI.getOpcode(), MatchInfo);
7383 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7389 unsigned LHSOpndIdx = 1;
7390 unsigned RHSOpndIdx = 2;
7391 switch (
MI.getOpcode()) {
7392 case TargetOpcode::G_UADDO:
7393 case TargetOpcode::G_SADDO:
7394 case TargetOpcode::G_UMULO:
7395 case TargetOpcode::G_SMULO:
7402 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7403 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7413 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7417 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7424 std::optional<FPValueAndVReg> ValAndVReg;
7432 unsigned LHSOpndIdx = 1;
7433 unsigned RHSOpndIdx = 2;
7434 switch (
MI.getOpcode()) {
7435 case TargetOpcode::G_UADDO:
7436 case TargetOpcode::G_SADDO:
7437 case TargetOpcode::G_UMULO:
7438 case TargetOpcode::G_SMULO:
7445 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7446 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7447 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7448 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7452bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7454 if (SrcTy.isFixedVector())
7456 if (SrcTy.isScalar()) {
7460 return IConstant && IConstant->Value == 1;
7465bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7466 LLT SrcTy =
MRI.getType(Src);
7468 return isConstantSplatVector(Src, 0, AllowUndefs);
7473 return IConstant && IConstant->Value == 0;
7480bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7481 bool AllowUndefs)
const {
7487 for (
unsigned I = 0;
I < NumSources; ++
I) {
7488 GImplicitDef *ImplicitDef =
7490 if (ImplicitDef && AllowUndefs)
7492 if (ImplicitDef && !AllowUndefs)
7494 std::optional<ValueAndVReg> IConstant =
7496 if (IConstant && IConstant->Value == SplatValue)
7506CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7509 return IConstant->Value;
7513 return std::nullopt;
7516 std::optional<APInt>
Value = std::nullopt;
7517 for (
unsigned I = 0;
I < NumSources; ++
I) {
7518 std::optional<ValueAndVReg> IConstant =
7521 return std::nullopt;
7523 Value = IConstant->Value;
7524 else if (*
Value != IConstant->Value)
7525 return std::nullopt;
7531bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7541 for (
unsigned I = 0;
I < NumSources; ++
I) {
7542 std::optional<ValueAndVReg> IConstant =
7551bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7558 LLT CondTy =
MRI.getType(
Select->getCondReg());
7559 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7569 std::optional<ValueAndVReg> TrueOpt =
7571 std::optional<ValueAndVReg> FalseOpt =
7574 if (!TrueOpt || !FalseOpt)
7577 APInt TrueValue = TrueOpt->Value;
7578 APInt FalseValue = FalseOpt->Value;
7582 MatchInfo = [=](MachineIRBuilder &
B) {
7583 B.setInstrAndDebugLoc(*
Select);
7584 B.buildZExtOrTrunc(Dest,
Cond);
7591 MatchInfo = [=](MachineIRBuilder &
B) {
7592 B.setInstrAndDebugLoc(*
Select);
7593 B.buildSExtOrTrunc(Dest,
Cond);
7600 MatchInfo = [=](MachineIRBuilder &
B) {
7601 B.setInstrAndDebugLoc(*
Select);
7602 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7603 B.buildNot(Inner,
Cond);
7604 B.buildZExtOrTrunc(Dest, Inner);
7611 MatchInfo = [=](MachineIRBuilder &
B) {
7612 B.setInstrAndDebugLoc(*
Select);
7613 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7614 B.buildNot(Inner,
Cond);
7615 B.buildSExtOrTrunc(Dest, Inner);
7621 if (TrueValue - 1 == FalseValue) {
7622 MatchInfo = [=](MachineIRBuilder &
B) {
7623 B.setInstrAndDebugLoc(*
Select);
7624 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7625 B.buildZExtOrTrunc(Inner,
Cond);
7626 B.buildAdd(Dest, Inner, False);
7632 if (TrueValue + 1 == FalseValue) {
7633 MatchInfo = [=](MachineIRBuilder &
B) {
7634 B.setInstrAndDebugLoc(*
Select);
7635 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7636 B.buildSExtOrTrunc(Inner,
Cond);
7637 B.buildAdd(Dest, Inner, False);
7644 MatchInfo = [=](MachineIRBuilder &
B) {
7645 B.setInstrAndDebugLoc(*
Select);
7646 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7647 B.buildZExtOrTrunc(Inner,
Cond);
7650 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7651 B.buildShl(Dest, Inner, ShAmtC, Flags);
7658 MatchInfo = [=](MachineIRBuilder &
B) {
7659 B.setInstrAndDebugLoc(*
Select);
7661 B.buildNot(Not,
Cond);
7662 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7663 B.buildZExtOrTrunc(Inner, Not);
7666 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7667 B.buildShl(Dest, Inner, ShAmtC, Flags);
7674 MatchInfo = [=](MachineIRBuilder &
B) {
7675 B.setInstrAndDebugLoc(*
Select);
7676 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7677 B.buildSExtOrTrunc(Inner,
Cond);
7678 B.buildOr(Dest, Inner, False, Flags);
7685 MatchInfo = [=](MachineIRBuilder &
B) {
7686 B.setInstrAndDebugLoc(*
Select);
7688 B.buildNot(Not,
Cond);
7689 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7690 B.buildSExtOrTrunc(Inner, Not);
7691 B.buildOr(Dest, Inner, True, Flags);
7700bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7707 LLT CondTy =
MRI.getType(
Select->getCondReg());
7708 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7717 if (CondTy != TrueTy)
7722 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7723 MatchInfo = [=](MachineIRBuilder &
B) {
7724 B.setInstrAndDebugLoc(*
Select);
7725 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7726 B.buildZExtOrTrunc(Ext,
Cond);
7727 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7728 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7735 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7736 MatchInfo = [=](MachineIRBuilder &
B) {
7737 B.setInstrAndDebugLoc(*
Select);
7738 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7739 B.buildZExtOrTrunc(Ext,
Cond);
7740 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7741 B.buildAnd(DstReg, Ext, FreezeTrue);
7747 if (isOneOrOneSplat(False,
true)) {
7748 MatchInfo = [=](MachineIRBuilder &
B) {
7749 B.setInstrAndDebugLoc(*
Select);
7751 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7752 B.buildNot(Inner,
Cond);
7754 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7755 B.buildZExtOrTrunc(Ext, Inner);
7756 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7757 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7763 if (isZeroOrZeroSplat(True,
true)) {
7764 MatchInfo = [=](MachineIRBuilder &
B) {
7765 B.setInstrAndDebugLoc(*
Select);
7767 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7768 B.buildNot(Inner,
Cond);
7770 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7771 B.buildZExtOrTrunc(Ext, Inner);
7772 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7773 B.buildAnd(DstReg, Ext, FreezeFalse);
7795 LLT DstTy =
MRI.getType(DstReg);
7800 if (!
MRI.hasOneNonDBGUse(CondReg))
7809 if (True == CmpRHS && False == CmpLHS) {
7817 if (True != CmpLHS || False != CmpRHS)
7857 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7858 Register DestReg =
MI.getOperand(0).getReg();
7859 LLT DestTy =
MRI.getType(DestReg);
7873 if (
isLegal({NewOpc, {DestTy}})) {
7875 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7887 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7890 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7900bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7902 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7903 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7907 unsigned Flags = Logic->
getFlags();
7926 std::optional<ValueAndVReg> MaybeC1 =
7930 C1 = MaybeC1->Value;
7932 std::optional<ValueAndVReg> MaybeC2 =
7936 C2 = MaybeC2->Value;
7957 std::optional<APInt> Offset1;
7958 std::optional<APInt> Offset2;
7961 std::optional<ValueAndVReg> MaybeOffset1 =
7964 R1 =
Add->getLHSReg();
7965 Offset1 = MaybeOffset1->Value;
7969 std::optional<ValueAndVReg> MaybeOffset2 =
7972 R2 =
Add->getLHSReg();
7973 Offset2 = MaybeOffset2->Value;
7992 bool CreateMask =
false;
8005 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
8018 CR->getEquivalentICmp(NewPred, NewC,
Offset);
8027 MatchInfo = [=](MachineIRBuilder &
B) {
8028 if (CreateMask &&
Offset != 0) {
8029 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8030 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8031 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8032 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
8033 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8034 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8035 B.buildZExtOrTrunc(DstReg, ICmp);
8036 }
else if (CreateMask &&
Offset == 0) {
8037 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8038 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8039 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8040 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
8041 B.buildZExtOrTrunc(DstReg, ICmp);
8042 }
else if (!CreateMask &&
Offset != 0) {
8043 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8044 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
8045 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8046 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8047 B.buildZExtOrTrunc(DstReg, ICmp);
8048 }
else if (!CreateMask &&
Offset == 0) {
8049 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8050 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
8051 B.buildZExtOrTrunc(DstReg, ICmp);
8059bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
8065 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8077 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8083 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8084 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8085 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8086 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8097 if (LHS0 == RHS1 && LHS1 == RHS0) {
8103 if (LHS0 == RHS0 && LHS1 == RHS1) {
8107 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8109 MatchInfo = [=](MachineIRBuilder &
B) {
8114 auto False =
B.buildConstant(CmpTy, 0);
8115 B.buildZExtOrTrunc(DestReg, False);
8122 B.buildZExtOrTrunc(DestReg, True);
8124 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8125 B.buildZExtOrTrunc(DestReg, Cmp);
8137 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8140 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8149 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8152 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8167 bool IsSigned =
Add->isSigned();
8168 LLT DstTy =
MRI.getType(Dst);
8169 LLT CarryTy =
MRI.getType(Carry);
8172 if (
MRI.use_nodbg_empty(Carry) &&
8175 B.buildAdd(Dst, LHS, RHS);
8176 B.buildUndef(Carry);
8182 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8185 B.buildSAddo(Dst, Carry, RHS, LHS);
8191 B.buildUAddo(Dst, Carry, RHS, LHS);
8196 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8197 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8203 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8204 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8206 B.buildConstant(Dst, Result);
8207 B.buildConstant(Carry, Overflow);
8215 B.buildCopy(Dst, LHS);
8216 B.buildConstant(Carry, 0);
8225 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8228 std::optional<APInt> MaybeAddRHS =
8229 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8232 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8233 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8237 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8238 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8244 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8245 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8270 B.buildConstant(Carry, 0);
8277 B.buildAdd(Dst, LHS, RHS);
8278 B.buildConstant(Carry, 1);
8290 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8293 B.buildConstant(Carry, 0);
8309 B.buildConstant(Carry, 0);
8316 B.buildAdd(Dst, LHS, RHS);
8317 B.buildConstant(Carry, 1);
8335 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8341 auto [Dst,
Base] =
MI.getFirst2Regs();
8342 LLT Ty =
MRI.getType(Dst);
8346 Builder.buildFConstant(Dst, 1.0);
8347 MI.removeFromParent();
8359 std::optional<SrcOp> Res;
8361 while (ExpVal > 0) {
8366 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8369 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8376 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8380 MI.eraseFromParent();
8391 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8398 LLT DstTy =
MRI.getType(Dst);
8401 auto Const =
B.buildConstant(DstTy, C1 - C2);
8402 B.buildAdd(Dst,
A, Const);
8416 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8423 LLT DstTy =
MRI.getType(Dst);
8426 auto Const =
B.buildConstant(DstTy, C2 - C1);
8427 B.buildSub(Dst, Const,
A);
8448 LLT DstTy =
MRI.getType(Dst);
8451 auto Const =
B.buildConstant(DstTy, C1 + C2);
8452 B.buildSub(Dst,
A, Const);
8473 LLT DstTy =
MRI.getType(Dst);
8476 auto Const =
B.buildConstant(DstTy, C1 - C2);
8477 B.buildSub(Dst, Const,
A);
8491 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8498 LLT DstTy =
MRI.getType(Dst);
8501 auto Const =
B.buildConstant(DstTy, C2 - C1);
8502 B.buildAdd(Dst,
A, Const);
8546 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8554 LLT SmallBvTy = DstTy;
8558 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8563 {TargetOpcode::G_ANYEXT,
8575 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8576 Ops.push_back(AnyExt.getReg(0));
8594 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8595 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8596 const unsigned NumDstElts = OrigMask.
size();
8597 for (
unsigned i = 0; i != NumDstElts; ++i) {
8598 int Idx = OrigMask[i];
8599 if (Idx >= (
int)NumSrcElems) {
8610 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8611 std::move(NewMask));
8618 const unsigned MaskSize = Mask.size();
8619 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8624 if (Idx < (
int)NumElems)
8625 Mask[
I] = Idx + NumElems;
8627 Mask[
I] = Idx - NumElems;
8637 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8640 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8643 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8644 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8646 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8650 const unsigned NumSrcElems = Src1Ty.getNumElements();
8652 bool TouchesSrc1 =
false;
8653 bool TouchesSrc2 =
false;
8654 const unsigned NumElems = Mask.size();
8655 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8659 if (Mask[Idx] < (
int)NumSrcElems)
8665 if (TouchesSrc1 == TouchesSrc2)
8668 Register NewSrc1 = Shuffle.getSrc1Reg();
8671 NewSrc1 = Shuffle.getSrc2Reg();
8676 auto Undef =
B.buildUndef(Src1Ty);
8677 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8691 LLT DstTy =
MRI.getType(Dst);
8692 LLT CarryTy =
MRI.getType(Carry);
8714 B.buildConstant(Carry, 0);
8721 B.buildSub(Dst, LHS, RHS);
8739 B.buildConstant(Carry, 0);
8746 B.buildSub(Dst, LHS, RHS);
8763 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8764 "Expected G_CTLZ variant");
8769 LLT Ty =
MRI.getType(Dst);
8770 LLT SrcTy =
MRI.getType(Src);
8772 if (!(Ty.isValid() && Ty.isScalar()))
8781 switch (
LI->getAction(Query).Action) {
8792 bool NeedAdd =
true;
8800 unsigned BitWidth = Ty.getScalarSizeInBits();
8811 B.buildCTLS(Dst,
X);
8815 auto Ctls =
B.buildCTLS(Ty,
X);
8816 auto One =
B.buildConstant(Ty, 1);
8818 B.buildAdd(Dst, Ctls, One);
8828 unsigned TargetOpc)
const {
8829 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8830 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8831 "Expected G_LSHR/G_ASHR");
8834 return XTy ==
MRI.getType(
Y) &&
isLegal({TargetOpc, {XTy}});
8838 assert((
MI.getOpcode() == TargetOpcode::G_CTLZ ||
8839 MI.getOpcode() == TargetOpcode::G_CTTZ) &&
8840 "Expected count-zero opcode");
8841 switch (
MI.getOpcode()) {
8842 case TargetOpcode::G_CTLZ:
8843 return TargetOpcode::G_CTLZ_ZERO_POISON;
8844 case TargetOpcode::G_CTTZ:
8845 return TargetOpcode::G_CTTZ_ZERO_POISON;
8857 if (!
VT->isKnownNeverZero(Src))
8860 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8861 LLT SrcTy =
MRI.getType(Src);
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 bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static std::optional< unsigned > getMinUselessShift(KnownBits ValueKB, unsigned Opcode, std::optional< int64_t > &Result)
Return the minimum useless shift amount that results in complete loss of the source value.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static unsigned getCountZeroPoisonOpcode(const MachineInstr &MI)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Interface for Targets to specify which operations they can successfully select and how the others sho...
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
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 matchCountZeroToZeroPoison(MachineInstr &MI) 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 matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
LLVM_ABI bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
LLVM_ABI bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchAVG(MachineInstr &MI, MachineRegisterInfo &MRI, Register X, Register Y, unsigned TargetOpc) 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 matchPtrAddZero(MachineInstr &MI) const
}
const TargetInstrInfo * TII
LLVM_ABI void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
LLVM_ABI void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
LLVM_ABI bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
LLVM_ABI bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
LLVM_ABI bool matchShiftsTooBig(MachineInstr &MI, std::optional< int64_t > &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
LLVM_ABI bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
LLVM_ABI void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
LLVM_ABI void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
LLVM_ABI bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
LLVM_ABI void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
LLVM_ABI void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
LLVM_ABI void applyCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo) const
LLVM_ABI bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
LLVM_ABI void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
LLVM_ABI const DataLayout & getDataLayout() const
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 applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) 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 bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
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 void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
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 matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
LLVM_ABI bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
LLVM_ABI void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) 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 matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
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 matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
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 applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
LLVM_ABI bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
LLVM_ABI void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
LLVM_ABI bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
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 matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
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 matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
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 tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
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 matchConstantFoldUnaryIntOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold a unary integer op (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON variants,...
LLVM_ABI void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
LLVM_ABI bool isLegal(const LegalityQuery &Query) const
LLVM_ABI bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
LLVM_ABI bool matchOperandIsKnownToBeAPowerOfTwo(const MachineOperand &MO, bool OrNegative=false) const
Check if operand MO is known to be a power of 2.
LLVM_ABI bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
LLVM_ABI void eraseInst(MachineInstr &MI) const
Erase MI.
LLVM_ABI bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
LLVM_ABI void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
LLVM_ABI void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
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 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 matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
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 matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
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 matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
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 matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) 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 void applyFunnelShiftToRotate(MachineInstr &MI) const
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 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 void applyCountZeroToZeroPoison(MachineInstr &MI) const
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 matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
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 applyCommuteBinOpOperands(MachineInstr &MI) const
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.
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.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
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 a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr ElementCount getElementCount() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
static LLT integer(unsigned SizeInBits)
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
This is an important class for using LLVM in a threaded context.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Helper class to build MachineInstr.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
LLVM_ABI bool isDereferenceableInvariantLoad() const
Return true if this load instruction never traps and points to a memory location whose value doesn't ...
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
mop_range uses()
Returns all operands which may be register uses.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
bool isAtomic() const
Returns true if this operation has an atomic ordering requirement of unordered or higher,...
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
static use_instr_nodbg_iterator use_instr_nodbg_end()
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
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)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
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)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(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)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
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)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a float constant integer or a splat vector of float constant integers.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
@ Load
The value being inserted comes from a load (InsertElement only).
LLVM_ABI 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 matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > OperandBuildSteps
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
std::tuple< Register, Register, uint64_t, Align, bool, std::vector< LLT > > MemCpyFamilyLoweringInfo
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
LLVM_ABI bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
LLVM_ABI std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
LLVM_ABI bool canLowerMemCpyFamily(const MachineInstr &MI, const MachineRegisterInfo &MRI, unsigned MaxLen, Register &Dst, Register &Src, uint64_t &KnownLen, Align &Alignment, bool &DstAlignCanChange, std::vector< LLT > &MemOps)
Matcher for memcpy-like instructions.
LLVM_ABI unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc)
Returns the inverse opcode of MinMaxOpc, which is a generic min/max opcode like G_SMIN.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
constexpr unsigned BitWidth
LLVM_ABI int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
LLVM_ABI SmallVector< APInt > ConstantFoldUnaryIntOp(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Tries to constant fold a unary integer operation (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON vari...
LLVM_ABI bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return true if the given value is known to have exactly one bit set when defined.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Simple struct used to hold a Register value and the instruction which defines it.
SmallVector< InstructionBuildSteps, 2 > InstrsToBuild
Describes instructions to be built during a combine.
bool isNonNegative() const
Returns true if this value is known to be non-negative.
unsigned countMinLeadingOnes() const
Returns the minimum number of leading one bits.
unsigned countMinTrailingZeros() const
Returns the minimum number of trailing zero bits.
bool isUnknown() const
Returns true if we don't know any bits.
unsigned getBitWidth() const
Get the bit width of this value.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
bool isNegative() const
Returns true if this value is known to be negative.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
This class contains a discriminated union of information about pointers in memory operands,...
LLVM_ABI unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
Magic data for optimising signed division by a constant.
unsigned ShiftAmount
shift amount
static LLVM_ABI SignedDivisionByConstantInfo get(const APInt &D)
Calculate the magic numbers required to implement a signed integer division by a constant as a sequen...
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
unsigned PostShift
post-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true, bool AllowWidenOptimization=false)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...