49#define DEBUG_TYPE "gi-combiner"
58 cl::desc(
"Force all indexed operations to be "
59 "legal for the GlobalISel combiner"));
68 TII(
Builder.getMF().getSubtarget().getInstrInfo()),
69 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
70 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
75 return *
Builder.getMF().getSubtarget().getTargetLowering();
89 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
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!");
178bool CombinerHelper::isImmConstantLegalOrBeforeLegalizer(
unsigned Opc,
179 const LLT Ty)
const {
188 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
193 return isImmConstantLegalOrBeforeLegalizer(TargetOpcode::G_CONSTANT, Ty);
197 return isImmConstantLegalOrBeforeLegalizer(TargetOpcode::G_FCONSTANT, Ty);
204 if (
MRI.constrainRegAttrs(ToReg, FromReg))
205 MRI.replaceRegWith(FromReg, ToReg);
207 Builder.buildCopy(FromReg, ToReg);
209 Observer.finishedChangingAllUsesOfReg();
224 unsigned ToOpcode)
const {
239 MRI.setRegBank(Reg, *RegBank);
243 if (
MI.getOpcode() != TargetOpcode::COPY)
253 MI.eraseFromParent();
258 assert(
MI.getOpcode() == TargetOpcode::G_FREEZE &&
"Invalid instruction");
264 if (!
MRI.hasOneNonDBGUse(OrigOp))
285 std::optional<MachineOperand> MaybePoisonOperand;
287 if (!Operand.isReg())
293 if (!MaybePoisonOperand)
294 MaybePoisonOperand = Operand;
303 if (!MaybePoisonOperand) {
308 B.buildCopy(
DstOp, OrigOp);
313 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
314 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
317 {TargetOpcode::G_FREEZE, {MaybePoisonOperandRegTy}}))
325 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
336 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
337 "Invalid instruction");
349 if (!
MRI.hasOneNonDBGUse(Reg))
351 switch (Def->getOpcode()) {
352 case TargetOpcode::G_BUILD_VECTOR:
357 Ops.push_back(BuildVecMO.getReg());
359 case TargetOpcode::G_IMPLICIT_DEF: {
360 LLT OpType =
MRI.getType(Reg);
367 OpType.getScalarType() &&
368 "All undefs should have the same type");
371 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
372 EltIdx != EltEnd; ++EltIdx)
373 Ops.push_back(
Undef->getOperand(0).getReg());
382 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
384 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
399 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
412 MI.eraseFromParent();
421 if (!Unmerge || Unmerge->
getReg(0) != BV.getSourceReg(0))
426 LLT InputTy =
MRI.getType(BCSrc);
428 if (!InputTy.
isScalar() || BV.getNumSources() % Factor != 0)
433 if (!
isLegal({TargetOpcode::G_BUILD_VECTOR, {BVDstTy, InputTy}}))
437 for (
unsigned Idx = 0; Idx < BV.getNumSources(); Idx += Factor) {
453 Ops.push_back(BCSrc);
474 auto BV =
Builder.buildBuildVector(BVDstTy,
Ops);
475 Builder.buildBitcast(
MI.getOperand(0).getReg(), BV);
476 MI.eraseFromParent();
482 Register SrcVec1 = Shuffle.getSrc1Reg();
483 Register SrcVec2 = Shuffle.getSrc2Reg();
484 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
485 int Width =
MRI.getType(SrcVec1).getNumElements();
487 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
488 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
492 for (
int Val : Shuffle.getMask()) {
495 else if (Val < Width)
496 Extracts.
push_back(Unmerge1.getReg(Val));
498 Extracts.
push_back(Unmerge2.getReg(Val - Width));
500 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
501 if (Extracts.
size() == 1)
502 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
504 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
505 MI.eraseFromParent();
510 Register SrcVec1 = Shuffle.getSrc1Reg();
511 Register SrcVec2 = Shuffle.getSrc2Reg();
514 assert((BuildMI1 && (BuildMI2 ||
MRI.getVRegDef(SrcVec2)->getOpcode() ==
515 TargetOpcode::G_IMPLICIT_DEF)) &&
516 "Unexpected input to applyCombineShuffleOfBuildVector");
517 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
518 int NumElts =
MRI.getType(SrcVec1).getNumElements();
521 for (
int Val : Shuffle.getMask()) {
524 else if (Val < NumElts)
525 Extracts.
push_back(BuildMI1->getSourceReg(Val));
527 Extracts.
push_back(BuildMI2->getSourceReg(Val - NumElts));
532 if (Extracts.
size() == 1)
533 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
535 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
536 MI.eraseFromParent();
553 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
555 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
559 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
560 if (i + j >= Mask.size())
562 if (Mask[i + j] != -1)
566 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
569 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
570 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
571 if (i + j >= Mask.size())
573 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
590 {TargetOpcode::G_CONCAT_VECTORS,
591 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
602 SrcTy =
MRI.getType(Reg);
604 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
611 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
617 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
620 MI.eraseFromParent();
625 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
626 "Invalid instruction kind");
627 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
629 LLT SrcType =
MRI.getType(Src1);
631 unsigned DstNumElts = DstType.getNumElements();
632 unsigned SrcNumElts = SrcType.getNumElements();
649 if (DstNumElts < 2 * SrcNumElts)
654 if (DstNumElts % SrcNumElts != 0)
660 unsigned NumConcat = DstNumElts / SrcNumElts;
663 for (
unsigned i = 0; i != DstNumElts; ++i) {
670 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
671 (ConcatSrcs[i / SrcNumElts] >= 0 &&
672 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
675 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
682 for (
auto Src : ConcatSrcs) {
686 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
688 Ops.push_back(UndefReg);
701 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
709 MI.eraseFromParent();
718 const LLT TyForCandidate,
719 unsigned OpcodeForCandidate,
724 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
735 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
738 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
739 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
740 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
748 OpcodeForCandidate == TargetOpcode::G_ZEXT)
750 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
751 OpcodeForCandidate == TargetOpcode::G_SEXT)
752 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
761 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
772static void InsertInsnsWithoutSideEffectsBeforeUse(
784 InsertBB = PredBB->
getMBB();
789 if (InsertBB ==
DefMI.getParent()) {
791 Inserter(InsertBB, std::next(InsertPt), UseMO);
810 unsigned CandidateLoadOpc;
812 case TargetOpcode::G_ANYEXT:
813 CandidateLoadOpc = TargetOpcode::G_LOAD;
815 case TargetOpcode::G_SEXT:
816 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
818 case TargetOpcode::G_ZEXT:
819 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
824 return CandidateLoadOpc;
841 LLT LoadValueTy =
MRI.getType(LoadReg);
863 unsigned PreferredOpcode =
865 ? TargetOpcode::G_ANYEXT
867 Preferred = {
LLT(), PreferredOpcode,
nullptr};
868 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
869 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
870 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
871 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
872 const auto &MMO = LoadMI->
getMMO();
880 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
882 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
886 Preferred = ChoosePreferredUse(
MI, Preferred,
887 MRI.getType(
UseMI.getOperand(0).getReg()),
897 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
915 if (PreviouslyEmitted) {
922 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
923 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
925 EmittedInsns[InsertIntoBB] = NewMI;
931 MI.setDesc(
Builder.getTII().get(LoadOpc));
938 for (
auto *UseMO :
Uses) {
944 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
947 const LLT UseDstTy =
MRI.getType(UseDstReg);
948 if (UseDstReg != ChosenDstReg) {
949 if (Preferred.
Ty == UseDstTy) {
986 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
1001 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
1004 MI.getOperand(0).setReg(ChosenDstReg);
1010 assert(
MI.getOpcode() == TargetOpcode::G_AND);
1021 if (
MRI.getType(Dst).isVector())
1029 APInt MaskVal = MaybeMask->Value;
1044 LLT RegTy =
MRI.getType(LoadReg);
1047 unsigned MaskSizeBits = MaskVal.
countr_one();
1050 !
MRI.hasOneNonDBGUse(LoadReg))
1055 if (MaskSizeBits > LoadSizeBits)
1074 else if (LoadSizeBits > MaskSizeBits || LoadSizeBits ==
RegSize)
1079 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
1083 B.setInstrAndDebugLoc(*LoadMI);
1084 auto &MF =
B.getMF();
1086 auto *NewMMO = MF.getMachineMemOperand(MMO, PtrInfo, MemDesc.
MemoryTy);
1087 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
1097 "shouldn't consider debug uses");
1105 if (DefOrUse ==
MBB.end())
1107 return &*DefOrUse == &
DefMI;
1113 "shouldn't consider debug uses");
1116 else if (
DefMI.getParent() !=
UseMI.getParent())
1123 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1127 if (
MRI.getType(SrcReg).isVector())
1132 LoadUser = TruncSrc;
1134 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1139 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1141 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1143 if (LoadSizeBits == SizeInBits)
1150 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1151 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1154 LLT RegTy =
MRI.getType(DstReg);
1167 uint64_t ExtFrom =
MI.getOperand(2).getImm();
1169 if (MemBits > ExtFrom && !
MRI.hasOneNonDBGUse(SrcReg))
1175 unsigned NewSizeBits = std::min(ExtFrom, MemBits);
1178 if (NewSizeBits < 8)
1191 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1196 {TargetOpcode::G_SEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MMDesc}}))
1199 MatchInfo = std::make_tuple(SrcReg, NewSizeBits);
1204 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1205 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1207 unsigned ScalarSizeBits;
1208 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1217 auto &MMO = LoadDef->
getMMO();
1218 Builder.setInstrAndDebugLoc(*LoadDef);
1220 auto PtrInfo = MMO.getPointerInfo();
1221 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1222 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1225 MI.eraseFromParent();
1236 auto *MF =
MI->getMF();
1243 AM.
BaseOffs = CstOff->getSExtValue();
1247 return TLI.isLegalAddressingMode(
1248 MF->getDataLayout(), AM,
1250 MF->getFunction().getContext()),
1251 MI->getMMO().getAddrSpace());
1256 case TargetOpcode::G_LOAD:
1257 return TargetOpcode::G_INDEXED_LOAD;
1258 case TargetOpcode::G_STORE:
1259 return TargetOpcode::G_INDEXED_STORE;
1260 case TargetOpcode::G_ZEXTLOAD:
1261 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1262 case TargetOpcode::G_SEXTLOAD:
1263 return TargetOpcode::G_INDEXED_SEXTLOAD;
1269bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1279 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1280 OpTys = {PtrTy, Ty, Ty};
1282 OpTys = {Ty, PtrTy};
1284 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1290 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1291 "considered for post-indexing."));
1295 bool &RematOffset)
const {
1305 if (
MRI.hasOneNonDBGUse(Ptr))
1308 if (!isIndexedLoadStoreLegal(LdSt))
1319 unsigned NumUsesChecked = 0;
1320 for (
auto &
Use :
MRI.use_nodbg_instructions(Ptr)) {
1327 if (!PtrAdd ||
MRI.use_nodbg_empty(PtrAdd->getReg(0)))
1332 if (StoredValDef == &
Use)
1335 Offset = PtrAdd->getOffsetReg();
1337 !
TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1345 RematOffset =
false;
1349 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1354 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1355 if (&BasePtrUse == PtrDef)
1361 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1363 isIndexedLoadStoreLegal(*BasePtrLdSt))
1369 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1370 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1373 if (BaseUseUse.getParent() != LdSt.
getParent())
1385 Addr = PtrAdd->getReg(0);
1386 Base = PtrAdd->getBaseReg();
1397 const auto &
TLI = *MF.getSubtarget().getTargetLowering();
1401 MRI.hasOneNonDBGUse(Addr))
1408 if (!isIndexedLoadStoreLegal(LdSt))
1412 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1417 if (
Base == St->getValueReg())
1422 if (St->getValueReg() == Addr)
1427 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1428 if (AddrUse.getParent() != LdSt.
getParent())
1433 bool RealUse =
false;
1434 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1452 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1462 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1469 if (!LoadMI->isSimple())
1481 const unsigned MaxIter = 20;
1483 for (
const auto &Instr :
1485 if (Instr.isLoadFoldBarrier())
1487 if (Iter++ == MaxIter)
1503 int Elt = CVal->getZExtValue();
1516 Register VecPtr = LoadMI->getPointerReg();
1517 LLT PtrTy =
MRI.getType(VecPtr);
1525 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1548 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1563 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1565 if (!MatchInfo.
IsPre &&
1566 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1576 unsigned Opcode =
MI.getOpcode();
1577 bool IsStore = Opcode == TargetOpcode::G_STORE;
1583 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1585 *OldCst->getOperand(1).getCImm());
1586 MatchInfo.
Offset = NewCst.getReg(0);
1589 auto MIB =
Builder.buildInstr(NewOpcode);
1591 MIB.addDef(MatchInfo.
Addr);
1592 MIB.addUse(
MI.getOperand(0).getReg());
1594 MIB.addDef(
MI.getOperand(0).getReg());
1595 MIB.addDef(MatchInfo.
Addr);
1598 MIB.addUse(MatchInfo.
Base);
1599 MIB.addUse(MatchInfo.
Offset);
1600 MIB.addImm(MatchInfo.
IsPre);
1601 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1602 MI.eraseFromParent();
1610 unsigned Opcode =
MI.getOpcode();
1611 bool IsDiv, IsSigned;
1616 case TargetOpcode::G_SDIV:
1617 case TargetOpcode::G_UDIV: {
1619 IsSigned = Opcode == TargetOpcode::G_SDIV;
1622 case TargetOpcode::G_SREM:
1623 case TargetOpcode::G_UREM: {
1625 IsSigned = Opcode == TargetOpcode::G_SREM;
1631 unsigned DivOpcode, RemOpcode, DivremOpcode;
1633 DivOpcode = TargetOpcode::G_SDIV;
1634 RemOpcode = TargetOpcode::G_SREM;
1635 DivremOpcode = TargetOpcode::G_SDIVREM;
1637 DivOpcode = TargetOpcode::G_UDIV;
1638 RemOpcode = TargetOpcode::G_UREM;
1639 DivremOpcode = TargetOpcode::G_UDIVREM;
1657 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1658 if (
MI.getParent() ==
UseMI.getParent() &&
1659 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1660 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1673 unsigned Opcode =
MI.getOpcode();
1674 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1677 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1678 DestDivReg =
MI.getOperand(0).getReg();
1682 DestRemReg =
MI.getOperand(0).getReg();
1686 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1693 Builder.setInstrAndDebugLoc(*FirstInst);
1695 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1696 : TargetOpcode::G_UDIVREM,
1697 {DestDivReg, DestRemReg},
1699 MI.eraseFromParent();
1705 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1722 if (BrIt ==
MBB->begin())
1724 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1726 BrCond = &*std::prev(BrIt);
1727 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1733 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1734 MBB->isLayoutSuccessor(BrCondTarget);
1740 Builder.setInstrAndDebugLoc(*BrCond);
1751 MI.getOperand(0).setMBB(FallthroughBB);
1764 unsigned MaxLen)
const {
1765 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1767 DstAlignCanChange, MemOps);
1772 auto &[Dst, Src, KnownLen, Alignment, DstAlignCanChange, MemOps] = MatchInfo;
1777 DstAlignCanChange, MemOps) ==
1779 assert(
Changed &&
"expected memcpy-family instruction to lower");
1784 unsigned MaxLen)
const {
1800 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1823 Type *AccessTy =
nullptr;
1824 auto &MF = *
MI.getMF();
1825 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1828 MF.getFunction().getContext());
1833 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1838 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1840 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1841 const auto &
TLI = *MF.getSubtarget().getTargetLowering();
1842 if (
TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1843 !
TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1852 unsigned PtrAddFlags =
MI.getFlags();
1868 MatchInfo.
Flags = Flags;
1874 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1876 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1880 MI.getOperand(1).setReg(MatchInfo.
Base);
1881 MI.getOperand(2).setReg(NewOffset.getReg(0));
1895 unsigned Opcode =
MI.getOpcode();
1896 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1897 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1898 Opcode == TargetOpcode::G_USHLSAT) &&
1899 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1919 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1924 if (Opcode == TargetOpcode::G_USHLSAT &&
1925 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1933 unsigned Opcode =
MI.getOpcode();
1934 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1935 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1936 Opcode == TargetOpcode::G_USHLSAT) &&
1937 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1939 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1940 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1941 auto Imm = MatchInfo.
Imm;
1943 if (
Imm >= ScalarSizeInBits) {
1945 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1946 Builder.buildConstant(
MI.getOperand(0), 0);
1947 MI.eraseFromParent();
1952 Imm = ScalarSizeInBits - 1;
1955 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1958 MI.getOperand(1).setReg(MatchInfo.
Reg);
1959 MI.getOperand(2).setReg(NewImm);
1975 unsigned ShiftOpcode =
MI.getOpcode();
1976 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1977 ShiftOpcode == TargetOpcode::G_ASHR ||
1978 ShiftOpcode == TargetOpcode::G_LSHR ||
1979 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1980 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1981 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1984 Register LogicDest =
MI.getOperand(1).getReg();
1985 if (!
MRI.hasOneNonDBGUse(LogicDest))
1991 unsigned LogicOpcode = LogicMI->
getOpcode();
1992 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1993 LogicOpcode != TargetOpcode::G_XOR)
1999 if (!MaybeImmVal || MaybeImmVal->Value == 0)
2002 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
2004 auto matchFirstShift = [&](
const MachineInstr *
MI, uint64_t &ShiftVal) {
2006 if (
MI->getOpcode() != ShiftOpcode ||
2007 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
2016 ShiftVal = MaybeImmVal->Value.getSExtValue();
2030 if (matchFirstShift(LogicMIOp1, C0Val)) {
2032 MatchInfo.
Shift2 = LogicMIOp1;
2033 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
2035 MatchInfo.
Shift2 = LogicMIOp2;
2039 MatchInfo.
ValSum = C0Val + C1Val;
2042 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
2045 MatchInfo.
Logic = LogicMI;
2051 unsigned Opcode =
MI.getOpcode();
2052 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2053 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2054 Opcode == TargetOpcode::G_SSHLSAT) &&
2055 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2057 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2058 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2064 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2073 Register Shift2Const =
MI.getOperand(2).getReg();
2075 .buildInstr(Opcode, {DestType},
2085 MI.eraseFromParent();
2097 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2101 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2116 LLT InnerShiftTy =
MRI.getType(InnerShift);
2118 if ((N1C + N001C).ult(InnerShiftSize)) {
2124 if ((N001C + OpSizeInBits) == InnerShiftSize)
2126 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2127 MatchInfo.
Mask =
true;
2137 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2144 if (MatchInfo.
Mask ==
true) {
2152 Builder.buildTrunc(Dst, Shift);
2153 MI.eraseFromParent();
2157 unsigned &ShiftVal)
const {
2158 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2164 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2165 return (
static_cast<int32_t
>(ShiftVal) != -1);
2169 unsigned &ShiftVal)
const {
2170 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2172 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2175 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2176 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2197 auto NegCst =
B.buildConstant(Ty, -
Imm);
2199 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2200 MI.getOperand(2).setReg(NegCst.getReg(0));
2202 if (
Imm.isMinSignedValue())
2212 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2226 if (!MaybeShiftAmtVal)
2230 LLT SrcTy =
MRI.getType(ExtSrc);
2240 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2241 MatchData.
Reg = ExtSrc;
2242 MatchData.
Imm = ShiftAmt;
2244 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2245 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2246 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2252 int64_t ShiftAmtVal = MatchData.
Imm;
2254 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2255 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2257 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2258 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2259 MI.eraseFromParent();
2272 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2273 "Expected an unmerge");
2282 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2283 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2285 if (SrcMergeTy != Dst0Ty && !SameSize)
2289 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2290 Operands.push_back(SrcInstr->getSourceReg(Idx));
2296 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2297 "Expected an unmerge");
2299 "Not enough operands to replace all defs");
2300 unsigned NumElems =
MI.getNumOperands() - 1;
2303 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2304 bool CanReuseInputDirectly = DstTy == SrcTy;
2305 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2306 Register DstReg =
MI.getOperand(Idx).getReg();
2311 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2312 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2313 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2314 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2317 if (CanReuseInputDirectly)
2320 Builder.buildCast(DstReg, SrcReg);
2322 MI.eraseFromParent();
2327 unsigned SrcIdx =
MI.getNumOperands() - 1;
2328 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2334 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2337 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2339 Val = Val.
lshr(ShiftAmt);
2347 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2348 "Expected an unmerge");
2350 "Not enough operands to replace all defs");
2351 unsigned NumElems =
MI.getNumOperands() - 1;
2352 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2353 Register DstReg =
MI.getOperand(Idx).getReg();
2354 Builder.buildConstant(DstReg, Csts[Idx]);
2357 MI.eraseFromParent();
2363 unsigned SrcIdx =
MI.getNumOperands() - 1;
2364 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2366 unsigned NumElems =
MI.getNumOperands() - 1;
2367 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2368 Register DstReg =
MI.getOperand(Idx).getReg();
2369 B.buildUndef(DstReg);
2377 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2378 "Expected an unmerge");
2379 if (!
MRI.getType(
MI.getOperand(0).getReg()).isScalar() ||
2380 !
MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isScalar())
2383 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2384 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2392 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2393 Register Dst0Reg =
MI.getOperand(0).getReg();
2394 Builder.buildTrunc(Dst0Reg, SrcReg);
2395 MI.eraseFromParent();
2399 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2400 "Expected an unmerge");
2401 Register Dst0Reg =
MI.getOperand(0).getReg();
2402 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2408 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2409 LLT SrcTy =
MRI.getType(SrcReg);
2410 if (SrcTy.isVector())
2420 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2425 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2426 "Expected an unmerge");
2428 Register Dst0Reg =
MI.getOperand(0).getReg();
2433 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2434 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2437 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2440 "ZExt src doesn't fit in destination");
2445 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2447 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2450 MI.eraseFromParent();
2454 unsigned TargetShiftSize,
2455 unsigned &ShiftVal)
const {
2456 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2457 MI.getOpcode() == TargetOpcode::G_LSHR ||
2458 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2460 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2465 unsigned Size = Ty.getSizeInBits();
2466 if (
Size <= TargetShiftSize)
2474 ShiftVal = MaybeImmVal->Value.getSExtValue();
2475 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2482 LLT Ty =
MRI.getType(SrcReg);
2483 unsigned Size = Ty.getSizeInBits();
2484 unsigned HalfSize =
Size / 2;
2485 assert(ShiftVal >= HalfSize);
2489 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2490 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2492 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2493 Register Narrowed = Unmerge.getReg(1);
2500 if (NarrowShiftAmt != 0) {
2501 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2502 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2506 Builder.buildMergeLikeInstr(DstReg, {Narrowed,
Zero});
2507 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2508 Register Narrowed = Unmerge.getReg(0);
2513 if (NarrowShiftAmt != 0) {
2514 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2515 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2519 Builder.buildMergeLikeInstr(DstReg, {
Zero, Narrowed});
2521 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2523 HalfTy, Unmerge.getReg(1),
2524 Builder.buildConstant(HalfTy, HalfSize - 1));
2526 if (ShiftVal == HalfSize) {
2529 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2530 }
else if (ShiftVal ==
Size - 1) {
2538 HalfTy, Unmerge.getReg(1),
2539 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2547 MI.eraseFromParent();
2563 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2568 SrcReg = OriginalSrcReg;
2569 LLT DstTy =
MRI.getType(DstReg);
2577 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2580 LLT DstTy =
MRI.getType(DstReg);
2585 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2586 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2596 if (ShiftSize > 32 && TruncSize < 32)
2609 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2610 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2614 if (!
MRI.hasOneNonDBGUse(SrcReg))
2617 LLT SrcTy =
MRI.getType(SrcReg);
2618 LLT DstTy =
MRI.getType(DstReg);
2627 case TargetOpcode::G_SHL: {
2636 case TargetOpcode::G_LSHR:
2637 case TargetOpcode::G_ASHR: {
2643 for (
auto &
User :
MRI.use_instructions(DstReg))
2644 if (
User.getOpcode() == TargetOpcode::G_STORE)
2648 if (NewShiftTy == SrcTy)
2662 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2665 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2670 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2672 LLT NewShiftTy = MatchInfo.second;
2675 LLT DstTy =
MRI.getType(Dst);
2679 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2682 LLT PrefShiftTy = TL.getPreferredShiftAmountTy(NewShiftTy);
2683 if (
MRI.getType(ShiftAmt) != PrefShiftTy)
2684 ShiftAmt =
Builder.buildZExtOrTrunc(PrefShiftTy, ShiftAmt).getReg(0);
2688 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2691 if (NewShiftTy == DstTy)
2694 Builder.buildTrunc(Dst, NewShift);
2701 return !MO.isReg() ||
2702 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2707 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2709 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2714 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2715 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2716 "Expected an insert/extract element op");
2717 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2722 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2770 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2797 return MO.isReg() && MO.getReg().isPhysical();
2807 return I1->isIdenticalTo(*I2);
2815 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2822 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2843 std::optional<FPValueAndVReg> MaybeCst;
2847 return MaybeCst->Value.isExactlyValue(
C);
2851 unsigned OpIdx)
const {
2852 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2854 Register Replacement =
MI.getOperand(OpIdx).getReg();
2857 MI.eraseFromParent();
2862 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2866 MI.eraseFromParent();
2870 unsigned ConstIdx)
const {
2871 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2872 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2884 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2885 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2886 "This is not a funnel shift operation");
2888 Register ConstReg =
MI.getOperand(3).getReg();
2889 LLT ConstTy =
MRI.getType(ConstReg);
2890 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2893 assert((VRegAndVal) &&
"Value is not a constant");
2896 APInt NewConst = VRegAndVal->Value.
urem(
2901 MI.getOpcode(), {MI.getOperand(0)},
2902 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
2904 MI.eraseFromParent();
2908 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2922 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2924 MI.eraseFromParent();
2929 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2931 MI.eraseFromParent();
2935 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2937 MI.eraseFromParent();
2942 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2944 MI.eraseFromParent();
2948 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
2950 MI.eraseFromParent();
2955 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
2958 LLT DstTy =
MRI.getType(DstReg);
2967 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
2968 TargetOpcode::G_INSERT_VECTOR_ELT)
2974 MatchInfo.
resize(NumElts);
2978 if (IntImm >= NumElts || IntImm < 0)
2980 if (!MatchInfo[IntImm])
2981 MatchInfo[IntImm] = TmpReg;
2985 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
2987 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
2996 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3003 auto GetUndef = [&]() {
3006 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3014 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3015 MI.eraseFromParent();
3028 unsigned InnerOpc = InnerDef->
getOpcode();
3029 if (InnerOpc != TargetOpcode::G_ADD && InnerOpc != TargetOpcode::G_SUB)
3032 if (!
MRI.hasOneNonDBGUse(MInner))
3043 if (!
MRI.hasOneNonDBGUse(MaybeNot))
3053 if (!TryMatch(InnerLHS, InnerRHS) &&
3054 !(InnerOpc == TargetOpcode::G_ADD && TryMatch(InnerRHS, InnerLHS)))
3058 unsigned FlippedOpc = (InnerOpc == TargetOpcode::G_ADD) ? TargetOpcode::G_SUB
3059 : TargetOpcode::G_ADD;
3062 MatchInfo = [=](MachineIRBuilder &
Builder) {
3063 auto NewInner =
Builder.buildInstr(FlippedOpc, {Ty}, {
B,
C});
3064 auto NewNot =
Builder.buildNot(Ty, NewInner);
3065 Builder.buildInstr(RootOpc, {Dst}, {
A, NewNot});
3077 unsigned RootOpc =
MI.getOpcode();
3079 LLT Ty =
MRI.getType(Dst);
3084 return matchBinopWithNegInner(LHS, RHS, RootOpc, Dst, Ty, MatchInfo) ||
3085 matchBinopWithNegInner(RHS, LHS, RootOpc, Dst, Ty, MatchInfo);
3096 unsigned LogicOpcode =
MI.getOpcode();
3097 assert(LogicOpcode == TargetOpcode::G_AND ||
3098 LogicOpcode == TargetOpcode::G_OR ||
3099 LogicOpcode == TargetOpcode::G_XOR);
3106 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3112 if (!LeftHandInst || !RightHandInst)
3114 unsigned HandOpcode = LeftHandInst->
getOpcode();
3115 if (HandOpcode != RightHandInst->
getOpcode())
3129 if (!XTy.
isValid() || XTy != YTy)
3134 switch (HandOpcode) {
3137 case TargetOpcode::G_ANYEXT:
3138 case TargetOpcode::G_SEXT:
3139 case TargetOpcode::G_ZEXT: {
3143 case TargetOpcode::G_TRUNC: {
3148 LLT DstTy =
MRI.getType(Dst);
3153 if (
TLI.isZExtFree(DstTy, XTy, Ctx) &&
TLI.isTruncateFree(XTy, DstTy, Ctx))
3157 case TargetOpcode::G_AND:
3158 case TargetOpcode::G_ASHR:
3159 case TargetOpcode::G_LSHR:
3160 case TargetOpcode::G_SHL: {
3165 ExtraHandOpSrcReg = ZOp.
getReg();
3176 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3187 if (ExtraHandOpSrcReg.
isValid())
3199 "Expected at least one instr to build?");
3201 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3202 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3204 for (
auto &OperandFn : InstrToBuild.OperandFns)
3207 MI.eraseFromParent();
3211 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3212 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3213 int64_t ShlCst, AshrCst;
3219 if (ShlCst != AshrCst)
3222 {TargetOpcode::G_SEXT_INREG,
3225 {
MRI.getType(Src).getScalarSizeInBits() - ShlCst}}))
3227 MatchInfo = std::make_tuple(Src, ShlCst);
3232 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3233 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3236 std::tie(Src, ShiftAmt) = MatchInfo;
3237 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3238 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3239 MI.eraseFromParent();
3246 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3249 LLT Ty =
MRI.getType(Dst);
3261 B.buildAnd(Dst, R,
B.buildConstant(Ty,
C1 & C2));
3264 auto Zero =
B.buildConstant(Ty, 0);
3287 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3311 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3318 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3335 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3353 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3360 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3371 unsigned ExtBits =
MI.getOperand(2).getImm();
3372 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3373 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3377 int64_t Cst,
bool IsVector,
bool IsFP) {
3379 return (ScalarSizeBits == 1 && Cst == -1) ||
3401 unsigned BuildUseCount = BV.getNumSources();
3402 if (BuildUseCount % 2 != 0)
3405 unsigned NumUnmerge = BuildUseCount / 2;
3411 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3414 UnmergeSrc = Unmerge->getSourceReg();
3416 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3417 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3424 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3429 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3430 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3433 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3436 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3441 if (Unmerge->getNumDefs() != NumUnmerge)
3445 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3448 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3459 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3460 B.setInstrAndDebugLoc(
MI);
3462 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3463 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3465 MI.eraseFromParent();
3487 unsigned NumOperands =
BuildMI->getNumSources();
3497 for (
I = 0;
I < NumOperands; ++
I) {
3509 UnmergeMI != UnmergeSrcMI)
3520 for (;
I < NumOperands; ++
I) {
3527 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3537 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3538 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3546 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3549 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3561 LLT DstTy =
MRI.getType(DstReg);
3562 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3567 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3572 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3576 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3579 Builder.buildTrunc(DstReg, MidReg);
3580 MI.eraseFromParent();
3585 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3586 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3587 const auto &
TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3595 if (!
MRI.hasOneNonDBGUse(XorSrc))
3605 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3607 if (!
MRI.hasOneNonDBGUse(Reg))
3612 switch (Def->getOpcode()) {
3617 case TargetOpcode::G_ICMP:
3623 case TargetOpcode::G_FCMP:
3629 case TargetOpcode::G_AND:
3630 case TargetOpcode::G_OR:
3636 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3637 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3645 if (Ty.isVector()) {
3663 for (
Register Reg : RegsToNegate) {
3668 switch (Def->getOpcode()) {
3671 case TargetOpcode::G_ICMP:
3672 case TargetOpcode::G_FCMP: {
3679 case TargetOpcode::G_AND:
3680 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3682 case TargetOpcode::G_OR:
3683 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3690 MI.eraseFromParent();
3694 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3696 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3700 Register SharedReg =
MI.getOperand(2).getReg();
3714 if (!
MRI.hasOneNonDBGUse(AndReg))
3721 return Y == SharedReg;
3725 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3728 std::tie(
X,
Y) = MatchInfo;
3731 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3732 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3733 MI.getOperand(2).setReg(
Y);
3739 Register DstReg = PtrAdd.getReg(0);
3740 LLT Ty =
MRI.getType(DstReg);
3743 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3758 Register Pow2Src1 =
MI.getOperand(2).getReg();
3759 LLT Ty =
MRI.getType(DstReg);
3762 auto NegOne =
Builder.buildConstant(Ty, -1);
3763 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3765 MI.eraseFromParent();
3769 unsigned &SelectOpNo)
const {
3781 !
MRI.hasOneNonDBGUse(LHS)) {
3782 OtherOperandReg = LHS;
3786 !
MRI.hasOneNonDBGUse(RHS))
3804 unsigned BinOpcode =
MI.getOpcode();
3809 bool CanFoldNonConst =
3810 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3815 if (CanFoldNonConst)
3840 LLT Ty =
MRI.getType(Dst);
3841 unsigned BinOpcode =
MI.getOpcode();
3848 if (SelectOperand == 1) {
3852 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3854 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3856 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3858 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3861 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3862 MI.eraseFromParent();
3865std::optional<SmallVector<Register, 8>>
3866CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3867 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3896 const unsigned MaxIter =
3898 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3906 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
3907 return std::nullopt;
3923 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
3924 return std::nullopt;
3936static std::optional<std::pair<GZExtLoad *, int64_t>>
3940 "Expected Reg to only have one non-debug use?");
3948 if (Shift % MemSizeInBits != 0)
3949 return std::nullopt;
3954 return std::nullopt;
3956 if (!
Load->isUnordered() ||
Load->getMemSizeInBits() != MemSizeInBits)
3957 return std::nullopt;
3959 return std::make_pair(
Load, Shift / MemSizeInBits);
3962std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
3963CombinerHelper::findLoadOffsetsForLoadOrCombine(
3966 const unsigned MemSizeInBits)
const {
3969 SmallSetVector<const MachineInstr *, 8> Loads;
3975 GZExtLoad *LowestIdxLoad =
nullptr;
3978 SmallSet<int64_t, 8> SeenIdx;
3982 MachineBasicBlock *
MBB =
nullptr;
3983 const MachineMemOperand *MMO =
nullptr;
3986 GZExtLoad *EarliestLoad =
nullptr;
3989 GZExtLoad *LatestLoad =
nullptr;
3998 for (
auto Reg : RegsToVisit) {
4003 return std::nullopt;
4006 std::tie(
Load, DstPos) = *LoadAndPos;
4010 MachineBasicBlock *LoadMBB =
Load->getParent();
4014 return std::nullopt;
4017 auto &LoadMMO =
Load->getMMO();
4021 return std::nullopt;
4028 LoadPtr =
Load->getOperand(1).getReg();
4033 if (!SeenIdx.
insert(Idx).second)
4034 return std::nullopt;
4041 if (BasePtr != LoadPtr)
4042 return std::nullopt;
4044 if (Idx < LowestIdx) {
4046 LowestIdxLoad =
Load;
4053 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4054 return std::nullopt;
4063 EarliestLoad =
Load;
4071 "Expected to find a load for each register?");
4072 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4073 LatestLoad &&
"Expected at least two loads?");
4082 const unsigned MaxIter = 20;
4088 if (
MI.isLoadFoldBarrier())
4089 return std::nullopt;
4090 if (Iter++ == MaxIter)
4091 return std::nullopt;
4094 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4100 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4113 LLT Ty =
MRI.getType(Dst);
4119 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4120 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4124 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4131 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4132 if (NarrowMemSizeInBits % 8 != 0)
4145 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4146 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4149 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4156 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4159 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4171 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4172 const unsigned ZeroByteOffset =
4176 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4177 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4178 ZeroOffsetIdx->second != LowestIdx)
4188 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4202 MIB.setInstrAndDebugLoc(*LatestLoad);
4203 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4204 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4206 MIB.buildBSwap(Dst, LoadDst);
4218 if (
MRI.getType(DstReg).isVector())
4222 if (!
MRI.hasOneNonDBGUse(DstReg))
4224 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4226 case TargetOpcode::G_ANYEXT:
4228 case TargetOpcode::G_ZEXT:
4229 case TargetOpcode::G_SEXT:
4236 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4243 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4245 switch (
DefMI->getOpcode()) {
4246 case TargetOpcode::G_LOAD:
4247 case TargetOpcode::G_TRUNC:
4248 case TargetOpcode::G_SEXT:
4249 case TargetOpcode::G_ZEXT:
4250 case TargetOpcode::G_ANYEXT:
4251 case TargetOpcode::G_CONSTANT:
4255 if (InSrcs.
size() > 2)
4269 LLT ExtTy =
MRI.getType(DstReg);
4276 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4277 auto SrcReg =
PHI.getIncomingValue(
I);
4281 if (!SrcMIs.
insert(SrcMI))
4287 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4288 InsertPt =
MBB->getFirstNonPHI();
4293 OldToNewSrcMap[SrcMI] = NewExt;
4298 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4299 NewPhi.addDef(DstReg);
4302 NewPhi.addMBB(MO.getMBB());
4305 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4306 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4314 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4318 LLT SrcTy =
MRI.getType(SrcVec);
4319 if (SrcTy.isScalableVector())
4323 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4326 unsigned VecIdx = Cst->Value.getZExtValue();
4338 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4339 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4343 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4355 LLT ScalarTy =
MRI.getType(Reg);
4357 LLT DstTy =
MRI.getType(DstReg);
4359 if (ScalarTy != DstTy) {
4361 Builder.buildTrunc(DstReg, Reg);
4362 MI.eraseFromParent();
4370 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4371 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4389 LLT DstTy =
MRI.getType(DstReg);
4394 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4399 unsigned Idx = Cst->getZExtValue();
4402 ExtractedElts.
set(Idx);
4403 SrcDstPairs.emplace_back(
4404 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4407 return ExtractedElts.
all();
4412 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4413 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4414 for (
auto &Pair : SrcDstPairs) {
4415 auto *ExtMI = Pair.second;
4417 ExtMI->eraseFromParent();
4419 MI.eraseFromParent();
4426 MI.eraseFromParent();
4436 bool AllowScalarConstants,
4438 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4441 LLT Ty =
MRI.getType(Dst);
4442 unsigned BitWidth = Ty.getScalarSizeInBits();
4444 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4445 unsigned FshOpc = 0;
4456 int64_t CstShlAmt = 0, CstLShrAmt;
4459 CstShlAmt + CstLShrAmt ==
BitWidth) {
4460 FshOpc = TargetOpcode::G_FSHR;
4466 FshOpc = TargetOpcode::G_FSHL;
4471 FshOpc = TargetOpcode::G_FSHR;
4476 LLT AmtTy =
MRI.getType(Amt);
4478 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4482 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4489 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4490 MI.getOpcode() == TargetOpcode::G_ROTR);
4492 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4494 bool OutOfRange =
false;
4495 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4497 OutOfRange |= CI->getValue().uge(Bitsize);
4504 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4505 MI.getOpcode() == TargetOpcode::G_ROTR);
4507 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4509 LLT AmtTy =
MRI.getType(Amt);
4510 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4511 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4513 MI.getOperand(2).setReg(Amt);
4518 int64_t &MatchInfo)
const {
4519 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4530 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4531 if (KnownRHS.isUnknown())
4534 std::optional<bool> KnownVal;
4535 if (KnownRHS.isZero()) {
4545 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4555 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4564 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4580 LLT DstTy =
MRI.getType(Dst);
4588 auto KnownLHS =
VT->getKnownBits(LHS);
4589 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4592 LLT LHSTy =
MRI.getType(LHS);
4595 unsigned Op = TargetOpcode::COPY;
4596 if (DstSize != LHSSize)
4597 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4608 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4612 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4618 int64_t AndMaskBits;
4626 if (AndMaskBits & OrMaskBits)
4632 if (
MI.getOperand(1).getReg() == AndMaskReg)
4633 MI.getOperand(2).setReg(AndMaskReg);
4634 MI.getOperand(1).setReg(Src);
4644 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4647 LLT Ty =
MRI.getType(Src);
4649 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4651 int64_t Width =
MI.getOperand(2).getImm();
4658 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4662 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4663 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4664 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4674 LLT Ty =
MRI.getType(Dst);
4678 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4681 int64_t AndImm, LSBImm;
4683 const unsigned Size = Ty.getScalarSizeInBits();
4691 uint64_t MaybeMask =
static_cast<uint64_t
>(AndImm);
4696 if (MaybeMask & (MaybeMask + 1))
4700 if (
static_cast<uint64_t
>(LSBImm) >=
Size)
4708 if (
static_cast<uint64_t
>(LSBImm) + Width >
Size)
4712 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4713 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4714 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4722 const unsigned Opcode =
MI.getOpcode();
4723 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4725 const Register Dst =
MI.getOperand(0).getReg();
4727 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4728 ? TargetOpcode::G_SBFX
4729 : TargetOpcode::G_UBFX;
4732 LLT Ty =
MRI.getType(Dst);
4734 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4740 const unsigned Size = Ty.getScalarSizeInBits();
4749 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4753 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4757 const int64_t Pos = ShrAmt - ShlAmt;
4758 const int64_t Width =
Size - ShrAmt;
4761 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4762 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4763 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4771 const unsigned Opcode =
MI.getOpcode();
4772 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4774 const Register Dst =
MI.getOperand(0).getReg();
4775 LLT Ty =
MRI.getType(Dst);
4777 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4789 const unsigned Size = Ty.getScalarSizeInBits();
4790 if (ShrAmt < 0 || ShrAmt >=
Size)
4794 if (0 == (SMask >> ShrAmt)) {
4796 B.buildConstant(Dst, 0);
4809 const int64_t Pos = ShrAmt;
4814 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4818 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4819 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4820 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4825bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4829 Register Src1Reg = PtrAdd.getBaseReg();
4834 Register Src2Reg = PtrAdd.getOffsetReg();
4836 if (
MRI.hasOneNonDBGUse(Src1Reg))
4846 const APInt &C1APIntVal = *
C1;
4847 const APInt &C2APIntVal = *C2;
4848 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4850 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4853 MachineInstr *ConvUseMI = &
UseMI;
4854 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4855 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4856 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4858 if (!
MRI.hasOneNonDBGUse(DefReg))
4860 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4869 TargetLoweringBase::AddrMode AM;
4872 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4874 PtrAdd.getMF()->getFunction().getContext());
4875 const auto &
TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4894 Register Src1Reg =
MI.getOperand(1).getReg();
4895 if (RHS->getOpcode() != TargetOpcode::G_ADD)
4907 unsigned PtrAddFlags =
MI.getFlags();
4908 unsigned AddFlags = RHS->getFlags();
4921 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
4924 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
4926 MI.getOperand(1).setReg(NewBase.getReg(0));
4927 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
4931 return !reassociationCanBreakAddressingModePattern(
MI);
4941 std::optional<ValueAndVReg> LHSCstOff;
4951 unsigned PtrAddFlags =
MI.getFlags();
4952 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
4954 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
4956 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
4970 LHSPtrAdd->moveBefore(&
MI);
4973 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
4975 MI.getOperand(2).setReg(NewCst.getReg(0));
4978 Observer.changingInstr(*LHSPtrAdd);
4979 LHSPtrAdd->getOperand(2).setReg(RHSReg);
4980 LHSPtrAdd->setFlags(Flags);
4983 return !reassociationCanBreakAddressingModePattern(
MI);
4994 Register Src2Reg =
MI.getOperand(2).getReg();
4995 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
4996 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5009 unsigned PtrAddFlags =
MI.getFlags();
5010 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5023 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *
C1 + *C2);
5025 MI.getOperand(1).setReg(LHSSrc1);
5026 MI.getOperand(2).setReg(NewCst.getReg(0));
5030 return !reassociationCanBreakAddressingModePattern(
MI);
5070 LLT OpRHSTy =
MRI.getType(OpRHS);
5087 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5088 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5096 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5097 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5110 unsigned Opc =
MI.getOpcode();
5126 LLT DstTy =
MRI.getType(Dst);
5127 unsigned Opc =
MI.getOpcode();
5140 for (
unsigned I = 0, E = BV->getNumSources();
I != E; ++
I) {
5147 B.buildBuildVectorConstant(Dst, Csts);
5154 B.buildConstant(Dst, Cst);
5165 LLT DstTy =
MRI.getType(Dst);
5168 MI.getOpcode(), DstTy,
MI.getOperand(1).getReg(),
MRI);
5173 if (Csts.
size() == 1)
5174 B.buildConstant(Dst, Csts[0]);
5176 B.buildBuildVectorConstant(Dst, Csts);
5186 LLT DstTy =
MRI.getType(Dst);
5200 B.buildBuildVectorConstant(Dst, Csts);
5209 B.buildConstant(Dst, Cst);
5234 LLT DstTy =
MRI.getType(Dst);
5247 B.buildBuildVectorFConstant(Dst, Csts);
5256 B.buildFConstant(Dst, Cst);
5265 LLT DstTy =
MRI.getType(Dst);
5266 LLT SrcTy =
MRI.getType(Src);
5273 if (SrcTy.isVector() &&
5283 if (Csts.
size() == 1)
5284 B.buildFConstant(Dst, Csts[0]);
5286 B.buildBuildVectorFConstant(Dst, Csts);
5293 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5294 MI.getOpcode() == TargetOpcode::G_FMAD);
5296 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5297 LLT DstTy =
MRI.getType(Dst);
5315 if (!BV1 || !BV2 || !BV3)
5317 unsigned NumElts = BV1->getNumSources();
5318 if (BV2->getNumSources() != NumElts || BV3->getNumSources() != NumElts)
5321 for (
unsigned I = 0;
I != NumElts; ++
I) {
5325 if (!
C1 || !C2 || !C3)
5331 B.buildBuildVectorFConstant(Dst, Csts);
5339 if (!Op1Cst || !Op2Cst || !Op3Cst)
5367 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5371 LLT WideTy =
MRI.getType(Dst);
5375 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5391 case TargetOpcode::G_ADD:
5392 case TargetOpcode::G_SUB:
5393 case TargetOpcode::G_MUL:
5394 case TargetOpcode::G_AND:
5395 case TargetOpcode::G_OR:
5396 case TargetOpcode::G_XOR:
5404 auto Mask = Cst->Value;
5409 unsigned NarrowWidth = Mask.countr_one();
5415 auto &MF = *
MI.getMF();
5418 if (!
TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5419 !
TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5427 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5428 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5430 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5431 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5433 MI.getOperand(1).setReg(Ext.getReg(0));
5442 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5443 MI.getOpcode() == TargetOpcode::G_SMULO);
5452 B.buildConstant(Dst, 0);
5453 B.buildConstant(Carry, 0);
5461 if (SrcA.
isValid() && SrcA == SrcB)
5469 unsigned Opcode =
MI.getOpcode();
5470 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5472 Register Dst = UDivorRem.getReg(0);
5473 Register LHS = UDivorRem.getReg(1);
5474 Register RHS = UDivorRem.getReg(2);
5475 LLT Ty =
MRI.getType(Dst);
5483 bool UseSRL =
false;
5488 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5490 if (IsSplat && !Factors.
empty()) {
5497 APInt Divisor = CI->getValue();
5506 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5507 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5517 if (Ty.isVector()) {
5518 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5519 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5522 Factor = Factors[0];
5530 return MIB.buildMul(Ty, Res, Factor);
5533 unsigned KnownLeadingZeros =
5534 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5536 bool UseNPQ =
false;
5538 auto BuildUDIVPattern = [&](
const Constant *
C) {
5540 const APInt &Divisor = CI->getValue();
5542 bool SelNPQ =
false;
5544 unsigned PreShift = 0, PostShift = 0;
5549 if (!Divisor.
isOne()) {
5555 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5557 Magic = std::move(magics.
Magic);
5560 "We shouldn't generate an undefined shift!");
5562 "We shouldn't generate an undefined shift!");
5566 SelNPQ = magics.
IsAdd;
5570 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5571 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5573 MIB.buildConstant(ScalarTy,
5578 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5586 assert(Matched &&
"Expected unary predicate match to succeed");
5588 Register PreShift, PostShift, MagicFactor, NPQFactor;
5591 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5592 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5593 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5594 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5597 "Non-build_vector operation should have been a scalar");
5598 PreShift = PreShifts[0];
5599 MagicFactor = MagicFactors[0];
5600 PostShift = PostShifts[0];
5604 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5607 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5610 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5615 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5617 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5619 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5622 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5623 auto One = MIB.buildConstant(Ty, 1);
5624 auto IsOne = MIB.buildICmp(
5628 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5630 if (Opcode == TargetOpcode::G_UREM) {
5631 auto Prod = MIB.buildMul(Ty, ret, RHS);
5632 return MIB.buildSub(Ty, LHS, Prod);
5638 unsigned Opcode =
MI.getOpcode();
5639 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5642 LLT DstTy =
MRI.getType(Dst);
5644 auto &MF = *
MI.getMF();
5654 if (MF.getFunction().hasMinSize())
5657 if (Opcode == TargetOpcode::G_UDIV &&
5660 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5675 {TargetOpcode::G_ICMP,
5679 if (Opcode == TargetOpcode::G_UREM &&
5685 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5694 unsigned Opcode =
MI.getOpcode();
5695 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5698 LLT DstTy =
MRI.getType(Dst);
5702 auto &MF = *
MI.getMF();
5712 if (MF.getFunction().hasMinSize())
5716 if (Opcode == TargetOpcode::G_SDIV &&
5719 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5734 if (Opcode == TargetOpcode::G_SREM &&
5740 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5749 unsigned Opcode =
MI.getOpcode();
5750 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5751 Opcode == TargetOpcode::G_SREM);
5753 Register Dst = SDivorRem.getReg(0);
5754 Register LHS = SDivorRem.getReg(1);
5755 Register RHS = SDivorRem.getReg(2);
5756 LLT Ty =
MRI.getType(Dst);
5763 bool UseSRA =
false;
5769 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5771 if (IsSplat && !ExactFactors.
empty()) {
5773 ExactFactors.
push_back(ExactFactors[0]);
5778 APInt Divisor = CI->getValue();
5788 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5789 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5797 assert(Matched &&
"Expected unary predicate match to succeed");
5800 if (Ty.isVector()) {
5801 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5802 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5804 Shift = ExactShifts[0];
5805 Factor = ExactFactors[0];
5813 return MIB.buildMul(Ty, Res, Factor);
5818 auto BuildSDIVPattern = [&](
const Constant *
C) {
5820 const APInt &Divisor = CI->getValue();
5824 int NumeratorFactor = 0;
5835 NumeratorFactor = 1;
5838 NumeratorFactor = -1;
5841 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5842 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5844 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5845 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5853 assert(Matched &&
"Expected unary predicate match to succeed");
5855 Register MagicFactor, Factor, Shift, ShiftMask;
5858 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5859 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5860 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5861 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5864 "Non-build_vector operation should have been a scalar");
5865 MagicFactor = MagicFactors[0];
5866 Factor = Factors[0];
5868 ShiftMask = ShiftMasks[0];
5872 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5875 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5876 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5879 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5882 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5883 auto T = MIB.buildLShr(Ty, Q, SignShift);
5884 T = MIB.buildAnd(Ty,
T, ShiftMask);
5885 auto ret = MIB.buildAdd(Ty, Q,
T);
5887 if (Opcode == TargetOpcode::G_SREM) {
5888 auto Prod = MIB.buildMul(Ty, ret, RHS);
5889 return MIB.buildSub(Ty, LHS, Prod);
5895 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5896 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5897 "Expected SDIV or UDIV");
5900 auto MatchPow2 = [&](
const Constant *
C) {
5902 return CI && (CI->getValue().isPowerOf2() ||
5903 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5909 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5914 LLT Ty =
MRI.getType(Dst);
5934 unsigned BitWidth = Ty.getScalarSizeInBits();
5938 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5939 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits,
C1);
5951 auto One =
Builder.buildConstant(Ty, 1);
5952 auto MinusOne =
Builder.buildConstant(Ty, -1);
5956 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5957 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5961 auto Neg =
Builder.buildNeg(Ty, AShr);
5963 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5964 MI.eraseFromParent();
5968 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5973 LLT Ty =
MRI.getType(Dst);
5976 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5977 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS,
C1);
5978 MI.eraseFromParent();
5992 return CI && CI->getValue().isPowerOf2();
5996 LLT Ty =
MRI.getType(Dst);
5997 LLT ShiftTy =
MRI.getType(Shift);
6010 auto Amount =
B.buildAdd(ShiftTy, Shift,
Log2);
6011 B.buildLShr(Dst, LHS, Amount, Flags);
6021 if (!
VT || !
VT->signBitIsZero(LHS) || !
VT->signBitIsZero(RHS))
6024 LLT Ty =
MRI.getType(Dst);
6029 assert(
MI.getOpcode() == TargetOpcode::G_SREM &&
"Expected SREM");
6034 LLT Ty =
MRI.getType(Dst);
6053 unsigned BitWidth = Ty.getScalarSizeInBits();
6054 auto AbsRHS =
Builder.buildAbs(Ty, RHS);
6055 auto Mask =
Builder.buildSub(Ty, AbsRHS,
Builder.buildConstant(Ty, 1));
6057 auto Sign =
Builder.buildAShr(Ty, LHS, BWMinusOne);
6059 auto Biased =
Builder.buildAdd(Ty, LHS, Bias);
6062 MI.eraseFromParent();
6066 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6069 LLT Ty =
MRI.getType(Dst);
6070 LLT RHSTy =
MRI.getType(RHS);
6072 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6074 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6089 LLT Ty =
MRI.getType(Dst);
6095 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6096 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6097 Builder.buildLShr(Dst, LHS, Trunc);
6098 MI.eraseFromParent();
6105 LLT DstTy =
MRI.getType(Dst);
6106 LLT SrcTy =
MRI.getType(Src);
6108 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6109 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6112 {TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6141 Builder.buildTruncSSatS(Dst, MatchInfo);
6142 MI.eraseFromParent();
6149 LLT DstTy =
MRI.getType(Dst);
6150 LLT SrcTy =
MRI.getType(Src);
6152 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6153 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6156 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6174 Builder.buildTruncSSatU(Dst, MatchInfo);
6175 MI.eraseFromParent();
6182 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6183 LLT SrcTy =
MRI.getType(Val);
6185 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6186 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6189 {TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6198 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6206 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6209 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6211 const auto LHSCst = Ty.isVector()
6225 if (LHSCst->Value.isNegZero())
6229 if (LHSCst->Value.isPosZero())
6238 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6246 MRI.use_instr_nodbg_end()) >
6248 MRI.use_instr_nodbg_end());
6252 bool &AllowFusionGlobally,
6254 bool CanReassociate)
const {
6256 auto *MF =
MI.getMF();
6257 const auto &
TLI = *MF->getSubtarget().getTargetLowering();
6258 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6266 bool HasFMA =
TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6269 if (!HasFMAD && !HasFMA)
6274 AllowFusionGlobally = HasFMAD;
6286 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6288 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6300 unsigned PreferredFusedOpcode =
6301 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6314 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6316 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6317 {LHS.MI->getOperand(1).getReg(),
6318 LHS.MI->getOperand(2).getReg(), RHS.Reg},
6327 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6329 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6330 {RHS.MI->getOperand(1).getReg(),
6331 RHS.MI->getOperand(2).getReg(), LHS.Reg},
6343 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6345 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6349 const auto &
TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6358 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6360 unsigned PreferredFusedOpcode =
6361 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6364 bool LHSContractable =
6367 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6370 bool RHSContractable =
6373 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6377 if (LHSContractable || RHSContractable) {
6380 if (!LHSContractable ||
6381 (RHSContractable &&
hasMoreUses(*LHSFpExtSrc, *RHSFpExtSrc,
MRI))) {
6383 LHSFpExtSrc = RHSFpExtSrc;
6386 unsigned Flags =
MI.getFlags() & LHSFpExtSrc->
getFlags();
6390 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6391 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg}, Flags);
6402 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6404 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6416 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6418 unsigned PreferredFusedOpcode =
6419 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6424 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6427 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6428 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6433 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6436 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6437 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6446 Register X = FMA->getOperand(1).getReg();
6447 Register Y = FMA->getOperand(2).getReg();
6450 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6451 unsigned OuterFlags =
MI.getFlags() & FMA->getFlags();
6454 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6455 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z}, InnerFlags);
6456 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6457 {
X,
Y, InnerFMA}, OuterFlags);
6468 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6470 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6477 const auto &
TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6478 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6488 unsigned PreferredFusedOpcode =
6489 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6503 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6504 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6505 Register InnerFMA =
B.buildInstr(PreferredFusedOpcode, {DstType},
6506 {FpExtU, FpExtV, Z}, InnerFlags)
6508 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6509 {
X,
Y, InnerFMA}, OuterFlags);
6515 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6519 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6521 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6522 unsigned OuterFlags =
MI.getFlags() & LHS.MI->getFlags();
6526 LHS.MI->getOperand(1).getReg(),
6527 LHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6538 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6543 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6545 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6546 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6550 X =
B.buildFPExt(DstType,
X).getReg(0);
6551 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6554 InnerFlags, OuterFlags,
B);
6563 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6567 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6569 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6570 unsigned OuterFlags =
MI.getFlags() & RHS.MI->getFlags();
6574 RHS.MI->getOperand(1).getReg(),
6575 RHS.MI->getOperand(2).getReg(), InnerFlags, OuterFlags,
B);
6586 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6591 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6593 unsigned InnerFlags =
MI.getFlags() & FMulMI->
getFlags();
6594 unsigned OuterFlags =
MI.getFlags() & FMAMI->
getFlags();
6598 X =
B.buildFPExt(DstType,
X).getReg(0);
6599 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6602 InnerFlags, OuterFlags,
B);
6614 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6616 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6628 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6632 int FirstMulHasFewerUses =
true;
6636 FirstMulHasFewerUses =
false;
6638 unsigned PreferredFusedOpcode =
6639 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6642 if (FirstMulHasFewerUses &&
6645 unsigned Flags =
MI.getFlags() & LHS.MI->getFlags();
6647 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6648 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6649 {LHS.MI->getOperand(1).getReg(),
6650 LHS.MI->getOperand(2).getReg(), NegZ},
6658 unsigned Flags =
MI.getFlags() & RHS.MI->getFlags();
6661 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6662 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6663 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg}, Flags);
6674 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6676 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6682 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6684 unsigned PreferredFusedOpcode =
6685 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6693 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6697 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6698 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6709 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6711 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6725 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6727 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6733 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6735 unsigned PreferredFusedOpcode =
6736 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6743 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6749 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6750 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6751 {FpExtX, FpExtY, NegZ}, Flags);
6760 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6764 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6767 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6768 {NegY, FpExtZ, LHSReg}, Flags);
6779 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6781 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6785 const auto &
TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6786 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6790 unsigned PreferredFusedOpcode =
6791 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6795 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6796 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6797 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z}, Flags);
6808 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6810 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6812 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6815 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6825 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6827 unsigned Flags =
MI.getFlags() & FMulMI->
getFlags();
6843 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6853 return N0CFP && (N0CFP->isOne() || N0CFP->isMinusOne());
6870 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6871 if (&U == &
MI || U.getParent() !=
MI.getParent())
6873 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6874 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y &&
6875 !IsOne(U.getOperand(1).getReg())) {
6888 return MatchInfo.
size() >= MinUses;
6896 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6897 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6898 MatchInfo[0]->getOperand(2).getReg(),
6899 MatchInfo[0]->getFlags());
6904 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6905 Div->getOperand(0).getReg(),
MI->getFlags());
6906 MI->eraseFromParent();
6928 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6937 return MRI.getType(MatchInfo) == DstVecTy;
6940 std::optional<ValueAndVReg> ShiftAmount;
6949 return MRI.getType(MatchInfo) == DstVecTy;
6964 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6971 std::optional<ValueAndVReg> ShiftAmt;
6977 LLT MatchTy =
MRI.getType(MatchInfo);
6978 return ShiftAmt->Value.getZExtValue() == MatchTy.
getSizeInBits() &&
6979 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6982unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6984 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6985 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6986 "Expected a NaN behaviour?");
6996 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6997 return TargetOpcode::G_FMAXNUM;
6998 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6999 return TargetOpcode::G_FMAXIMUM;
7000 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
7001 return TargetOpcode::G_FMAXNUM;
7002 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
7003 return TargetOpcode::G_FMAXIMUM;
7009 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
7010 return TargetOpcode::G_FMINNUM;
7011 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
7012 return TargetOpcode::G_FMINIMUM;
7013 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
7014 return TargetOpcode::G_FMINNUM;
7015 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
7017 return TargetOpcode::G_FMINIMUM;
7021CombinerHelper::SelectPatternNaNBehaviour
7023 bool IsOrderedComparison)
const {
7024 bool LHSSafe =
VT->isKnownNeverNaN(
LHS);
7025 bool RHSSafe =
VT->isKnownNeverNaN(
RHS);
7027 if (!LHSSafe && !RHSSafe)
7028 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7029 if (LHSSafe && RHSSafe)
7030 return SelectPatternNaNBehaviour::RETURNS_ANY;
7033 if (IsOrderedComparison)
7034 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7035 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7038 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7039 : SelectPatternNaNBehaviour::RETURNS_NAN;
7048 LLT DstTy =
MRI.getType(Dst);
7061 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7063 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7065 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7068 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7069 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7070 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7071 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7073 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7076 unsigned Opc = getFPMinMaxOpcForSelect(
Pred, DstTy, ResWithKnownNaNInfo);
7081 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7086 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7088 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7092 MatchInfo = [=](MachineIRBuilder &
B) {
7093 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7101 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7108 Register TrueVal =
MI.getOperand(2).getReg();
7109 Register FalseVal =
MI.getOperand(3).getReg();
7110 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7115 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7128 if (MatchedSub &&
X != OpLHS)
7136 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7139 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7140 B.buildICmp(Pred, Dst,
Y,
Zero);
7147static std::optional<unsigned>
7149 std::optional<int64_t> &Result) {
7150 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7151 Opcode == TargetOpcode::G_ASHR) &&
7152 "Expect G_SHL, G_LSHR or G_ASHR.");
7153 auto SignificantBits = 0;
7155 case TargetOpcode::G_SHL:
7159 case TargetOpcode::G_LSHR:
7163 case TargetOpcode::G_ASHR:
7172 Result = std::nullopt;
7184 Register ShiftVal =
MI.getOperand(1).getReg();
7185 Register ShiftReg =
MI.getOperand(2).getReg();
7186 LLT ResTy =
MRI.getType(Dst);
7187 std::optional<int64_t> Result;
7188 auto IsShiftTooBig = [&](
const Constant *
C) {
7193 Result = std::nullopt;
7196 auto OptMaxUsefulShift =
7198 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7208 int64_t Val = *Result;
7214 unsigned LHSOpndIdx = 1;
7215 unsigned RHSOpndIdx = 2;
7216 switch (
MI.getOpcode()) {
7217 case TargetOpcode::G_UADDO:
7218 case TargetOpcode::G_SADDO:
7219 case TargetOpcode::G_UMULO:
7220 case TargetOpcode::G_SMULO:
7227 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7228 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7238 if (LHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7242 return RHSDef->
getOpcode() != TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7249 std::optional<FPValueAndVReg> ValAndVReg;
7255bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7256 LLT SrcTy =
MRI.getType(Src);
7257 if (SrcTy.isFixedVector())
7259 if (SrcTy.isScalar()) {
7263 return IConstant && IConstant->Value == 1;
7268bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7269 LLT SrcTy =
MRI.getType(Src);
7271 return isConstantSplatVector(Src, 0, AllowUndefs);
7276 return IConstant && IConstant->Value == 0;
7283bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7284 bool AllowUndefs)
const {
7290 for (
unsigned I = 0;
I < NumSources; ++
I) {
7291 GImplicitDef *ImplicitDef =
7293 if (ImplicitDef && AllowUndefs)
7295 if (ImplicitDef && !AllowUndefs)
7297 std::optional<ValueAndVReg> IConstant =
7299 if (IConstant && IConstant->Value == SplatValue)
7309CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7312 return IConstant->Value;
7316 return std::nullopt;
7319 std::optional<APInt>
Value = std::nullopt;
7320 for (
unsigned I = 0;
I < NumSources; ++
I) {
7321 std::optional<ValueAndVReg> IConstant =
7324 return std::nullopt;
7326 Value = IConstant->Value;
7327 else if (*
Value != IConstant->Value)
7328 return std::nullopt;
7334bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7344 for (
unsigned I = 0;
I < NumSources; ++
I) {
7345 std::optional<ValueAndVReg> IConstant =
7354bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7361 LLT CondTy =
MRI.getType(
Select->getCondReg());
7362 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7372 std::optional<ValueAndVReg> TrueOpt =
7374 std::optional<ValueAndVReg> FalseOpt =
7377 if (!TrueOpt || !FalseOpt)
7380 APInt TrueValue = TrueOpt->Value;
7381 APInt FalseValue = FalseOpt->Value;
7385 MatchInfo = [=](MachineIRBuilder &
B) {
7386 B.setInstrAndDebugLoc(*
Select);
7387 B.buildZExtOrTrunc(Dest,
Cond);
7394 MatchInfo = [=](MachineIRBuilder &
B) {
7395 B.setInstrAndDebugLoc(*
Select);
7396 B.buildSExtOrTrunc(Dest,
Cond);
7403 MatchInfo = [=](MachineIRBuilder &
B) {
7404 B.setInstrAndDebugLoc(*
Select);
7405 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7406 B.buildNot(Inner,
Cond);
7407 B.buildZExtOrTrunc(Dest, Inner);
7414 MatchInfo = [=](MachineIRBuilder &
B) {
7415 B.setInstrAndDebugLoc(*
Select);
7416 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7417 B.buildNot(Inner,
Cond);
7418 B.buildSExtOrTrunc(Dest, Inner);
7424 if (TrueValue - 1 == FalseValue) {
7425 MatchInfo = [=](MachineIRBuilder &
B) {
7426 B.setInstrAndDebugLoc(*
Select);
7427 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7428 B.buildZExtOrTrunc(Inner,
Cond);
7429 B.buildAdd(Dest, Inner,
False);
7435 if (TrueValue + 1 == FalseValue) {
7436 MatchInfo = [=](MachineIRBuilder &
B) {
7437 B.setInstrAndDebugLoc(*
Select);
7438 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7439 B.buildSExtOrTrunc(Inner,
Cond);
7440 B.buildAdd(Dest, Inner,
False);
7447 MatchInfo = [=](MachineIRBuilder &
B) {
7448 B.setInstrAndDebugLoc(*
Select);
7449 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7450 B.buildZExtOrTrunc(Inner,
Cond);
7453 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7454 B.buildShl(Dest, Inner, ShAmtC, Flags);
7461 MatchInfo = [=](MachineIRBuilder &
B) {
7462 B.setInstrAndDebugLoc(*
Select);
7464 B.buildNot(Not,
Cond);
7465 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7466 B.buildZExtOrTrunc(Inner, Not);
7469 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7470 B.buildShl(Dest, Inner, ShAmtC, Flags);
7477 MatchInfo = [=](MachineIRBuilder &
B) {
7478 B.setInstrAndDebugLoc(*
Select);
7479 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7480 B.buildSExtOrTrunc(Inner,
Cond);
7481 B.buildOr(Dest, Inner,
False, Flags);
7488 MatchInfo = [=](MachineIRBuilder &
B) {
7489 B.setInstrAndDebugLoc(*
Select);
7491 B.buildNot(Not,
Cond);
7492 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7493 B.buildSExtOrTrunc(Inner, Not);
7494 B.buildOr(Dest, Inner,
True, Flags);
7503bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7510 LLT CondTy =
MRI.getType(
Select->getCondReg());
7511 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7520 if (CondTy != TrueTy)
7526 MatchInfo = [=](MachineIRBuilder &
B) {
7527 B.setInstrAndDebugLoc(*
Select);
7528 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7529 B.buildZExtOrTrunc(Ext,
Cond);
7530 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7531 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7539 MatchInfo = [=](MachineIRBuilder &
B) {
7540 B.setInstrAndDebugLoc(*
Select);
7541 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7542 B.buildZExtOrTrunc(Ext,
Cond);
7543 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7544 B.buildAnd(DstReg, Ext, FreezeTrue);
7550 if (isOneOrOneSplat(
False,
true)) {
7551 MatchInfo = [=](MachineIRBuilder &
B) {
7552 B.setInstrAndDebugLoc(*
Select);
7554 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7555 B.buildNot(Inner,
Cond);
7557 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7558 B.buildZExtOrTrunc(Ext, Inner);
7559 auto FreezeTrue =
B.buildFreeze(TrueTy,
True);
7560 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7566 if (isZeroOrZeroSplat(
True,
true)) {
7567 MatchInfo = [=](MachineIRBuilder &
B) {
7568 B.setInstrAndDebugLoc(*
Select);
7570 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7571 B.buildNot(Inner,
Cond);
7573 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7574 B.buildZExtOrTrunc(Ext, Inner);
7575 auto FreezeFalse =
B.buildFreeze(TrueTy,
False);
7576 B.buildAnd(DstReg, Ext, FreezeFalse);
7598 LLT DstTy =
MRI.getType(DstReg);
7603 if (!
MRI.hasOneNonDBGUse(CondReg))
7612 if (
True == CmpRHS &&
False == CmpLHS) {
7660 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7661 Register DestReg =
MI.getOperand(0).getReg();
7662 LLT DestTy =
MRI.getType(DestReg);
7676 if (
isLegal({NewOpc, {DestTy}})) {
7678 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7690 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7693 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7703bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7705 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7706 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7710 unsigned Flags = Logic->
getFlags();
7723 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7729 std::optional<ValueAndVReg> MaybeC1 =
7733 C1 = MaybeC1->Value;
7735 std::optional<ValueAndVReg> MaybeC2 =
7739 C2 = MaybeC2->Value;
7746 LLT CmpOperandTy =
MRI.getType(R1);
7760 std::optional<APInt> Offset1;
7761 std::optional<APInt> Offset2;
7764 std::optional<ValueAndVReg> MaybeOffset1 =
7767 R1 =
Add->getLHSReg();
7768 Offset1 = MaybeOffset1->Value;
7772 std::optional<ValueAndVReg> MaybeOffset2 =
7775 R2 =
Add->getLHSReg();
7776 Offset2 = MaybeOffset2->Value;
7795 bool CreateMask =
false;
7808 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7821 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7830 MatchInfo = [=](MachineIRBuilder &
B) {
7831 if (CreateMask &&
Offset != 0) {
7832 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7833 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7834 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7835 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7836 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7837 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7838 B.buildZExtOrTrunc(DstReg, ICmp);
7839 }
else if (CreateMask &&
Offset == 0) {
7840 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7841 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7842 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7843 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7844 B.buildZExtOrTrunc(DstReg, ICmp);
7845 }
else if (!CreateMask &&
Offset != 0) {
7846 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7847 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7848 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7849 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7850 B.buildZExtOrTrunc(DstReg, ICmp);
7851 }
else if (!CreateMask &&
Offset == 0) {
7852 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7853 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7854 B.buildZExtOrTrunc(DstReg, ICmp);
7862bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7868 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7880 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7886 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7887 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7888 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7889 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7900 if (LHS0 == RHS1 && LHS1 == RHS0) {
7906 if (LHS0 == RHS0 && LHS1 == RHS1) {
7910 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7912 MatchInfo = [=](MachineIRBuilder &
B) {
7917 auto False =
B.buildConstant(CmpTy, 0);
7918 B.buildZExtOrTrunc(DestReg,
False);
7925 B.buildZExtOrTrunc(DestReg,
True);
7927 auto Cmp =
B.buildFCmp(
Pred, CmpTy, LHS0, LHS1, Flags);
7928 B.buildZExtOrTrunc(DestReg, Cmp);
7940 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7943 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7952 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7955 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7970 bool IsSigned =
Add->isSigned();
7971 LLT DstTy =
MRI.getType(Dst);
7972 LLT CarryTy =
MRI.getType(Carry);
7975 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7978 B.buildSAddo(Dst, Carry, RHS, LHS);
7984 B.buildUAddo(Dst, Carry, RHS, LHS);
7989 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7990 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7996 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7997 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7999 B.buildConstant(Dst, Result);
8000 B.buildConstant(Carry, Overflow);
8008 B.buildCopy(Dst, LHS);
8009 B.buildConstant(Carry, 0);
8018 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8021 std::optional<APInt> MaybeAddRHS =
8022 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8025 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8026 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8030 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8031 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8037 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8038 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8063 B.buildConstant(Carry, 0);
8070 B.buildAdd(Dst, LHS, RHS);
8071 B.buildConstant(Carry, 1);
8083 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8086 B.buildConstant(Carry, 0);
8102 B.buildConstant(Carry, 0);
8109 B.buildAdd(Dst, LHS, RHS);
8110 B.buildConstant(Carry, 1);
8128 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8134 auto [Dst,
Base] =
MI.getFirst2Regs();
8135 LLT Ty =
MRI.getType(Dst);
8139 Builder.buildFConstant(Dst, 1.0);
8140 MI.removeFromParent();
8152 std::optional<SrcOp> Res;
8154 while (ExpVal > 0) {
8159 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8162 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8169 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8173 MI.eraseFromParent();
8184 if (!
MRI.hasOneNonDBGUse(
Sub->getLHSReg()))
8191 LLT DstTy =
MRI.getType(Dst);
8194 auto Const =
B.buildConstant(DstTy,
C1 - C2);
8195 B.buildAdd(Dst,
A, Const);
8209 if (!
MRI.hasOneNonDBGUse(
Sub->getRHSReg()))
8216 LLT DstTy =
MRI.getType(Dst);
8219 auto Const =
B.buildConstant(DstTy, C2 -
C1);
8220 B.buildSub(Dst, Const,
A);
8241 LLT DstTy =
MRI.getType(Dst);
8244 auto Const =
B.buildConstant(DstTy,
C1 + C2);
8245 B.buildSub(Dst,
A, Const);
8266 LLT DstTy =
MRI.getType(Dst);
8269 auto Const =
B.buildConstant(DstTy,
C1 - C2);
8270 B.buildSub(Dst, Const,
A);
8284 if (!
MRI.hasOneNonDBGUse(
Add->getLHSReg()))
8291 LLT DstTy =
MRI.getType(Dst);
8294 auto Const =
B.buildConstant(DstTy, C2 -
C1);
8295 B.buildAdd(Dst,
A, Const);
8339 if (!
MRI.hasOneNonDBGUse(BV->
getReg(0)))
8347 LLT SmallBvTy = DstTy;
8351 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8356 {TargetOpcode::G_ANYEXT,
8368 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8369 Ops.push_back(AnyExt.getReg(0));
8387 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8388 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8389 const unsigned NumDstElts = OrigMask.
size();
8390 for (
unsigned i = 0; i != NumDstElts; ++i) {
8391 int Idx = OrigMask[i];
8392 if (Idx >= (
int)NumSrcElems) {
8403 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8404 std::move(NewMask));
8411 const unsigned MaskSize = Mask.size();
8412 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8417 if (Idx < (
int)NumElems)
8418 Mask[
I] = Idx + NumElems;
8420 Mask[
I] = Idx - NumElems;
8430 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8433 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8436 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8437 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8439 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8443 const unsigned NumSrcElems = Src1Ty.getNumElements();
8445 bool TouchesSrc1 =
false;
8446 bool TouchesSrc2 =
false;
8447 const unsigned NumElems = Mask.size();
8448 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8452 if (Mask[Idx] < (
int)NumSrcElems)
8458 if (TouchesSrc1 == TouchesSrc2)
8461 Register NewSrc1 = Shuffle.getSrc1Reg();
8464 NewSrc1 = Shuffle.getSrc2Reg();
8469 auto Undef =
B.buildUndef(Src1Ty);
8470 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8484 LLT DstTy =
MRI.getType(Dst);
8485 LLT CarryTy =
MRI.getType(Carry);
8507 B.buildConstant(Carry, 0);
8514 B.buildSub(Dst, LHS, RHS);
8532 B.buildConstant(Carry, 0);
8539 B.buildSub(Dst, LHS, RHS);
8556 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON) &&
8557 "Expected G_CTLZ variant");
8562 LLT Ty =
MRI.getType(Dst);
8563 LLT SrcTy =
MRI.getType(Src);
8565 if (!(Ty.isValid() && Ty.isScalar()))
8574 switch (
LI->getAction(Query).Action) {
8585 bool NeedAdd =
true;
8593 unsigned BitWidth = Ty.getScalarSizeInBits();
8604 B.buildCTLS(Dst,
X);
8608 auto Ctls =
B.buildCTLS(Ty,
X);
8609 auto One =
B.buildConstant(Ty, 1);
8611 B.buildAdd(Dst, Ctls, One);
8619 return C &&
C->getValueAPF().isNaN();
8623 unsigned ZeroPoisonOpc)
const {
8624 const bool IsCtlzPair =
Opc == TargetOpcode::G_CTLZ &&
8625 ZeroPoisonOpc == TargetOpcode::G_CTLZ_ZERO_POISON;
8626 const bool IsCttzPair =
Opc == TargetOpcode::G_CTTZ &&
8627 ZeroPoisonOpc == TargetOpcode::G_CTTZ_ZERO_POISON;
8628 if (
MI.getOpcode() !=
Opc || (!IsCtlzPair && !IsCttzPair))
8634 if (!
VT->isKnownNeverZero(Src))
8637 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
8638 LLT SrcTy =
MRI.getType(Src);
8644 assert((Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) &&
8645 "Expected G_AND or G_OR");
8647 ~(Opcode == TargetOpcode::G_AND ? OtherKnown.
Zero : OtherKnown.
One);
8650static std::optional<unsigned>
8652 if (!Amt || Amt->uge(BW))
8653 return std::nullopt;
8654 return Amt->getZExtValue();
8661 "shift amount must be less than the bit width");
8663 case TargetOpcode::G_SHL:
8665 case TargetOpcode::G_LSHR:
8667 case TargetOpcode::G_ASHR: {
8678Register CombinerHelper::simplifyMultipleUseDemandedBits(
8680 assert(
R.isVirtual() &&
"Expected a virtual register");
8681 assert(!DemandedBits.
isZero() &&
"Zero demand is handled by the caller");
8685 [[maybe_unused]] LLT Ty =
MRI.getType(R);
8688 "DemandedBits width must match the register scalar type");
8690 MachineInstr *
DefMI =
MRI.getVRegDef(R);
8691 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8700 "Logical operands must match the result type");
8703 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8706 bool BypassToX = Opcode == TargetOpcode::G_AND
8711 simplifyMultipleUseDemandedBits(
X, DemandedBits,
Depth + 1))
8715 bool BypassToC = Opcode == TargetOpcode::G_AND
8725 return LookThrough(
RHS,
LHS);
8728bool CombinerHelper::simplifyDemandedBitsImpl(
MachineInstr &
MI,
unsigned OpNo,
8731 bool DoRewrite)
const {
8733 assert(
MI.getOperand(OpNo).isReg() && !
MI.getOperand(OpNo).isDef() &&
8734 "Expected a register use");
8735 Register OpReg =
MI.getOperand(OpNo).getReg();
8737 LLT OpTy =
MRI.getType(OpReg);
8740 "DemandedBits width must match the operand scalar type");
8742 MachineInstr *
DefMI =
MRI.getVRegDef(OpReg);
8743 assert(
DefMI &&
"Expected a definition in generic SSA MIR");
8745 auto DropPoisonFlags = [&]() {
8754 auto InvalidateDebugUses = [&](
const APInt &Demanded) {
8755 if (DoRewrite && !Demanded.isAllOnes())
8756 MRI.markUsesInDebugValueAsUndef(OpReg);
8758 auto Rewrite = [&](
Register Repl) {
8759 if (!DoRewrite || Repl == OpReg)
8760 return Repl != OpReg;
8763 InvalidateDebugUses(DemandedBits);
8772 if (DemandedBits.
isZero()) {
8777 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8782 Builder.setInsertPt(SaveMBB, SavePt);
8794 auto GiveUp = [&]() {
8807 APInt Demanded = DemandedBits;
8808 if (!
MRI.hasOneNonDBGUse(OpReg) && !Demanded.
isAllOnes()) {
8810 simplifyMultipleUseDemandedBits(OpReg, Demanded,
Depth)) {
8811 Known =
VT->getKnownBits(Repl);
8820 case TargetOpcode::G_AND:
8821 case TargetOpcode::G_OR: {
8826 "Logical operands must match the result type");
8827 auto SimplifyWithConst = [&](
Register X,
8828 Register CReg) -> std::optional<Register> {
8829 std::optional<APInt>
C = getConstantOrConstantSplatVector(CReg);
8831 return std::nullopt;
8832 assert(
C->getBitWidth() == BW &&
"Constant width must match its type");
8834 if (Opcode == TargetOpcode::G_AND) {
8839 return std::nullopt;
8845 return std::nullopt;
8849 if (std::optional<Register> Repl = SimplifyWithConst(
LHS,
RHS)) {
8850 Known =
VT->getKnownBits(*Repl);
8854 if (std::optional<Register> Repl = SimplifyWithConst(
RHS,
LHS)) {
8855 Known =
VT->getKnownBits(*Repl);
8860 KnownBits RHSKnown(BW);
8861 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 2, Demanded,
8862 RHSKnown,
Depth + 1, DoRewrite);
8864 KnownBits LHSKnown(BW);
8865 Changed |= simplifyDemandedBitsImpl(*
DefMI, 1, LHSDemand, LHSKnown,
8866 Depth + 1, DoRewrite);
8868 !getConstantOrConstantSplatVector(
RHS)) {
8871 LHSDemand == Demanded
8877 OpTy.isFixedVector()
8881 if (RHSDemand != Demanded) {
8883 KnownBits RetryKnown(BW);
8884 Changed = simplifyDemandedBitsImpl(*
DefMI, 2, RHSDemand,
8885 RetryKnown,
Depth + 1, DoRewrite);
8890 InvalidateDebugUses(Demanded);
8892 Known = Opcode == TargetOpcode::G_AND ? LHSKnown & RHSKnown
8893 : LHSKnown | RHSKnown;
8896 case TargetOpcode::G_SHL:
8897 case TargetOpcode::G_LSHR:
8898 case TargetOpcode::G_ASHR: {
8905 KnownBits SrcKnown(BW);
8906 bool Changed = simplifyDemandedBitsImpl(*
DefMI, 1, SrcDemand,
8907 SrcKnown,
Depth + 1, DoRewrite);
8910 InvalidateDebugUses(Demanded);
8914 case TargetOpcode::G_SHL:
8917 case TargetOpcode::G_LSHR:
8920 case TargetOpcode::G_ASHR: {
8924 isLegal({TargetOpcode::G_LSHR, {OpTy, AmtTy}});
8926 SrcKnown.isNonNegative()) &&
8929 MachineBasicBlock &SaveMBB =
Builder.getMBB();
8935 Builder.setInsertPt(SaveMBB, SavePt);
8937 Rewrite(Lshr.getReg(0));
8956 unsigned Depth)
const {
8964 LLT Ty =
MRI.getType(Dst);
8965 assert(Ty.isValid() &&
"Expected a typed generic result");
8966 if (!
VT || Ty.isVector())
8971 if (!simplifyDemandedBitsImpl(
MI, OpNo, OpDemand,
Known, 0,
8982 unsigned Opcode =
MI.getOpcode();
8984 case TargetOpcode::G_SHL:
8985 case TargetOpcode::G_LSHR:
8986 case TargetOpcode::G_ASHR: {
8988 getConstantOrConstantSplatVector(
MI.getOperand(2).getReg()),
8995 return Probe(1, SrcDemand, SrcKnown);
8999 case TargetOpcode::G_AND:
9000 case TargetOpcode::G_OR: {
9005 bool RootRedundant = Opcode == TargetOpcode::G_AND
9014 if (Probe(2, RootDemand, RHSKnown))
9020 if (Probe(1, LHSDemand, LHSKnown))
9024 if (!
MRI.hasOneNonDBGUse(RHS) || getConstantOrConstantSplatVector(RHS))
9028 LHSDemand == RootDemand
9032 VT->getKnownBits(
MI.getOperand(1).getReg()));
9034 return RHSDemand != RootDemand && Probe(2, RHSDemand, RetryKnown);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static APInt getDemandedBitsForLogicalOp(unsigned Opcode, const APInt &Demanded, const KnownBits &OtherKnown)
static bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static std::optional< unsigned > getValidConstShiftAmt(const std::optional< APInt > &Amt, unsigned BW)
static APInt getDemandedSrcBitsForShiftConst(unsigned Opcode, const APInt &DemandedBits, unsigned ShAmt)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static std::optional< unsigned > getMinUselessShift(KnownBits ValueKB, unsigned Opcode, std::optional< int64_t > &Result)
Return the minimum useless shift amount that results in complete loss of the source value.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static bool vectorFPFoldUsesIEEEDenormals(const MachineFunction &MF, LLT Ty)
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
Utilities for dealing with flags related to floating point properties and mode controls.
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
SmallVector< MachineOperand, 4 > Cond
MachineRegisterInfo & MRI
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmNearestTiesToEven
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
Class for arbitrary precision integers.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
unsigned countLeadingZeros() const
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
static bool isSameValue(const APInt &I1, const APInt &I2, bool SignedCompare=false)
Determine if two APInts have the same value, after zero-extending or sign-extending (if SignedCompare...
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
static LLVM_ABI bool isEquality(Predicate pred)
Determine if this is an equals/not equals predicate.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
static LLVM_ABI bool isOrdered(Predicate predicate)
Determine if the predicate is an ordered operation.
LLVM_ABI void applyCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
LLVM_ABI void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
LLVM_ABI bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
LLVM_ABI bool isFPConstantLegalOrBeforeLegalizer(const LLT Ty) const
LLVM_ABI bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
LLVM_ABI const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
LLVM_ABI bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
LLVM_ABI void applyUDivOrURemByConst(MachineInstr &MI) const
LLVM_ABI void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
LLVM_ABI bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchFsubToFneg(MachineInstr &MI) const
LLVM_ABI bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
LLVM_ABI bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
LLVM_ABI bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
LLVM_ABI bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
LLVM_ABI bool matchSimplifyDemandedBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match demanded-bits simplification of a root's register use.
const TargetInstrInfo * TII
LLVM_ABI void applyCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
LLVM_ABI void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
LLVM_ABI bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
LLVM_ABI bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
LLVM_ABI bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI void applyCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
Replace MI with a flattened build_vector with Ops or an implicit_def if Ops is empty.
LLVM_ABI void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
LLVM_ABI void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace shuffle MI with a build_vector.
LLVM_ABI bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
LLVM_ABI void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
LLVM_ABI void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
LLVM_ABI void applyCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo) const
LLVM_ABI bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
LLVM_ABI void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
LLVM_ABI bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
LLVM_ABI bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM when their source operands are iden...
LLVM_ABI void applyUMulHToLShr(MachineInstr &MI) const
LLVM_ABI void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
LLVM_ABI bool isLegalOrHasFewerElements(const LegalityQuery &Query) const
LLVM_ABI bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
LLVM_ABI bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
LLVM_ABI bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
LLVM_ABI bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
LLVM_ABI bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI const TargetLowering & getTargetLowering() const
LLVM_ABI bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
LLVM_ABI void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
LLVM_ABI void applySDivByPow2(MachineInstr &MI) const
LLVM_ABI bool matchConstantFoldFPBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
LLVM_ABI void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
LLVM_ABI bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
LLVM_ABI bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
LLVM_ABI void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
LLVM_ABI bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), (fneg z)) (fsub (fpext (fmul x,...
LLVM_ABI bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
LLVM_ABI void applyCombineCopy(MachineInstr &MI) const
LLVM_ABI bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
LLVM_ABI bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
LLVM_ABI bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) (fadd (fmad x,...
LLVM_ABI bool matchSextTruncSextLoad(MachineInstr &MI) const
LLVM_ABI bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
LLVM_ABI bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
LLVM_ABI bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
LLVM_ABI bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
LLVM_ABI bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
LLVM_ABI bool matchCombineCopy(MachineInstr &MI) const
LLVM_ABI bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
LLVM_ABI void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
LLVM_ABI bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
LLVM_ABI bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
LLVM_ABI void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
LLVM_ABI bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchRedundantSExtInReg(MachineInstr &MI) const
LLVM_ABI void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
LLVM_ABI void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
LLVM_ABI bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
LLVM_ABI void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
LLVM_ABI bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
LLVM_ABI bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
LLVM_ABI void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
LLVM_ABI bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
LLVM_ABI void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
LLVM_ABI bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
LLVM_ABI bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
LLVM_ABI void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
LLVM_ABI bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
LLVM_ABI bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
LLVM_ABI bool isPreLegalize() const
LLVM_ABI bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
LLVM_ABI bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
If we have a shift-by-constant of a bitwise logic op that itself has a shift-by-constant operand with...
LLVM_ABI bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
LLVM_ABI bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
LLVM_ABI bool matchOperandIsKnownToBeAPowerOfTwo(const MachineOperand &MO, bool OrNegative=false, bool OrZero=false) const
Check if operand MO is known to be a power of 2.
LLVM_ABI bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVM_ABI LLVMContext & getContext() const
LLVM_ABI void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
LLVM_ABI bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
LLVM_ABI bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
LLVM_ABI bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
LLVM_ABI bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
LLVM_ABI bool simplifyDemandedBits(MachineInstr &MI, unsigned OpNo, const APInt &DemandedBits, KnownBits &Known, unsigned Depth=0) const
Simplify a register use under DemandedBits and compute Known in the same walk.
LLVM_ABI bool matchConstantFoldUnaryIntOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold a unary integer op (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON variants,...
LLVM_ABI bool isLegal(const LegalityQuery &Query) const
LLVM_ABI bool matchShiftsTooBig(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
LLVM_ABI void applyCombineShuffleOfBuildVector(MachineInstr &MI) const
Replace shuffle of build_vector with a build_vector.
LLVM_ABI bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
LLVM_ABI bool 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 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 matchConstantFoldBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
MachineRegisterInfo & MRI
LLVM_ABI void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
LLVM_ABI bool matchConstantFPOp(const MachineOperand &MOP, double C) const
Return true if MOP is defined by a G_FCONSTANT or splat with a value exactly equal to C.
LLVM_ABI MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
LLVM_ABI void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
LLVM_ABI bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
LLVM_ABI bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
LLVM_ABI bool isConstantNaN(Register Reg) const
LLVM_ABI bool matchPtrAddZeroVector(MachineInstr &MI) const
}
LLVM_ABI bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
LLVM_ABI bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
LLVM_ABI bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
LLVM_ABI void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applyRotateOutOfRange(MachineInstr &MI) const
LLVM_ABI bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
LLVM_ABI bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
LLVM_ABI bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
LLVM_ABI bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
LLVM_ABI bool isDesirableToCommuteWithShift(const MachineInstr &MI) const
LLVM_ABI bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (X + Y) == X -> Y == 0 (X - Y) == X -> Y == 0 (X ^ Y) == X -> Y == 0 (X + Y) !...
LLVM_ABI bool matchConstantFoldFPUnary(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold a unary FP operation when the source is constant.
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 matchConstantFoldCastOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
LLVM_ABI bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
LLVM_ABI bool matchRotateOutOfRange(MachineInstr &MI) const
LLVM_ABI void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
LLVM_ABI void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
LLVM_ABI bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
LLVM_ABI void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
LLVM_ABI bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
LLVM_ABI void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applySimplifySRemByPow2(MachineInstr &MI) const
Combine G_SREM x, (+/-2^k) to a bias-and-mask sequence.
LLVM_ABI bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
LLVM_ABI bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
LLVM_ABI void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
LLVM_ABI bool matchConstantOp(const MachineOperand &MOP, int64_t C) const
Return true if MOP is defined by a G_CONSTANT or splat with a value equal to C.
LLVM_ABI void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
LLVM_ABI void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
LLVM_ABI bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
LLVM_ABI bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
LLVM_ABI bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
LLVM_ABI bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
LLVM_ABI bool matchBinopWithNeg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold a bitwiseop (~b +/- c) -> a bitwiseop ~(b -/+ c)
LLVM_ABI bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
LLVM_ABI bool matchCountZeroToZeroPoison(MachineInstr &MI, unsigned Opc, unsigned ZeroPoisonOpc) const
LLVM_ABI void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
LLVM_ABI bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
LLVM_ABI bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
LLVM_ABI void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
LLVM_ABI bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
LLVM_ABI bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, unsigned &ShiftVal) const
Reduce a shift by a constant to an unmerge and a shift on a half sized type.
LLVM_ABI bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
LLVM_ABI bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
LLVM_ABI bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
LLVM_ABI bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
LLVM_ABI bool matchUDivByShiftedPow2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine unsigned division by a shifted power of two into a right shift.
LLVM_ABI bool matchSameRegOrICstOrSplat(Register A, Register B) const
True when A and B are the same register, including through copies, or different registers holding the...
LLVM_ABI void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
LLVM_ABI bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
LLVM_ABI bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI void applySDivOrSRemByConst(MachineInstr &MI) const
LLVM_ABI bool matchCombineMemCpyFamily(MachineInstr &MI, MemCpyFamilyLoweringInfo &MatchInfo, unsigned MaxLen=0) const
LLVM_ABI MachineInstr * buildSDivOrSRemUsingMul(MachineInstr &MI) const
Given an G_SDIV MI or G_SREM MI expressing a signed divide by constant, return an expression that imp...
LLVM_ABI bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
LLVM_ABI bool matchSignedDivRemToUnsigned(MachineInstr &MI, unsigned UnsignedOpcode) const
Convert signed division or remainder of nonnegative operands to unsigned.
LLVM_ABI bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
LLVM_ABI bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
LLVM_ABI void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
LLVM_ABI void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
LLVM_ABI const MachineFunction & getMachineFunction() const
LLVM_ABI bool matchCombineBuildVectorOfBitcast(MachineInstr &MI, SmallVector< Register > &Ops) const
Combine G_BUILD_VECTOR(G_UNMERGE(G_BITCAST), Undef) to G_BITCAST(G_BUILD_VECTOR(.....
LLVM_ABI bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchConstantFoldFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Constant fold G_FMA/G_FMAD.
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 & getValueAPF() const
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Register getSrcReg() const
Represents a G_CONCAT_VECTORS.
Abstract class that contains various methods for clients to notify about changes.
Simple wrapper observer that takes several observers, and calls each one for each event.
Represents any type of generic load or store.
Register getPointerReg() const
Get the source register of the pointer value.
Represents a logical binary operation.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
bool isAtomic() const
Returns true if the attached MachineMemOperand has the atomic flag set.
LocationSize getMemSizeInBits() const
Returns the size in bits of the memory access.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isFloat() const
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 bool isAnyScalar() const
constexpr ElementCount getElementCount() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
static LLT integer(unsigned SizeInBits)
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
This is an important class for using LLVM in a threaded context.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
DenormalMode getDenormalMode(const fltSemantics &FPType) const
Returns the denormal handling type for the default rounding mode of the function.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Helper class to build MachineInstr.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
LLVM_ABI bool isDereferenceableInvariantLoad() const
Return true if this load instruction never traps and points to a memory location whose value doesn't ...
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
unsigned getNumOperands() const
Retuns the total number of operands.
static constexpr uint32_t getPoisonGeneratingFlags()
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
mop_range uses()
Returns all operands which may be register uses.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI int findRegisterDefOperandIdx(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false) const
Returns the operand index that is a def of the specified register or -1 if it is not found.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
bool isAtomic() const
Returns true if this operation has an atomic ordering requirement of unordered or higher,...
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setMBB(MachineBasicBlock *MBB)
void setPredicate(unsigned Predicate)
Register getReg() const
getReg - Returns the register number.
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual LLVM_READONLY LLT getPreferredShiftAmountTy(LLT ShiftValueTy) const
Return the preferred type to use for a shift opcode, given the shifted amount type is ShiftValueTy.
bool isBeneficialToExpandPowI(int64_t Exponent, bool OptForSize) const
Return true if it is beneficial to expand an @llvm.powi.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual bool isIndexingLegal(MachineInstr &MI, Register Base, Register Offset, bool IsPre, MachineRegisterInfo &MRI) const
Returns true if the specified base+offset is a legal indexed addressing mode for this target.
virtual bool isDesirableToCommuteWithShift(const SDNode *N, CombineLevel Level) const
Return true if it is profitable to move this shift by a constant amount through its operand,...
virtual unsigned combineRepeatedFPDivisors() const
Indicate whether this target prefers to combine FDIVs with the same divisor.
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
@ Custom
The target wants to do something special with this combination of operand and type.
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
GInstrBind< GBuildVector > m_GBuildVector(GBuildVector *&Inst)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
LoadOp_match< GLoad, PtrP > m_GLoad(const PtrP &Ptr)
MIFlagsRef m_MIFlags(uint32_t &Flags)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
GInstrBind< GConcatVectors > m_GConcatVectors(GConcatVectors *&Inst)
GConstantBitsMatch m_GConstantOrFConstantBits(APInt &Bits)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP > m_GICmp(const Pred &P, const LHS &L, const RHS &R)
GInstrBind< GUnmerge > m_GUnmerge(GUnmerge *&Inst)
Instruction binders for ops with no operand-form matcher (constant-immediate or variadic-source ops).
MMORef m_MMO(const MachineMemOperand *&MMO)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT > m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(const APInt &RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false > m_GBuildVectorTrunc(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP, true > m_c_GICmp(const Pred &P, const LHS &L, const RHS &R)
G_ICMP matcher that also matches commuted compares.
LoadOp_match< GAnyLoad, PtrP > m_GAnyLoad(const PtrP &Ptr)
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FMUL, true > m_GFMul(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
unsigned getNumElements(Type *Ty)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a float constant integer or a splat vector of float constant integers.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
LLVM_ABI bool isAllOnesOrAllOnesSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant -1 integer or a splatted vector of a constant -1 integer (with...
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
unsigned Log2_64_Ceil(uint64_t Value)
Return the ceil log base 2 of the specified value, 64 if the value is zero.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
@ Load
The value being inserted comes from a load (InsertElement only).
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, llvm::function_ref< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return true if the given value is known to have exactly one bit set when defined.
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
constexpr unsigned MaxAnalysisRecursionDepth
SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > OperandBuildSteps
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
std::tuple< Register, Register, uint64_t, Align, bool, std::vector< LLT > > MemCpyFamilyLoweringInfo
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
LLVM_ABI bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI SmallVector< APInt > ConstantFoldVectorBinop(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
Tries to constant fold a vector binop with sources Op1 and Op2.
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 SmallVector< APFloat > ConstantFoldUnaryFPOp(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Tries to constant fold a unary floating-point operation on Src.
LLVM_ABI unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc)
Returns the inverse opcode of MinMaxOpc, which is a generic min/max opcode like G_SMIN.
LLVM_ABI SmallVector< APFloat > ConstantFoldVectorFPBinop(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
Tries to constant fold a vector floating-point binop with sources Op1 and Op2.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
constexpr unsigned BitWidth
LLVM_ABI int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP)
Returns an integer representing true, as defined by the TargetBooleanContents.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
LLVM_ABI std::optional< DefinitionAndSourceRegister > getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, and underlying value Register folding away any copies.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
LLVM_ABI SmallVector< APInt > ConstantFoldUnaryIntOp(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Tries to constant fold a unary integer operation (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON vari...
unsigned Log2(Align A)
Returns the log2 of the alignment.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Simple struct used to hold a Register value and the instruction which defines it.
static constexpr DenormalMode getIEEE()
SmallVector< InstructionBuildSteps, 2 > InstrsToBuild
Describes instructions to be built during a combine.
static KnownBits makeConstant(const APInt &C)
Create known bits from a known constant.
bool isNonNegative() const
Returns true if this value is known to be non-negative.
unsigned countMinLeadingOnes() const
Returns the minimum number of leading one bits.
unsigned countMinTrailingZeros() const
Returns the minimum number of trailing zero bits.
static LLVM_ABI KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS, bool ShAmtNonZero=false, bool Exact=false)
Compute known bits for ashr(LHS, RHS).
bool isUnknown() const
Returns true if we don't know any bits.
unsigned getBitWidth() const
Get the bit width of this value.
static LLVM_ABI KnownBits lshr(const KnownBits &LHS, const KnownBits &RHS, bool ShAmtNonZero=false, bool Exact=false)
Compute known bits for lshr(LHS, RHS).
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
bool isNegative() const
Returns true if this value is known to be negative.
static LLVM_ABI KnownBits shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW=false, bool NSW=false, bool ShAmtNonZero=false)
Compute known bits for shl(LHS, RHS).
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
This class contains a discriminated union of information about pointers in memory operands,...
LLVM_ABI unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
Magic data for optimising signed division by a constant.
unsigned ShiftAmount
shift amount
static LLVM_ABI SignedDivisionByConstantInfo get(const APInt &D)
Calculate the magic numbers required to implement a signed integer division by a constant as a sequen...
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
unsigned PostShift
post-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true, bool AllowWidenOptimization=false)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...