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 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1116 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1117 MI.eraseFromParent();
1121 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1122 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1125 LLT RegTy =
MRI.getType(DstReg);
1138 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1140 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1146 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1149 if (NewSizeBits < 8)
1162 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1167 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1170 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1175 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1176 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1178 unsigned ScalarSizeBits;
1179 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1188 auto &MMO = LoadDef->
getMMO();
1189 Builder.setInstrAndDebugLoc(*LoadDef);
1191 auto PtrInfo = MMO.getPointerInfo();
1192 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1193 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1196 MI.eraseFromParent();
1207 auto *MF =
MI->getMF();
1214 AM.
BaseOffs = CstOff->getSExtValue();
1219 MF->getDataLayout(), AM,
1221 MF->getFunction().getContext()),
1222 MI->getMMO().getAddrSpace());
1227 case TargetOpcode::G_LOAD:
1228 return TargetOpcode::G_INDEXED_LOAD;
1229 case TargetOpcode::G_STORE:
1230 return TargetOpcode::G_INDEXED_STORE;
1231 case TargetOpcode::G_ZEXTLOAD:
1232 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1233 case TargetOpcode::G_SEXTLOAD:
1234 return TargetOpcode::G_INDEXED_SEXTLOAD;
1240bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1250 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1251 OpTys = {PtrTy, Ty, Ty};
1253 OpTys = {Ty, PtrTy};
1255 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1261 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1262 "considered for post-indexing."));
1266 bool &RematOffset)
const {
1279 if (!isIndexedLoadStoreLegal(LdSt))
1290 unsigned NumUsesChecked = 0;
1303 if (StoredValDef == &
Use)
1306 Offset = PtrAdd->getOffsetReg();
1308 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1316 RematOffset =
false;
1320 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1325 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1326 if (&BasePtrUse == PtrDef)
1332 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1334 isIndexedLoadStoreLegal(*BasePtrLdSt))
1340 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1341 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1344 if (BaseUseUse.getParent() != LdSt.
getParent())
1356 Addr = PtrAdd->getReg(0);
1357 Base = PtrAdd->getBaseReg();
1372 MRI.hasOneNonDBGUse(Addr))
1379 if (!isIndexedLoadStoreLegal(LdSt))
1383 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1388 if (
Base == St->getValueReg())
1393 if (St->getValueReg() == Addr)
1398 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1399 if (AddrUse.getParent() != LdSt.
getParent())
1404 bool RealUse =
false;
1405 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1423 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1433 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1440 if (!LoadMI->isSimple())
1452 const unsigned MaxIter = 20;
1455 if (
II->isLoadFoldBarrier())
1457 if (Iter++ == MaxIter)
1473 int Elt = CVal->getZExtValue();
1486 Register VecPtr = LoadMI->getPointerReg();
1487 LLT PtrTy =
MRI.getType(VecPtr);
1495 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1518 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1533 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1535 if (!MatchInfo.
IsPre &&
1536 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1546 unsigned Opcode =
MI.getOpcode();
1547 bool IsStore = Opcode == TargetOpcode::G_STORE;
1553 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1555 *OldCst->getOperand(1).getCImm());
1556 MatchInfo.
Offset = NewCst.getReg(0);
1559 auto MIB =
Builder.buildInstr(NewOpcode);
1561 MIB.addDef(MatchInfo.
Addr);
1562 MIB.addUse(
MI.getOperand(0).getReg());
1564 MIB.addDef(
MI.getOperand(0).getReg());
1565 MIB.addDef(MatchInfo.
Addr);
1568 MIB.addUse(MatchInfo.
Base);
1569 MIB.addUse(MatchInfo.
Offset);
1570 MIB.addImm(MatchInfo.
IsPre);
1571 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1572 MI.eraseFromParent();
1580 unsigned Opcode =
MI.getOpcode();
1581 bool IsDiv, IsSigned;
1586 case TargetOpcode::G_SDIV:
1587 case TargetOpcode::G_UDIV: {
1589 IsSigned = Opcode == TargetOpcode::G_SDIV;
1592 case TargetOpcode::G_SREM:
1593 case TargetOpcode::G_UREM: {
1595 IsSigned = Opcode == TargetOpcode::G_SREM;
1601 unsigned DivOpcode, RemOpcode, DivremOpcode;
1603 DivOpcode = TargetOpcode::G_SDIV;
1604 RemOpcode = TargetOpcode::G_SREM;
1605 DivremOpcode = TargetOpcode::G_SDIVREM;
1607 DivOpcode = TargetOpcode::G_UDIV;
1608 RemOpcode = TargetOpcode::G_UREM;
1609 DivremOpcode = TargetOpcode::G_UDIVREM;
1627 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1628 if (
MI.getParent() ==
UseMI.getParent() &&
1629 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1630 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1643 unsigned Opcode =
MI.getOpcode();
1644 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1647 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1648 DestDivReg =
MI.getOperand(0).getReg();
1652 DestRemReg =
MI.getOperand(0).getReg();
1656 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1663 Builder.setInstrAndDebugLoc(*FirstInst);
1665 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1666 : TargetOpcode::G_UDIVREM,
1667 {DestDivReg, DestRemReg},
1669 MI.eraseFromParent();
1675 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1692 if (BrIt ==
MBB->begin())
1694 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1696 BrCond = &*std::prev(BrIt);
1697 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1703 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1704 MBB->isLayoutSuccessor(BrCondTarget);
1710 Builder.setInstrAndDebugLoc(*BrCond);
1715 auto True =
Builder.buildConstant(
1721 MI.getOperand(0).setMBB(FallthroughBB);
1734 unsigned MaxLen)
const {
1735 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1737 DstAlignCanChange, MemOps);
1742 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1747 DstAlignCanChange, MemOps) ==
1749 assert(
Changed &&
"expected memcpy-family instruction to lower");
1754 unsigned MaxLen)
const {
1766 switch (
MI.getOpcode()) {
1769 case TargetOpcode::G_FNEG: {
1770 Result.changeSign();
1773 case TargetOpcode::G_FABS: {
1777 case TargetOpcode::G_FCEIL:
1780 case TargetOpcode::G_FFLOOR:
1783 case TargetOpcode::G_INTRINSIC_TRUNC:
1786 case TargetOpcode::G_INTRINSIC_ROUND:
1789 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1792 case TargetOpcode::G_FRINT:
1793 case TargetOpcode::G_FNEARBYINT:
1797 case TargetOpcode::G_FPEXT:
1798 case TargetOpcode::G_FPTRUNC: {
1805 case TargetOpcode::G_FSQRT: {
1809 Result =
APFloat(sqrt(Result.convertToDouble()));
1812 case TargetOpcode::G_FLOG2: {
1832 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1833 MI.eraseFromParent();
1844 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1867 Type *AccessTy =
nullptr;
1868 auto &MF = *
MI.getMF();
1869 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1872 MF.getFunction().getContext());
1877 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1882 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1884 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1885 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1886 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1887 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1896 unsigned PtrAddFlags =
MI.getFlags();
1912 MatchInfo.
Flags = Flags;
1918 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1920 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1924 MI.getOperand(1).setReg(MatchInfo.
Base);
1925 MI.getOperand(2).setReg(NewOffset.getReg(0));
1939 unsigned Opcode =
MI.getOpcode();
1940 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1941 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1942 Opcode == TargetOpcode::G_USHLSAT) &&
1943 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1963 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1968 if (Opcode == TargetOpcode::G_USHLSAT &&
1969 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1977 unsigned Opcode =
MI.getOpcode();
1978 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1979 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1980 Opcode == TargetOpcode::G_USHLSAT) &&
1981 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1983 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1984 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1985 auto Imm = MatchInfo.
Imm;
1987 if (
Imm >= ScalarSizeInBits) {
1989 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1990 Builder.buildConstant(
MI.getOperand(0), 0);
1991 MI.eraseFromParent();
1996 Imm = ScalarSizeInBits - 1;
1999 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
2002 MI.getOperand(1).setReg(MatchInfo.
Reg);
2003 MI.getOperand(2).setReg(NewImm);
2019 unsigned ShiftOpcode =
MI.getOpcode();
2020 assert((ShiftOpcode == TargetOpcode::G_SHL ||
2021 ShiftOpcode == TargetOpcode::G_ASHR ||
2022 ShiftOpcode == TargetOpcode::G_LSHR ||
2023 ShiftOpcode == TargetOpcode::G_USHLSAT ||
2024 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
2025 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2028 Register LogicDest =
MI.getOperand(1).getReg();
2029 if (!
MRI.hasOneNonDBGUse(LogicDest))
2035 unsigned LogicOpcode = LogicMI->
getOpcode();
2036 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
2037 LogicOpcode != TargetOpcode::G_XOR)
2041 const Register C1 =
MI.getOperand(2).getReg();
2043 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2046 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2048 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2050 if (
MI->getOpcode() != ShiftOpcode ||
2051 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2060 ShiftVal = MaybeImmVal->Value.getSExtValue();
2074 if (matchFirstShift(LogicMIOp1, C0Val)) {
2076 MatchInfo.
Shift2 = LogicMIOp1;
2077 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2079 MatchInfo.
Shift2 = LogicMIOp2;
2083 MatchInfo.
ValSum = C0Val + C1Val;
2086 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2089 MatchInfo.
Logic = LogicMI;
2095 unsigned Opcode =
MI.getOpcode();
2096 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2097 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2098 Opcode == TargetOpcode::G_SSHLSAT) &&
2099 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2101 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2102 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2108 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2117 Register Shift2Const =
MI.getOperand(2).getReg();
2119 .buildInstr(Opcode, {DestType},
2129 MI.eraseFromParent();
2134 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2159 LLT SrcTy =
MRI.getType(SrcReg);
2161 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2162 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2163 B.buildInstr(SrcOpc, {DstReg}, {
S1, S2});
2171 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2175 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2190 LLT InnerShiftTy =
MRI.getType(InnerShift);
2192 if ((N1C + N001C).ult(InnerShiftSize)) {
2198 if ((N001C + OpSizeInBits) == InnerShiftSize)
2200 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2201 MatchInfo.
Mask =
true;
2211 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2218 if (MatchInfo.
Mask ==
true) {
2226 Builder.buildTrunc(Dst, Shift);
2227 MI.eraseFromParent();
2231 unsigned &ShiftVal)
const {
2232 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2238 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2239 return (
static_cast<int32_t
>(ShiftVal) != -1);
2243 unsigned &ShiftVal)
const {
2244 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2246 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2249 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2250 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2271 auto NegCst =
B.buildConstant(Ty, -
Imm);
2273 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2274 MI.getOperand(2).setReg(NegCst.getReg(0));
2276 if (
Imm.isMinSignedValue())
2286 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2300 if (!MaybeShiftAmtVal)
2304 LLT SrcTy =
MRI.getType(ExtSrc);
2314 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2315 MatchData.
Reg = ExtSrc;
2316 MatchData.
Imm = ShiftAmt;
2318 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2319 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2320 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2326 int64_t ShiftAmtVal = MatchData.
Imm;
2328 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2329 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2331 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2332 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2333 MI.eraseFromParent();
2340 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2344 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2347 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2348 if (MergedValues[
I] != Unmerge->getReg(
I))
2351 MatchInfo = Unmerge->getSourceReg();
2365 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2366 "Expected an unmerge");
2375 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2376 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2378 if (SrcMergeTy != Dst0Ty && !SameSize)
2382 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2383 Operands.push_back(SrcInstr->getSourceReg(Idx));
2389 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2390 "Expected an unmerge");
2392 "Not enough operands to replace all defs");
2393 unsigned NumElems =
MI.getNumOperands() - 1;
2396 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2397 bool CanReuseInputDirectly = DstTy == SrcTy;
2398 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2399 Register DstReg =
MI.getOperand(Idx).getReg();
2404 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2405 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2406 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2407 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2410 if (CanReuseInputDirectly)
2413 Builder.buildCast(DstReg, SrcReg);
2415 MI.eraseFromParent();
2420 unsigned SrcIdx =
MI.getNumOperands() - 1;
2421 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2427 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2430 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2432 Val = Val.
lshr(ShiftAmt);
2440 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2441 "Expected an unmerge");
2443 "Not enough operands to replace all defs");
2444 unsigned NumElems =
MI.getNumOperands() - 1;
2445 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2446 Register DstReg =
MI.getOperand(Idx).getReg();
2447 Builder.buildConstant(DstReg, Csts[Idx]);
2450 MI.eraseFromParent();
2456 unsigned SrcIdx =
MI.getNumOperands() - 1;
2457 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2459 unsigned NumElems =
MI.getNumOperands() - 1;
2460 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2461 Register DstReg =
MI.getOperand(Idx).getReg();
2462 B.buildUndef(DstReg);
2470 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2471 "Expected an unmerge");
2472 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2473 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2476 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2477 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2485 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2486 Register Dst0Reg =
MI.getOperand(0).getReg();
2487 Builder.buildTrunc(Dst0Reg, SrcReg);
2488 MI.eraseFromParent();
2492 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2493 "Expected an unmerge");
2494 Register Dst0Reg =
MI.getOperand(0).getReg();
2495 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2501 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2502 LLT SrcTy =
MRI.getType(SrcReg);
2503 if (SrcTy.isVector())
2513 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2518 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2519 "Expected an unmerge");
2521 Register Dst0Reg =
MI.getOperand(0).getReg();
2526 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2527 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2530 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2533 "ZExt src doesn't fit in destination");
2538 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2540 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2543 MI.eraseFromParent();
2547 unsigned TargetShiftSize,
2548 unsigned &ShiftVal)
const {
2549 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2550 MI.getOpcode() == TargetOpcode::G_LSHR ||
2551 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2553 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2558 unsigned Size = Ty.getSizeInBits();
2559 if (
Size <= TargetShiftSize)
2567 ShiftVal = MaybeImmVal->Value.getSExtValue();
2568 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2575 LLT Ty =
MRI.getType(SrcReg);
2576 unsigned Size = Ty.getSizeInBits();
2577 unsigned HalfSize =
Size / 2;
2578 assert(ShiftVal >= HalfSize);
2582 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2583 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2585 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2586 Register Narrowed = Unmerge.getReg(1);
2593 if (NarrowShiftAmt != 0) {
2594 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2595 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2598 auto Zero =
Builder.buildConstant(HalfTy, 0);
2599 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2600 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2601 Register Narrowed = Unmerge.getReg(0);
2606 if (NarrowShiftAmt != 0) {
2607 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2608 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2611 auto Zero =
Builder.buildConstant(HalfTy, 0);
2612 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2614 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2616 HalfTy, Unmerge.getReg(1),
2617 Builder.buildConstant(HalfTy, HalfSize - 1));
2619 if (ShiftVal == HalfSize) {
2622 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2623 }
else if (ShiftVal ==
Size - 1) {
2631 HalfTy, Unmerge.getReg(1),
2632 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2640 MI.eraseFromParent();
2656 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2658 LLT DstTy =
MRI.getType(DstReg);
2666 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2668 Builder.buildCopy(DstReg, Reg);
2669 MI.eraseFromParent();
2674 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2676 Builder.buildZExtOrTrunc(DstReg, Reg);
2677 MI.eraseFromParent();
2682 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2685 LLT IntTy =
MRI.getType(LHS);
2689 PtrReg.second =
false;
2690 for (
Register SrcReg : {LHS, RHS}) {
2694 LLT PtrTy =
MRI.getType(PtrReg.first);
2699 PtrReg.second =
true;
2711 const bool DoCommute = PtrReg.second;
2716 LLT PtrTy =
MRI.getType(LHS);
2718 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2719 Builder.buildPtrToInt(Dst, PtrAdd);
2720 MI.eraseFromParent();
2724 APInt &NewCst)
const {
2726 Register LHS = PtrAdd.getBaseReg();
2727 Register RHS = PtrAdd.getOffsetReg();
2733 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2736 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2745 APInt &NewCst)
const {
2749 Builder.buildConstant(Dst, NewCst);
2750 PtrAdd.eraseFromParent();
2755 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2760 SrcReg = OriginalSrcReg;
2761 LLT DstTy =
MRI.getType(DstReg);
2769 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2772 LLT DstTy =
MRI.getType(DstReg);
2777 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2778 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2788 if (ShiftSize > 32 && TruncSize < 32)
2801 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2802 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2806 if (!
MRI.hasOneNonDBGUse(SrcReg))
2809 LLT SrcTy =
MRI.getType(SrcReg);
2810 LLT DstTy =
MRI.getType(DstReg);
2819 case TargetOpcode::G_SHL: {
2828 case TargetOpcode::G_LSHR:
2829 case TargetOpcode::G_ASHR: {
2835 for (
auto &
User :
MRI.use_instructions(DstReg))
2836 if (
User.getOpcode() == TargetOpcode::G_STORE)
2840 if (NewShiftTy == SrcTy)
2854 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2857 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2862 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2864 LLT NewShiftTy = MatchInfo.second;
2867 LLT DstTy =
MRI.getType(Dst);
2871 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2874 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2875 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2876 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2880 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2883 if (NewShiftTy == DstTy)
2886 Builder.buildTrunc(Dst, NewShift);
2893 return MO.isReg() &&
2894 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2900 return !MO.isReg() ||
2901 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2906 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2908 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2912 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2913 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2918 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2919 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2925 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2926 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2927 "Expected an insert/extract element op");
2928 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2933 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2941 unsigned &OpIdx)
const {
2946 OpIdx = Cst->isZero() ? 3 : 2;
2991 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
3018 return MO.isReg() && MO.getReg().isPhysical();
3028 return I1->isIdenticalTo(*I2);
3036 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
3043 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
3054 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
3055 MaybeCst->getSExtValue() ==
C;
3062 std::optional<FPValueAndVReg> MaybeCst;
3066 return MaybeCst->Value.isExactlyValue(
C);
3070 unsigned OpIdx)
const {
3071 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3073 Register Replacement =
MI.getOperand(OpIdx).getReg();
3076 MI.eraseFromParent();
3081 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
3085 MI.eraseFromParent();
3089 unsigned ConstIdx)
const {
3090 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3091 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3103 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3104 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3105 "This is not a funnel shift operation");
3107 Register ConstReg =
MI.getOperand(3).getReg();
3108 LLT ConstTy =
MRI.getType(ConstReg);
3109 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3112 assert((VRegAndVal) &&
"Value is not a constant");
3115 APInt NewConst = VRegAndVal->Value.
urem(
3120 MI.getOpcode(), {MI.getOperand(0)},
3121 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3123 MI.eraseFromParent();
3127 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3141 unsigned OpIdx)
const {
3143 return MO.
isReg() &&
3154 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3156 MI.eraseFromParent();
3161 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3163 MI.eraseFromParent();
3167 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3169 MI.eraseFromParent();
3174 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3176 MI.eraseFromParent();
3180 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3182 MI.eraseFromParent();
3186 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3189 Register &NewLHS = std::get<0>(MatchInfo);
3190 Register &NewRHS = std::get<1>(MatchInfo);
3198 NewLHS = MaybeNewLHS;
3202 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3207 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3210 LLT DstTy =
MRI.getType(DstReg);
3219 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3220 TargetOpcode::G_INSERT_VECTOR_ELT)
3226 MatchInfo.
resize(NumElts);
3230 if (IntImm >= NumElts || IntImm < 0)
3232 if (!MatchInfo[IntImm])
3233 MatchInfo[IntImm] = TmpReg;
3237 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3239 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3248 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3255 auto GetUndef = [&]() {
3258 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3266 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3267 MI.eraseFromParent();
3271 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3273 std::tie(SubLHS, SubRHS) = MatchInfo;
3274 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3275 MI.eraseFromParent();
3288 unsigned InnerOpc = InnerDef->
getOpcode();
3289 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3313 if (!TryMatch(InnerLHS, InnerRHS) &&
3314 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3318 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3319 : TargetOpcode::G_ADD;
3322 MatchInfo = [=](MachineIRBuilder &
Builder) {
3323 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3324 auto NewNot =
Builder.buildNot(Ty, NewInner);
3325 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3337 unsigned RootOpc =
MI.getOpcode();
3339 LLT Ty =
MRI.getType(Dst);
3344 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3345 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3356 unsigned LogicOpcode =
MI.getOpcode();
3357 assert(LogicOpcode == TargetOpcode::G_AND ||
3358 LogicOpcode == TargetOpcode::G_OR ||
3359 LogicOpcode == TargetOpcode::G_XOR);
3366 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3372 if (!LeftHandInst || !RightHandInst)
3374 unsigned HandOpcode = LeftHandInst->
getOpcode();
3375 if (HandOpcode != RightHandInst->
getOpcode())
3389 if (!XTy.
isValid() || XTy != YTy)
3394 switch (HandOpcode) {
3397 case TargetOpcode::G_ANYEXT:
3398 case TargetOpcode::G_SEXT:
3399 case TargetOpcode::G_ZEXT: {
3403 case TargetOpcode::G_TRUNC: {
3408 LLT DstTy =
MRI.getType(Dst);
3417 case TargetOpcode::G_AND:
3418 case TargetOpcode::G_ASHR:
3419 case TargetOpcode::G_LSHR:
3420 case TargetOpcode::G_SHL: {
3425 ExtraHandOpSrcReg = ZOp.
getReg();
3436 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3447 if (ExtraHandOpSrcReg.
isValid())
3459 "Expected at least one instr to build?");
3461 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3462 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3464 for (
auto &OperandFn : InstrToBuild.OperandFns)
3467 MI.eraseFromParent();
3471 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3472 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3473 int64_t ShlCst, AshrCst;
3479 if (ShlCst != AshrCst)
3482 {TargetOpcode::G_SEXT_INREG,
3485 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3487 MatchInfo = std::make_tuple(Src, ShlCst);
3492 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3493 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3496 std::tie(Src, ShiftAmt) = MatchInfo;
3497 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3498 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3499 MI.eraseFromParent();
3506 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3509 LLT Ty =
MRI.getType(Dst);
3521 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3524 auto Zero =
B.buildConstant(Ty, 0);
3547 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3571 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3578 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3595 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3613 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3620 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3631 unsigned ExtBits =
MI.getOperand(2).getImm();
3632 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3633 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3637 int64_t Cst,
bool IsVector,
bool IsFP) {
3639 return (ScalarSizeBits == 1 && Cst == -1) ||
3661 unsigned BuildUseCount = BV.getNumSources();
3662 if (BuildUseCount % 2 != 0)
3665 unsigned NumUnmerge = BuildUseCount / 2;
3671 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3674 UnmergeSrc = Unmerge->getSourceReg();
3676 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3677 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3684 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3689 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3690 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3693 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3696 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3701 if (Unmerge->getNumDefs() != NumUnmerge)
3705 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3708 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3719 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3720 B.setInstrAndDebugLoc(
MI);
3722 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3723 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3725 MI.eraseFromParent();
3747 unsigned NumOperands =
BuildMI->getNumSources();
3757 for (
I = 0;
I < NumOperands; ++
I) {
3769 UnmergeMI != UnmergeSrcMI)
3780 for (;
I < NumOperands; ++
I) {
3787 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3794 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3795 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3803 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3806 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3818 LLT DstTy =
MRI.getType(DstReg);
3819 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3824 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3829 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3833 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3836 Builder.buildTrunc(DstReg, MidReg);
3837 MI.eraseFromParent();
3842 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3843 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3844 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3852 if (!
MRI.hasOneNonDBGUse(XorSrc))
3862 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3864 if (!
MRI.hasOneNonDBGUse(Reg))
3869 switch (Def->getOpcode()) {
3874 case TargetOpcode::G_ICMP:
3880 case TargetOpcode::G_FCMP:
3886 case TargetOpcode::G_AND:
3887 case TargetOpcode::G_OR:
3893 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3894 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3902 if (Ty.isVector()) {
3906 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), SplatCst,
true, IsFP))
3920 for (
Register Reg : RegsToNegate) {
3925 switch (Def->getOpcode()) {
3928 case TargetOpcode::G_ICMP:
3929 case TargetOpcode::G_FCMP: {
3936 case TargetOpcode::G_AND:
3937 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3939 case TargetOpcode::G_OR:
3940 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3947 MI.eraseFromParent();
3951 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3953 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3957 Register SharedReg =
MI.getOperand(2).getReg();
3971 if (!
MRI.hasOneNonDBGUse(AndReg))
3978 return Y == SharedReg;
3982 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3985 std::tie(
X,
Y) = MatchInfo;
3988 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3989 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3990 MI.getOperand(2).setReg(
Y);
3996 Register DstReg = PtrAdd.getReg(0);
3997 LLT Ty =
MRI.getType(DstReg);
4000 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
4003 if (Ty.isPointer()) {
4005 return ConstVal && *ConstVal == 0;
4008 assert(Ty.isVector() &&
"Expecting a vector type");
4017 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
4018 PtrAdd.eraseFromParent();
4025 Register Pow2Src1 =
MI.getOperand(2).getReg();
4026 LLT Ty =
MRI.getType(DstReg);
4029 auto NegOne =
Builder.buildConstant(Ty, -1);
4030 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
4032 MI.eraseFromParent();
4036 unsigned &SelectOpNo)
const {
4048 !
MRI.hasOneNonDBGUse(LHS)) {
4049 OtherOperandReg = LHS;
4053 !
MRI.hasOneNonDBGUse(RHS))
4071 unsigned BinOpcode =
MI.getOpcode();
4076 bool CanFoldNonConst =
4077 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
4082 if (CanFoldNonConst)
4107 LLT Ty =
MRI.getType(Dst);
4108 unsigned BinOpcode =
MI.getOpcode();
4115 if (SelectOperand == 1) {
4119 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
4121 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
4123 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
4125 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
4128 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
4129 MI.eraseFromParent();
4132std::optional<SmallVector<Register, 8>>
4133CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
4134 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
4163 const unsigned MaxIter =
4165 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4174 return std::nullopt;
4190 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4191 return std::nullopt;
4203static std::optional<std::pair<GZExtLoad *, int64_t>>
4207 "Expected Reg to only have one non-debug use?");
4216 if (Shift % MemSizeInBits != 0)
4217 return std::nullopt;
4222 return std::nullopt;
4224 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
4225 return std::nullopt;
4227 return std::make_pair(
Load, Shift / MemSizeInBits);
4230std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4231CombinerHelper::findLoadOffsetsForLoadOrCombine(
4234 const unsigned MemSizeInBits)
const {
4237 SmallSetVector<const MachineInstr *, 8> Loads;
4243 GZExtLoad *LowestIdxLoad =
nullptr;
4246 SmallSet<int64_t, 8> SeenIdx;
4250 MachineBasicBlock *
MBB =
nullptr;
4251 const MachineMemOperand *MMO =
nullptr;
4254 GZExtLoad *EarliestLoad =
nullptr;
4257 GZExtLoad *LatestLoad =
nullptr;
4266 for (
auto Reg : RegsToVisit) {
4271 return std::nullopt;
4274 std::tie(
Load, DstPos) = *LoadAndPos;
4278 MachineBasicBlock *LoadMBB =
Load->getParent();
4282 return std::nullopt;
4285 auto &LoadMMO =
Load->getMMO();
4289 return std::nullopt;
4296 LoadPtr =
Load->getOperand(1).getReg();
4301 if (!SeenIdx.
insert(Idx).second)
4302 return std::nullopt;
4309 if (BasePtr != LoadPtr)
4310 return std::nullopt;
4312 if (Idx < LowestIdx) {
4314 LowestIdxLoad =
Load;
4321 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4322 return std::nullopt;
4331 EarliestLoad =
Load;
4339 "Expected to find a load for each register?");
4340 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4341 LatestLoad &&
"Expected at least two loads?");
4350 const unsigned MaxIter = 20;
4356 if (
MI.isLoadFoldBarrier())
4357 return std::nullopt;
4358 if (Iter++ == MaxIter)
4359 return std::nullopt;
4362 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4368 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4381 LLT Ty =
MRI.getType(Dst);
4387 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4388 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4392 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4399 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4400 if (NarrowMemSizeInBits % 8 != 0)
4413 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4414 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4417 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4424 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4427 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4439 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4440 const unsigned ZeroByteOffset =
4444 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4445 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4446 ZeroOffsetIdx->second != LowestIdx)
4456 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4470 MIB.setInstrAndDebugLoc(*LatestLoad);
4471 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4472 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4474 MIB.buildBSwap(Dst, LoadDst);
4486 if (
MRI.getType(DstReg).isVector())
4490 if (!
MRI.hasOneNonDBGUse(DstReg))
4492 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4494 case TargetOpcode::G_ANYEXT:
4496 case TargetOpcode::G_ZEXT:
4497 case TargetOpcode::G_SEXT:
4504 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4511 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4513 switch (
DefMI->getOpcode()) {
4514 case TargetOpcode::G_LOAD:
4515 case TargetOpcode::G_TRUNC:
4516 case TargetOpcode::G_SEXT:
4517 case TargetOpcode::G_ZEXT:
4518 case TargetOpcode::G_ANYEXT:
4519 case TargetOpcode::G_CONSTANT:
4523 if (InSrcs.
size() > 2)
4537 LLT ExtTy =
MRI.getType(DstReg);
4544 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4545 auto SrcReg =
PHI.getIncomingValue(
I);
4549 if (!SrcMIs.
insert(SrcMI))
4555 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4556 InsertPt =
MBB->getFirstNonPHI();
4561 OldToNewSrcMap[SrcMI] = NewExt;
4566 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4567 NewPhi.addDef(DstReg);
4570 NewPhi.addMBB(MO.getMBB());
4573 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4574 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4582 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4586 LLT SrcTy =
MRI.getType(SrcVec);
4587 if (SrcTy.isScalableVector())
4591 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4594 unsigned VecIdx = Cst->Value.getZExtValue();
4606 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4607 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4611 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4623 LLT ScalarTy =
MRI.getType(Reg);
4625 LLT DstTy =
MRI.getType(DstReg);
4627 if (ScalarTy != DstTy) {
4629 Builder.buildTrunc(DstReg, Reg);
4630 MI.eraseFromParent();
4638 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4639 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4657 LLT DstTy =
MRI.getType(DstReg);
4662 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4667 unsigned Idx = Cst->getZExtValue();
4670 ExtractedElts.
set(Idx);
4671 SrcDstPairs.emplace_back(
4672 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4675 return ExtractedElts.
all();
4680 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4681 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4682 for (
auto &Pair : SrcDstPairs) {
4683 auto *ExtMI = Pair.second;
4685 ExtMI->eraseFromParent();
4687 MI.eraseFromParent();
4694 MI.eraseFromParent();
4704 bool AllowScalarConstants,
4706 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4709 LLT Ty =
MRI.getType(Dst);
4710 unsigned BitWidth = Ty.getScalarSizeInBits();
4712 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4713 unsigned FshOpc = 0;
4724 int64_t CstShlAmt = 0, CstLShrAmt;
4727 CstShlAmt + CstLShrAmt ==
BitWidth) {
4728 FshOpc = TargetOpcode::G_FSHR;
4734 FshOpc = TargetOpcode::G_FSHL;
4739 FshOpc = TargetOpcode::G_FSHR;
4744 LLT AmtTy =
MRI.getType(Amt);
4746 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4750 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4757 unsigned Opc =
MI.getOpcode();
4758 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4763 unsigned RotateOpc =
4764 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4769 unsigned Opc =
MI.getOpcode();
4770 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4771 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4773 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4774 : TargetOpcode::G_ROTR));
4775 MI.removeOperand(2);
4781 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4782 MI.getOpcode() == TargetOpcode::G_ROTR);
4784 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4786 bool OutOfRange =
false;
4787 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4789 OutOfRange |= CI->getValue().uge(Bitsize);
4796 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4797 MI.getOpcode() == TargetOpcode::G_ROTR);
4799 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4801 LLT AmtTy =
MRI.getType(Amt);
4802 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4803 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4805 MI.getOperand(2).setReg(Amt);
4810 int64_t &MatchInfo)
const {
4811 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4822 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4823 if (KnownRHS.isUnknown())
4826 std::optional<bool> KnownVal;
4827 if (KnownRHS.isZero()) {
4837 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4847 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4856 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4872 LLT DstTy =
MRI.getType(Dst);
4880 auto KnownLHS =
VT->getKnownBits(LHS);
4881 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4884 LLT LHSTy =
MRI.getType(LHS);
4887 unsigned Op = TargetOpcode::COPY;
4888 if (DstSize != LHSSize)
4889 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4900 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4904 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4910 int64_t AndMaskBits;
4918 if (AndMaskBits & OrMaskBits)
4924 if (
MI.getOperand(1).getReg() == AndMaskReg)
4925 MI.getOperand(2).setReg(AndMaskReg);
4926 MI.getOperand(1).setReg(Src);
4936 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4939 LLT Ty =
MRI.getType(Src);
4941 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4943 int64_t Width =
MI.getOperand(2).getImm();
4951 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4955 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4956 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4957 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4967 LLT Ty =
MRI.getType(Dst);
4971 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4974 int64_t AndImm, LSBImm;
4976 const unsigned Size = Ty.getScalarSizeInBits();
4983 auto MaybeMask =
static_cast<uint64_t
>(AndImm);
4984 if (MaybeMask & (MaybeMask + 1))
4988 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4993 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4994 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4995 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
5003 const unsigned Opcode =
MI.getOpcode();
5004 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
5006 const Register Dst =
MI.getOperand(0).getReg();
5008 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
5009 ? TargetOpcode::G_SBFX
5010 : TargetOpcode::G_UBFX;
5013 LLT Ty =
MRI.getType(Dst);
5015 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
5021 const unsigned Size = Ty.getScalarSizeInBits();
5031 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
5035 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
5039 const int64_t Pos = ShrAmt - ShlAmt;
5040 const int64_t Width =
Size - ShrAmt;
5043 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5044 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5045 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
5053 const unsigned Opcode =
MI.getOpcode();
5054 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
5056 const Register Dst =
MI.getOperand(0).getReg();
5057 LLT Ty =
MRI.getType(Dst);
5059 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
5072 const unsigned Size = Ty.getScalarSizeInBits();
5073 if (ShrAmt < 0 || ShrAmt >=
Size)
5077 if (0 == (SMask >> ShrAmt)) {
5079 B.buildConstant(Dst, 0);
5092 const int64_t Pos = ShrAmt;
5097 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
5101 auto WidthCst =
B.buildConstant(ExtractTy, Width);
5102 auto PosCst =
B.buildConstant(ExtractTy, Pos);
5103 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
5108bool CombinerHelper::reassociationCanBreakAddressingModePattern(
5112 Register Src1Reg = PtrAdd.getBaseReg();
5117 Register Src2Reg = PtrAdd.getOffsetReg();
5119 if (
MRI.hasOneNonDBGUse(Src1Reg))
5129 const APInt &C1APIntVal = *C1;
5130 const APInt &C2APIntVal = *C2;
5131 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
5133 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
5136 MachineInstr *ConvUseMI = &
UseMI;
5137 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
5138 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
5139 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
5141 if (!
MRI.hasOneNonDBGUse(DefReg))
5143 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
5152 TargetLoweringBase::AddrMode AM;
5155 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
5157 PtrAdd.getMF()->getFunction().getContext());
5158 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
5159 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5165 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5177 Register Src1Reg =
MI.getOperand(1).getReg();
5178 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5190 unsigned PtrAddFlags =
MI.getFlags();
5191 unsigned AddFlags = RHS->getFlags();
5204 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5207 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5209 MI.getOperand(1).setReg(NewBase.getReg(0));
5210 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5214 return !reassociationCanBreakAddressingModePattern(
MI);
5224 std::optional<ValueAndVReg> LHSCstOff;
5234 unsigned PtrAddFlags =
MI.getFlags();
5235 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5237 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5239 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5253 LHSPtrAdd->moveBefore(&
MI);
5256 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5258 MI.getOperand(2).setReg(NewCst.getReg(0));
5261 Observer.changingInstr(*LHSPtrAdd);
5262 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5263 LHSPtrAdd->setFlags(Flags);
5266 return !reassociationCanBreakAddressingModePattern(
MI);
5277 Register Src2Reg =
MI.getOperand(2).getReg();
5278 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5279 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5292 unsigned PtrAddFlags =
MI.getFlags();
5293 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5306 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5308 MI.getOperand(1).setReg(LHSSrc1);
5309 MI.getOperand(2).setReg(NewCst.getReg(0));
5313 return !reassociationCanBreakAddressingModePattern(
MI);
5353 LLT OpRHSTy =
MRI.getType(OpRHS);
5370 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5371 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5379 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5380 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5393 unsigned Opc =
MI.getOpcode();
5406 APInt &MatchInfo)
const {
5407 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5411 MatchInfo = *MaybeCst;
5422 MI.getOperand(1).getReg(),
MRI);
5427 if (Csts.size() == 1)
5428 B.buildConstant(Dst, Csts[0]);
5430 B.buildBuildVectorConstant(Dst, Csts);
5436 APInt &MatchInfo)
const {
5442 MatchInfo = *MaybeCst;
5454 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5460 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5461 MI.getOpcode() == TargetOpcode::G_FMAD);
5462 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5479 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5502 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5506 LLT WideTy =
MRI.getType(Dst);
5510 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5526 case TargetOpcode::G_ADD:
5527 case TargetOpcode::G_SUB:
5528 case TargetOpcode::G_MUL:
5529 case TargetOpcode::G_AND:
5530 case TargetOpcode::G_OR:
5531 case TargetOpcode::G_XOR:
5539 auto Mask = Cst->Value;
5544 unsigned NarrowWidth = Mask.countr_one();
5550 auto &MF = *
MI.getMF();
5553 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5554 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5562 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5563 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5565 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5566 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5568 MI.getOperand(1).setReg(Ext.getReg(0));
5576 unsigned Opc =
MI.getOpcode();
5577 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5584 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5585 : TargetOpcode::G_SADDO;
5586 MI.setDesc(
Builder.getTII().get(NewOpc));
5587 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5596 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5597 MI.getOpcode() == TargetOpcode::G_SMULO);
5606 B.buildConstant(Dst, 0);
5607 B.buildConstant(Carry, 0);
5616 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5617 MI.getOpcode() == TargetOpcode::G_SADDE ||
5618 MI.getOpcode() == TargetOpcode::G_USUBE ||
5619 MI.getOpcode() == TargetOpcode::G_SSUBE);
5624 switch (
MI.getOpcode()) {
5625 case TargetOpcode::G_UADDE:
5626 NewOpcode = TargetOpcode::G_UADDO;
5628 case TargetOpcode::G_SADDE:
5629 NewOpcode = TargetOpcode::G_SADDO;
5631 case TargetOpcode::G_USUBE:
5632 NewOpcode = TargetOpcode::G_USUBO;
5634 case TargetOpcode::G_SSUBE:
5635 NewOpcode = TargetOpcode::G_SSUBO;
5639 MI.setDesc(
B.getTII().get(NewOpcode));
5640 MI.removeOperand(4);
5648 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5681 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5682 B.buildSub(Dst, Zero, ReplaceReg);
5691 unsigned Opcode =
MI.getOpcode();
5692 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5694 Register Dst = UDivorRem.getReg(0);
5695 Register LHS = UDivorRem.getReg(1);
5696 Register RHS = UDivorRem.getReg(2);
5697 LLT Ty =
MRI.getType(Dst);
5705 bool UseSRL =
false;
5710 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5712 if (IsSplat && !Factors.
empty()) {
5719 APInt Divisor = CI->getValue();
5728 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5729 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5739 if (Ty.isVector()) {
5740 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5741 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5744 Factor = Factors[0];
5752 return MIB.buildMul(Ty, Res, Factor);
5755 unsigned KnownLeadingZeros =
5756 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5758 bool UseNPQ =
false;
5760 auto BuildUDIVPattern = [&](
const Constant *
C) {
5762 const APInt &Divisor = CI->getValue();
5764 bool SelNPQ =
false;
5766 unsigned PreShift = 0, PostShift = 0;
5771 if (!Divisor.
isOne()) {
5777 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5779 Magic = std::move(magics.
Magic);
5782 "We shouldn't generate an undefined shift!");
5784 "We shouldn't generate an undefined shift!");
5788 SelNPQ = magics.
IsAdd;
5792 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5793 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5795 MIB.buildConstant(ScalarTy,
5800 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5808 assert(Matched &&
"Expected unary predicate match to succeed");
5810 Register PreShift, PostShift, MagicFactor, NPQFactor;
5813 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5814 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5815 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5816 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5819 "Non-build_vector operation should have been a scalar");
5820 PreShift = PreShifts[0];
5821 MagicFactor = MagicFactors[0];
5822 PostShift = PostShifts[0];
5826 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5829 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5832 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5837 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5839 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5841 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5844 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5845 auto One = MIB.buildConstant(Ty, 1);
5846 auto IsOne = MIB.buildICmp(
5850 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5852 if (Opcode == TargetOpcode::G_UREM) {
5853 auto Prod = MIB.buildMul(Ty, ret, RHS);
5854 return MIB.buildSub(Ty, LHS, Prod);
5860 unsigned Opcode =
MI.getOpcode();
5861 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5864 LLT DstTy =
MRI.getType(Dst);
5866 auto &MF = *
MI.getMF();
5867 AttributeList Attr = MF.getFunction().getAttributes();
5876 if (MF.getFunction().hasMinSize())
5879 if (Opcode == TargetOpcode::G_UDIV &&
5882 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5897 {TargetOpcode::G_ICMP,
5901 if (Opcode == TargetOpcode::G_UREM &&
5907 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5916 unsigned Opcode =
MI.getOpcode();
5917 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5920 LLT DstTy =
MRI.getType(Dst);
5924 auto &MF = *
MI.getMF();
5925 AttributeList Attr = MF.getFunction().getAttributes();
5934 if (MF.getFunction().hasMinSize())
5938 if (Opcode == TargetOpcode::G_SDIV &&
5941 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5953 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5956 if (Opcode == TargetOpcode::G_SREM &&
5962 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5971 unsigned Opcode =
MI.getOpcode();
5972 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5973 Opcode == TargetOpcode::G_SREM);
5975 Register Dst = SDivorRem.getReg(0);
5976 Register LHS = SDivorRem.getReg(1);
5977 Register RHS = SDivorRem.getReg(2);
5978 LLT Ty =
MRI.getType(Dst);
5985 bool UseSRA =
false;
5991 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5993 if (IsSplat && !ExactFactors.
empty()) {
5995 ExactFactors.
push_back(ExactFactors[0]);
6000 APInt Divisor = CI->getValue();
6010 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
6011 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
6019 assert(Matched &&
"Expected unary predicate match to succeed");
6022 if (Ty.isVector()) {
6023 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
6024 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
6026 Shift = ExactShifts[0];
6027 Factor = ExactFactors[0];
6035 return MIB.buildMul(Ty, Res, Factor);
6040 auto BuildSDIVPattern = [&](
const Constant *
C) {
6042 const APInt &Divisor = CI->getValue();
6046 int NumeratorFactor = 0;
6057 NumeratorFactor = 1;
6060 NumeratorFactor = -1;
6063 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
6064 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
6066 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
6067 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
6075 assert(Matched &&
"Expected unary predicate match to succeed");
6077 Register MagicFactor, Factor, Shift, ShiftMask;
6080 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
6081 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
6082 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
6083 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
6086 "Non-build_vector operation should have been a scalar");
6087 MagicFactor = MagicFactors[0];
6088 Factor = Factors[0];
6090 ShiftMask = ShiftMasks[0];
6094 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
6097 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
6098 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
6101 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
6104 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
6105 auto T = MIB.buildLShr(Ty, Q, SignShift);
6106 T = MIB.buildAnd(Ty,
T, ShiftMask);
6107 auto ret = MIB.buildAdd(Ty, Q,
T);
6109 if (Opcode == TargetOpcode::G_SREM) {
6110 auto Prod = MIB.buildMul(Ty, ret, RHS);
6111 return MIB.buildSub(Ty, LHS, Prod);
6117 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
6118 MI.getOpcode() == TargetOpcode::G_UDIV) &&
6119 "Expected SDIV or UDIV");
6122 auto MatchPow2 = [&](
const Constant *
C) {
6124 return CI && (CI->getValue().isPowerOf2() ||
6125 (IsSigned && CI->getValue().isNegatedPowerOf2()));
6131 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
6136 LLT Ty =
MRI.getType(Dst);
6156 unsigned BitWidth = Ty.getScalarSizeInBits();
6157 auto Zero =
Builder.buildConstant(Ty, 0);
6160 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6161 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
6163 auto Sign =
Builder.buildAShr(
6167 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
6173 auto One =
Builder.buildConstant(Ty, 1);
6174 auto MinusOne =
Builder.buildConstant(Ty, -1);
6178 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
6179 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
6183 auto Neg =
Builder.buildNeg(Ty, AShr);
6185 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
6186 MI.eraseFromParent();
6190 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
6195 LLT Ty =
MRI.getType(Dst);
6198 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6199 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6200 MI.eraseFromParent();
6204 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6209 LLT Ty =
MRI.getType(Dst);
6228 unsigned BitWidth = Ty.getScalarSizeInBits();
6229 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6230 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6232 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6233 auto Bias =
Builder.buildAnd(Ty, Sign, Mask);
6234 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6237 MI.eraseFromParent();
6241 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6244 LLT Ty =
MRI.getType(Dst);
6245 LLT RHSTy =
MRI.getType(RHS);
6247 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6249 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6264 LLT Ty =
MRI.getType(Dst);
6270 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6271 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6272 Builder.buildLShr(Dst, LHS, Trunc);
6273 MI.eraseFromParent();
6280 LLT DstTy =
MRI.getType(Dst);
6281 LLT SrcTy =
MRI.getType(Src);
6283 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6284 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6287 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6316 Builder.buildTruncSSatS(Dst, MatchInfo);
6317 MI.eraseFromParent();
6324 LLT DstTy =
MRI.getType(Dst);
6325 LLT SrcTy =
MRI.getType(Src);
6327 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6328 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6331 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6349 Builder.buildTruncSSatU(Dst, MatchInfo);
6350 MI.eraseFromParent();
6357 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6358 LLT SrcTy =
MRI.getType(Val);
6360 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6361 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6364 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6373 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6382 unsigned Opc =
MI.getOpcode();
6383 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6384 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6385 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6397 Opc = TargetOpcode::G_FSUB;
6402 Opc = TargetOpcode::G_FADD;
6408 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6409 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6418 MI.setDesc(
B.getTII().get(
Opc));
6419 MI.getOperand(1).setReg(
X);
6420 MI.getOperand(2).setReg(
Y);
6428 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6431 MatchInfo =
MI.getOperand(2).getReg();
6432 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6434 const auto LHSCst = Ty.isVector()
6441 if (LHSCst->Value.isNegZero())
6445 if (LHSCst->Value.isPosZero())
6455 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6462 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6476 bool &AllowFusionGlobally,
6478 bool CanReassociate)
const {
6480 auto *MF =
MI.getMF();
6481 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6483 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6491 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6494 if (!HasFMAD && !HasFMA)
6502 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6509 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6511 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6523 unsigned PreferredFusedOpcode =
6524 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6537 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6539 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6540 {LHS.MI->getOperand(1).getReg(),
6541 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6550 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6552 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6553 {RHS.MI->getOperand(1).getReg(),
6554 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6566 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6568 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6572 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6581 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6583 unsigned PreferredFusedOpcode =
6584 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6598 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6600 unsigned Flags =
MI.getFlags() & FpExtSrc->
getFlags();
6604 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6605 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6614 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6616 unsigned Flags =
MI.getFlags() & FpExtSrc->
getFlags();
6620 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6621 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg}, Flags);
6632 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6634 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6646 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6648 unsigned PreferredFusedOpcode =
6649 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6654 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6657 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6658 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6663 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6666 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6667 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6676 Register X = FMA->getOperand(1).getReg();
6677 Register Y = FMA->getOperand(2).getReg();
6680 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6681 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6684 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6685 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6686 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6687 {
X,
Y, InnerFMA}, OuterFlags);
6698 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6700 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6707 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6708 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6718 unsigned PreferredFusedOpcode =
6719 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6733 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6734 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6735 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6736 {FpExtU, FpExtV, Z}, InnerFlags)
6738 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6739 {
X,
Y, InnerFMA}, OuterFlags);
6745 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6749 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6751 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6752 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6756 LHS.MI->getOperand(1).getReg(),
6757 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6768 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6773 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6775 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6776 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6780 X =
B.buildFPExt(DstType,
X).getReg(0);
6781 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6784 InnerFlags, OuterFlags,
B);
6793 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6797 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6799 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6800 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6804 RHS.MI->getOperand(1).getReg(),
6805 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6816 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6821 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6823 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6824 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6828 X =
B.buildFPExt(DstType,
X).getReg(0);
6829 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6832 InnerFlags, OuterFlags,
B);
6844 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6846 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6858 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6862 int FirstMulHasFewerUses =
true;
6866 FirstMulHasFewerUses =
false;
6868 unsigned PreferredFusedOpcode =
6869 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6872 if (FirstMulHasFewerUses &&
6875 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6877 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6878 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6879 {LHS.MI->getOperand(1).getReg(),
6880 LHS.MI->getOperand(2).getReg(), NegZ},
6888 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6891 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6892 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6893 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6904 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6906 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6912 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6914 unsigned PreferredFusedOpcode =
6915 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6923 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6927 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6928 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6939 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6941 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6955 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6957 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6963 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6965 unsigned PreferredFusedOpcode =
6966 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6973 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6979 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6980 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6981 {FpExtX, FpExtY, NegZ}, Flags);
6990 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6994 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6997 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6998 {NegY, FpExtZ, LHSReg}, Flags);
7009 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
7011 bool AllowFusionGlobally, HasFMAD,
Aggressive;
7015 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
7016 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
7020 unsigned PreferredFusedOpcode =
7021 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
7025 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
7026 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
7027 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
7038 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
7040 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
7042 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
7045 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
7055 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
7057 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
7069 unsigned &IdxToPropagate)
const {
7071 switch (
MI.getOpcode()) {
7074 case TargetOpcode::G_FMINNUM:
7075 case TargetOpcode::G_FMAXNUM:
7076 PropagateNaN =
false;
7078 case TargetOpcode::G_FMINIMUM:
7079 case TargetOpcode::G_FMAXIMUM:
7080 PropagateNaN =
true;
7084 auto MatchNaN = [&](
unsigned Idx) {
7085 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
7089 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
7093 return MatchNaN(1) || MatchNaN(2);
7101 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
7111 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
7128 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
7129 if (&U == &
MI || U.getParent() !=
MI.getParent())
7131 if (U.getOpcode() == TargetOpcode::G_FDIV &&
7132 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
7133 !IsOne(U.getOperand(1).getReg())) {
7146 return MatchInfo.
size() >= MinUses;
7154 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
7155 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
7156 MatchInfo[0]->getOperand(2).getReg(),
7157 MatchInfo[0]->getFlags());
7162 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
7163 Div->getOperand(0).getReg(),
MI->getFlags());
7164 MI->eraseFromParent();
7169 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
7179 Reg == MaybeSameReg;
7181 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
7202 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
7211 return MRI.getType(MatchInfo) == DstVecTy;
7214 std::optional<ValueAndVReg> ShiftAmount;
7223 return MRI.getType(MatchInfo) == DstVecTy;
7238 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
7245 std::optional<ValueAndVReg> ShiftAmt;
7251 LLT MatchTy =
MRI.getType(MatchInfo);
7252 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
7253 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
7256unsigned CombinerHelper::getFPMinMaxOpcForSelect(
7258 SelectPatternNaNBehaviour VsNaNRetVal)
const {
7259 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
7260 "Expected a NaN behaviour?");
7270 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7271 return TargetOpcode::G_FMAXNUM;
7272 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7273 return TargetOpcode::G_FMAXIMUM;
7274 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7275 return TargetOpcode::G_FMAXNUM;
7276 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7277 return TargetOpcode::G_FMAXIMUM;
7283 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7284 return TargetOpcode::G_FMINNUM;
7285 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7286 return TargetOpcode::G_FMINIMUM;
7287 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7288 return TargetOpcode::G_FMINNUM;
7289 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7291 return TargetOpcode::G_FMINIMUM;
7295CombinerHelper::SelectPatternNaNBehaviour
7297 bool IsOrderedComparison)
const {
7298 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7299 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7301 if (!LHSSafe && !RHSSafe)
7302 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7303 if (LHSSafe && RHSSafe)
7304 return SelectPatternNaNBehaviour::RETURNS_ANY;
7307 if (IsOrderedComparison)
7308 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7309 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7312 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7313 : SelectPatternNaNBehaviour::RETURNS_NAN;
7322 LLT DstTy =
MRI.getType(Dst);
7335 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7337 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7339 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7342 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7343 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7344 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7345 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7347 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7350 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7355 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7360 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7362 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7366 MatchInfo = [=](MachineIRBuilder &
B) {
7367 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7375 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7382 Register TrueVal =
MI.getOperand(2).getReg();
7383 Register FalseVal =
MI.getOperand(3).getReg();
7384 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7389 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7402 if (MatchedSub &&
X != OpLHS)
7410 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7413 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7414 B.buildICmp(Pred, Dst,
Y, Zero);
7421static std::optional<unsigned>
7423 std::optional<int64_t> &Result) {
7424 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7425 Opcode == TargetOpcode::G_ASHR) &&
7426 "Expect G_SHL, G_LSHR or G_ASHR.");
7427 auto SignificantBits = 0;
7429 case TargetOpcode::G_SHL:
7433 case TargetOpcode::G_LSHR:
7437 case TargetOpcode::G_ASHR:
7446 Result = std::nullopt;
7457 Register ShiftVal =
MI.getOperand(1).getReg();
7458 Register ShiftReg =
MI.getOperand(2).getReg();
7459 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7460 auto IsShiftTooBig = [&](
const Constant *
C) {
7465 MatchInfo = std::nullopt;
7469 MI.getOpcode(), MatchInfo);
7470 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7476 unsigned LHSOpndIdx = 1;
7477 unsigned RHSOpndIdx = 2;
7478 switch (
MI.getOpcode()) {
7479 case TargetOpcode::G_UADDO:
7480 case TargetOpcode::G_SADDO:
7481 case TargetOpcode::G_UMULO:
7482 case TargetOpcode::G_SMULO:
7489 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7490 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7500 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7504 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7511 std::optional<FPValueAndVReg> ValAndVReg;
7519 unsigned LHSOpndIdx = 1;
7520 unsigned RHSOpndIdx = 2;
7521 switch (
MI.getOpcode()) {
7522 case TargetOpcode::G_UADDO:
7523 case TargetOpcode::G_SADDO:
7524 case TargetOpcode::G_UMULO:
7525 case TargetOpcode::G_SMULO:
7532 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7533 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7534 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7535 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7539bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7541 if (SrcTy.isFixedVector())
7543 if (SrcTy.isScalar()) {
7547 return IConstant && IConstant->Value == 1;
7552bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7553 LLT SrcTy =
MRI.getType(Src);
7555 return isConstantSplatVector(Src, 0, AllowUndefs);
7560 return IConstant && IConstant->Value == 0;
7567bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7568 bool AllowUndefs)
const {
7574 for (
unsigned I = 0;
I < NumSources; ++
I) {
7575 GImplicitDef *ImplicitDef =
7577 if (ImplicitDef && AllowUndefs)
7579 if (ImplicitDef && !AllowUndefs)
7581 std::optional<ValueAndVReg> IConstant =
7583 if (IConstant && IConstant->Value == SplatValue)
7593CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7596 return IConstant->Value;
7600 return std::nullopt;
7603 std::optional<APInt>
Value = std::nullopt;
7604 for (
unsigned I = 0;
I < NumSources; ++
I) {
7605 std::optional<ValueAndVReg> IConstant =
7608 return std::nullopt;
7610 Value = IConstant->Value;
7611 else if (*
Value != IConstant->Value)
7612 return std::nullopt;
7618bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7628 for (
unsigned I = 0;
I < NumSources; ++
I) {
7629 std::optional<ValueAndVReg> IConstant =
7638bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7645 LLT CondTy =
MRI.getType(
Select->getCondReg());
7646 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7656 std::optional<ValueAndVReg> TrueOpt =
7658 std::optional<ValueAndVReg> FalseOpt =
7661 if (!TrueOpt || !FalseOpt)
7664 APInt TrueValue = TrueOpt->Value;
7665 APInt FalseValue = FalseOpt->Value;
7669 MatchInfo = [=](MachineIRBuilder &
B) {
7670 B.setInstrAndDebugLoc(*
Select);
7671 B.buildZExtOrTrunc(Dest,
Cond);
7678 MatchInfo = [=](MachineIRBuilder &
B) {
7679 B.setInstrAndDebugLoc(*
Select);
7680 B.buildSExtOrTrunc(Dest,
Cond);
7687 MatchInfo = [=](MachineIRBuilder &
B) {
7688 B.setInstrAndDebugLoc(*
Select);
7689 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7690 B.buildNot(Inner,
Cond);
7691 B.buildZExtOrTrunc(Dest, Inner);
7698 MatchInfo = [=](MachineIRBuilder &
B) {
7699 B.setInstrAndDebugLoc(*
Select);
7700 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7701 B.buildNot(Inner,
Cond);
7702 B.buildSExtOrTrunc(Dest, Inner);
7708 if (TrueValue - 1 == FalseValue) {
7709 MatchInfo = [=](MachineIRBuilder &
B) {
7710 B.setInstrAndDebugLoc(*
Select);
7711 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7712 B.buildZExtOrTrunc(Inner,
Cond);
7713 B.buildAdd(Dest, Inner, False);
7719 if (TrueValue + 1 == FalseValue) {
7720 MatchInfo = [=](MachineIRBuilder &
B) {
7721 B.setInstrAndDebugLoc(*
Select);
7722 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7723 B.buildSExtOrTrunc(Inner,
Cond);
7724 B.buildAdd(Dest, Inner, False);
7731 MatchInfo = [=](MachineIRBuilder &
B) {
7732 B.setInstrAndDebugLoc(*
Select);
7733 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7734 B.buildZExtOrTrunc(Inner,
Cond);
7737 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7738 B.buildShl(Dest, Inner, ShAmtC, Flags);
7745 MatchInfo = [=](MachineIRBuilder &
B) {
7746 B.setInstrAndDebugLoc(*
Select);
7748 B.buildNot(Not,
Cond);
7749 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7750 B.buildZExtOrTrunc(Inner, Not);
7753 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7754 B.buildShl(Dest, Inner, ShAmtC, Flags);
7761 MatchInfo = [=](MachineIRBuilder &
B) {
7762 B.setInstrAndDebugLoc(*
Select);
7763 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7764 B.buildSExtOrTrunc(Inner,
Cond);
7765 B.buildOr(Dest, Inner, False, Flags);
7772 MatchInfo = [=](MachineIRBuilder &
B) {
7773 B.setInstrAndDebugLoc(*
Select);
7775 B.buildNot(Not,
Cond);
7776 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7777 B.buildSExtOrTrunc(Inner, Not);
7778 B.buildOr(Dest, Inner, True, Flags);
7787bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7794 LLT CondTy =
MRI.getType(
Select->getCondReg());
7795 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7804 if (CondTy != TrueTy)
7809 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7810 MatchInfo = [=](MachineIRBuilder &
B) {
7811 B.setInstrAndDebugLoc(*
Select);
7812 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7813 B.buildZExtOrTrunc(Ext,
Cond);
7814 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7815 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7822 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7823 MatchInfo = [=](MachineIRBuilder &
B) {
7824 B.setInstrAndDebugLoc(*
Select);
7825 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7826 B.buildZExtOrTrunc(Ext,
Cond);
7827 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7828 B.buildAnd(DstReg, Ext, FreezeTrue);
7834 if (isOneOrOneSplat(False,
true)) {
7835 MatchInfo = [=](MachineIRBuilder &
B) {
7836 B.setInstrAndDebugLoc(*
Select);
7838 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7839 B.buildNot(Inner,
Cond);
7841 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7842 B.buildZExtOrTrunc(Ext, Inner);
7843 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7844 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7850 if (isZeroOrZeroSplat(True,
true)) {
7851 MatchInfo = [=](MachineIRBuilder &
B) {
7852 B.setInstrAndDebugLoc(*
Select);
7854 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7855 B.buildNot(Inner,
Cond);
7857 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7858 B.buildZExtOrTrunc(Ext, Inner);
7859 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7860 B.buildAnd(DstReg, Ext, FreezeFalse);
7882 LLT DstTy =
MRI.getType(DstReg);
7887 if (!
MRI.hasOneNonDBGUse(CondReg))
7896 if (True == CmpRHS && False == CmpLHS) {
7904 if (True != CmpLHS || False != CmpRHS)
7944 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7945 Register DestReg =
MI.getOperand(0).getReg();
7946 LLT DestTy =
MRI.getType(DestReg);
7960 if (
isLegal({NewOpc, {DestTy}})) {
7962 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7974 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7977 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7987bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7989 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7990 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7994 unsigned Flags = Logic->
getFlags();
8013 std::optional<ValueAndVReg> MaybeC1 =
8017 C1 = MaybeC1->Value;
8019 std::optional<ValueAndVReg> MaybeC2 =
8023 C2 = MaybeC2->Value;
8044 std::optional<APInt> Offset1;
8045 std::optional<APInt> Offset2;
8048 std::optional<ValueAndVReg> MaybeOffset1 =
8051 R1 =
Add->getLHSReg();
8052 Offset1 = MaybeOffset1->Value;
8056 std::optional<ValueAndVReg> MaybeOffset2 =
8059 R2 =
Add->getLHSReg();
8060 Offset2 = MaybeOffset2->Value;
8079 bool CreateMask =
false;
8092 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
8105 CR->getEquivalentICmp(NewPred, NewC,
Offset);
8114 MatchInfo = [=](MachineIRBuilder &
B) {
8115 if (CreateMask &&
Offset != 0) {
8116 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8117 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8118 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8119 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
8120 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8121 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8122 B.buildZExtOrTrunc(DstReg, ICmp);
8123 }
else if (CreateMask &&
Offset == 0) {
8124 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
8125 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
8126 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8127 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
8128 B.buildZExtOrTrunc(DstReg, ICmp);
8129 }
else if (!CreateMask &&
Offset != 0) {
8130 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
8131 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
8132 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8133 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
8134 B.buildZExtOrTrunc(DstReg, ICmp);
8135 }
else if (!CreateMask &&
Offset == 0) {
8136 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
8137 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
8138 B.buildZExtOrTrunc(DstReg, ICmp);
8146bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
8152 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
8164 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
8170 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
8171 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
8172 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
8173 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
8184 if (LHS0 == RHS1 && LHS1 == RHS0) {
8190 if (LHS0 == RHS0 && LHS1 == RHS1) {
8194 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
8196 MatchInfo = [=](MachineIRBuilder &
B) {
8201 auto False =
B.buildConstant(CmpTy, 0);
8202 B.buildZExtOrTrunc(DestReg, False);
8209 B.buildZExtOrTrunc(DestReg, True);
8211 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
8212 B.buildZExtOrTrunc(DestReg, Cmp);
8224 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
8227 if (tryFoldLogicOfFCmps(
And, MatchInfo))
8236 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
8239 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
8254 bool IsSigned =
Add->isSigned();
8255 LLT DstTy =
MRI.getType(Dst);
8256 LLT CarryTy =
MRI.getType(Carry);
8259 if (
MRI.use_nodbg_empty(Carry) &&
8262 B.buildAdd(Dst, LHS, RHS);
8263 B.buildUndef(Carry);
8269 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
8272 B.buildSAddo(Dst, Carry, RHS, LHS);
8278 B.buildUAddo(Dst, Carry, RHS, LHS);
8283 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
8284 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
8290 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
8291 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
8293 B.buildConstant(Dst, Result);
8294 B.buildConstant(Carry, Overflow);
8302 B.buildCopy(Dst, LHS);
8303 B.buildConstant(Carry, 0);
8312 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8315 std::optional<APInt> MaybeAddRHS =
8316 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8319 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8320 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8324 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8325 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8331 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8332 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8357 B.buildConstant(Carry, 0);
8364 B.buildAdd(Dst, LHS, RHS);
8365 B.buildConstant(Carry, 1);
8377 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8380 B.buildConstant(Carry, 0);
8396 B.buildConstant(Carry, 0);
8403 B.buildAdd(Dst, LHS, RHS);
8404 B.buildConstant(Carry, 1);
8422 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8428 auto [Dst,
Base] =
MI.getFirst2Regs();
8429 LLT Ty =
MRI.getType(Dst);
8433 Builder.buildFConstant(Dst, 1.0);
8434 MI.removeFromParent();
8446 std::optional<SrcOp> Res;
8448 while (ExpVal > 0) {
8453 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8456 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8463 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8467 MI.eraseFromParent();
8478 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8485 LLT DstTy =
MRI.getType(Dst);
8488 auto Const =
B.buildConstant(DstTy, C1 - C2);
8489 B.buildAdd(Dst,
A, Const);
8503 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8510 LLT DstTy =
MRI.getType(Dst);
8513 auto Const =
B.buildConstant(DstTy, C2 - C1);
8514 B.buildSub(Dst, Const,
A);
8535 LLT DstTy =
MRI.getType(Dst);
8538 auto Const =
B.buildConstant(DstTy, C1 + C2);
8539 B.buildSub(Dst,
A, Const);
8560 LLT DstTy =
MRI.getType(Dst);
8563 auto Const =
B.buildConstant(DstTy, C1 - C2);
8564 B.buildSub(Dst, Const,
A);
8578 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8585 LLT DstTy =
MRI.getType(Dst);
8588 auto Const =
B.buildConstant(DstTy, C2 - C1);
8589 B.buildAdd(Dst,
A, Const);
8633 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8641 LLT SmallBvTy = DstTy;
8645 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8650 {TargetOpcode::G_ANYEXT,
8662 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8663 Ops.push_back(AnyExt.getReg(0));
8681 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8682 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8683 const unsigned NumDstElts = OrigMask.
size();
8684 for (
unsigned i = 0; i != NumDstElts; ++i) {
8685 int Idx = OrigMask[i];
8686 if (Idx >= (
int)NumSrcElems) {
8697 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8698 std::move(NewMask));
8705 const unsigned MaskSize = Mask.size();
8706 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8711 if (Idx < (
int)NumElems)
8712 Mask[
I] = Idx + NumElems;
8714 Mask[
I] = Idx - NumElems;
8724 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8727 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8730 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8731 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8733 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8737 const unsigned NumSrcElems = Src1Ty.getNumElements();
8739 bool TouchesSrc1 =
false;
8740 bool TouchesSrc2 =
false;
8741 const unsigned NumElems = Mask.size();
8742 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8746 if (Mask[Idx] < (
int)NumSrcElems)
8752 if (TouchesSrc1 == TouchesSrc2)
8755 Register NewSrc1 = Shuffle.getSrc1Reg();
8758 NewSrc1 = Shuffle.getSrc2Reg();
8763 auto Undef =
B.buildUndef(Src1Ty);
8764 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8778 LLT DstTy =
MRI.getType(Dst);
8779 LLT CarryTy =
MRI.getType(Carry);
8801 B.buildConstant(Carry, 0);
8808 B.buildSub(Dst, LHS, RHS);
8826 B.buildConstant(Carry, 0);
8833 B.buildSub(Dst, LHS, RHS);
8850 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8851 "Expected G_CTLZ variant");
8856 LLT Ty =
MRI.getType(Dst);
8857 LLT SrcTy =
MRI.getType(Src);
8859 if (!(Ty.isValid() && Ty.isScalar()))
8868 switch (
LI->getAction(Query).Action) {
8879 bool NeedAdd =
true;
8887 unsigned BitWidth = Ty.getScalarSizeInBits();
8898 B.buildCTLS(Dst,
X);
8902 auto Ctls =
B.buildCTLS(Ty,
X);
8903 auto One =
B.buildConstant(Ty, 1);
8905 B.buildAdd(Dst, Ctls, One);
8915 unsigned TargetOpc)
const {
8916 assert((
MI.getOpcode() == TargetOpcode::G_LSHR ||
8917 MI.getOpcode() == TargetOpcode::G_ASHR) &&
8918 "Expected G_LSHR/G_ASHR");
8921 return XTy ==
MRI.getType(
Y) &&
isLegal({TargetOpc, {XTy}});
8925 assert((
MI.getOpcode() == TargetOpcode::G_CTLZ ||
8926 MI.getOpcode() == TargetOpcode::G_CTTZ) &&
8927 "Expected count-zero opcode");
8928 switch (
MI.getOpcode()) {
8929 case TargetOpcode::G_CTLZ:
8930 return TargetOpcode::G_CTLZ_ZERO_POISON;
8931 case TargetOpcode::G_CTTZ:
8932 return TargetOpcode::G_CTTZ_ZERO_POISON;
8944 if (!
VT->isKnownNeverZero(Src))
8947 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8948 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 matchCommuteShift(MachineInstr &MI, BuildFnTy &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 void applyPtrAddZero(MachineInstr &MI) const
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 matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
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 void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
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 matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
LLVM_ABI bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
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 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 bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
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 void applySextTruncSextLoad(MachineInstr &MI) const
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 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...