46#define DEBUG_TYPE "gi-combiner"
55 cl::desc(
"Force all indexed operations to be "
56 "legal for the GlobalISel combiner"));
65 RBI(
Builder.getMF().getSubtarget().getRegBankInfo()),
66 TRI(
Builder.getMF().getSubtarget().getRegisterInfo()) {
71 return *
Builder.getMF().getSubtarget().getTargetLowering();
89 assert(
I < ByteWidth &&
"I must be in [0, ByteWidth)");
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!");
178 return isLegal({TargetOpcode::G_BUILD_VECTOR, {Ty, EltTy}}) &&
179 isLegal({TargetOpcode::G_CONSTANT, {EltTy}});
186 if (
MRI.constrainRegAttrs(ToReg, FromReg))
187 MRI.replaceRegWith(FromReg, ToReg);
189 Builder.buildCopy(FromReg, ToReg);
191 Observer.finishedChangingAllUsesOfReg();
206 unsigned ToOpcode)
const {
221 MRI.setRegBank(Reg, *RegBank);
232 if (
MI.getOpcode() != TargetOpcode::COPY)
242 MI.eraseFromParent();
251 if (!
MRI.hasOneNonDBGUse(OrigOp))
270 std::optional<MachineOperand> MaybePoisonOperand;
272 if (!Operand.isReg())
278 if (!MaybePoisonOperand)
279 MaybePoisonOperand = Operand;
288 if (!MaybePoisonOperand) {
293 B.buildCopy(
DstOp, OrigOp);
298 Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
299 LLT MaybePoisonOperandRegTy =
MRI.getType(MaybePoisonOperandReg);
306 auto Freeze =
B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
317 assert(
MI.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
318 "Invalid instruction");
328 assert(Def &&
"Operand not defined");
329 if (!
MRI.hasOneNonDBGUse(Reg))
331 switch (Def->getOpcode()) {
332 case TargetOpcode::G_BUILD_VECTOR:
337 Ops.push_back(BuildVecMO.getReg());
339 case TargetOpcode::G_IMPLICIT_DEF: {
340 LLT OpType =
MRI.getType(Reg);
347 OpType.getScalarType() &&
348 "All undefs should have the same type");
351 for (
unsigned EltIdx = 0, EltEnd = OpType.getNumElements();
352 EltIdx != EltEnd; ++EltIdx)
353 Ops.push_back(
Undef->getOperand(0).getReg());
362 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
364 {TargetOpcode::G_BUILD_VECTOR, {DstTy,
MRI.getType(
Ops[0])}})) {
379 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
392 MI.eraseFromParent();
398 Register SrcVec1 = Shuffle.getSrc1Reg();
399 Register SrcVec2 = Shuffle.getSrc2Reg();
400 LLT EltTy =
MRI.getType(SrcVec1).getElementType();
401 int Width =
MRI.getType(SrcVec1).getNumElements();
403 auto Unmerge1 =
Builder.buildUnmerge(EltTy, SrcVec1);
404 auto Unmerge2 =
Builder.buildUnmerge(EltTy, SrcVec2);
408 for (
int Val : Shuffle.getMask()) {
411 else if (Val < Width)
412 Extracts.
push_back(Unmerge1.getReg(Val));
414 Extracts.
push_back(Unmerge2.getReg(Val - Width));
416 assert(Extracts.
size() > 0 &&
"Expected at least one element in the shuffle");
417 if (Extracts.
size() == 1)
418 Builder.buildCopy(
MI.getOperand(0).getReg(), Extracts[0]);
420 Builder.buildBuildVector(
MI.getOperand(0).getReg(), Extracts);
421 MI.eraseFromParent();
431 if (!ConcatMI1 || !ConcatMI2)
435 if (
MRI.getType(ConcatMI1->getSourceReg(0)) !=
436 MRI.getType(ConcatMI2->getSourceReg(0)))
439 LLT ConcatSrcTy =
MRI.getType(ConcatMI1->getReg(1));
440 LLT ShuffleSrcTy1 =
MRI.getType(
MI.getOperand(1).getReg());
442 for (
unsigned i = 0; i < Mask.size(); i += ConcatSrcNumElt) {
446 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
447 if (i + j >= Mask.size())
449 if (Mask[i + j] != -1)
453 {TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
456 }
else if (Mask[i] % ConcatSrcNumElt == 0) {
457 for (
unsigned j = 1; j < ConcatSrcNumElt; j++) {
458 if (i + j >= Mask.size())
460 if (Mask[i + j] != Mask[i] +
static_cast<int>(j))
466 Ops.push_back(ConcatMI1->getSourceReg(Mask[i] / ConcatSrcNumElt));
468 Ops.push_back(ConcatMI2->getSourceReg(Mask[i] / ConcatSrcNumElt -
469 ConcatMI1->getNumSources()));
477 {TargetOpcode::G_CONCAT_VECTORS,
478 {
MRI.getType(
MI.getOperand(0).getReg()), ConcatSrcTy}}))
489 SrcTy =
MRI.getType(Reg);
491 assert(SrcTy.isValid() &&
"Unexpected full undef vector in concat combine");
498 UndefReg =
Builder.buildUndef(SrcTy).getReg(0);
504 Builder.buildConcatVectors(
MI.getOperand(0).getReg(),
Ops);
507 MI.eraseFromParent();
521 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
522 "Invalid instruction kind");
523 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
525 LLT SrcType =
MRI.getType(Src1);
527 unsigned DstNumElts = DstType.getNumElements();
528 unsigned SrcNumElts = SrcType.getNumElements();
545 if (DstNumElts < 2 * SrcNumElts)
550 if (DstNumElts % SrcNumElts != 0)
556 unsigned NumConcat = DstNumElts / SrcNumElts;
559 for (
unsigned i = 0; i != DstNumElts; ++i) {
566 if ((Idx % SrcNumElts != (i % SrcNumElts)) ||
567 (ConcatSrcs[i / SrcNumElts] >= 0 &&
568 ConcatSrcs[i / SrcNumElts] != (
int)(Idx / SrcNumElts)))
571 ConcatSrcs[i / SrcNumElts] = Idx / SrcNumElts;
578 for (
auto Src : ConcatSrcs) {
582 UndefReg =
Builder.buildUndef(SrcType).getReg(0);
584 Ops.push_back(UndefReg);
597 Register NewDstReg =
MRI.cloneVirtualRegister(DstReg);
605 MI.eraseFromParent();
614 const LLT TyForCandidate,
615 unsigned OpcodeForCandidate,
620 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
631 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
634 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ANYEXT &&
635 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
636 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
644 OpcodeForCandidate == TargetOpcode::G_ZEXT)
646 else if (CurrentUse.
ExtendOpcode == TargetOpcode::G_ZEXT &&
647 OpcodeForCandidate == TargetOpcode::G_SEXT)
648 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
657 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
668static void InsertInsnsWithoutSideEffectsBeforeUse(
680 InsertBB = PredBB->
getMBB();
685 if (InsertBB ==
DefMI.getParent()) {
687 Inserter(InsertBB, std::next(InsertPt), UseMO);
706 unsigned CandidateLoadOpc;
708 case TargetOpcode::G_ANYEXT:
709 CandidateLoadOpc = TargetOpcode::G_LOAD;
711 case TargetOpcode::G_SEXT:
712 CandidateLoadOpc = TargetOpcode::G_SEXTLOAD;
714 case TargetOpcode::G_ZEXT:
715 CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD;
720 return CandidateLoadOpc;
737 LLT LoadValueTy =
MRI.getType(LoadReg);
759 unsigned PreferredOpcode =
761 ? TargetOpcode::G_ANYEXT
763 Preferred = {
LLT(), PreferredOpcode,
nullptr};
764 for (
auto &
UseMI :
MRI.use_nodbg_instructions(LoadReg)) {
765 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
766 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
767 (
UseMI.getOpcode() == TargetOpcode::G_ANYEXT)) {
768 const auto &MMO = LoadMI->
getMMO();
776 LLT UseTy =
MRI.getType(
UseMI.getOperand(0).getReg());
778 if (
LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}})
782 Preferred = ChoosePreferredUse(
MI, Preferred,
783 MRI.getType(
UseMI.getOperand(0).getReg()),
793 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
811 if (PreviouslyEmitted) {
818 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
819 Register NewDstReg =
MRI.cloneVirtualRegister(
MI.getOperand(0).getReg());
821 EmittedInsns[InsertIntoBB] = NewMI;
827 MI.setDesc(
Builder.getTII().get(LoadOpc));
834 for (
auto *UseMO :
Uses) {
840 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
843 const LLT UseDstTy =
MRI.getType(UseDstReg);
844 if (UseDstReg != ChosenDstReg) {
845 if (Preferred.
Ty == UseDstTy) {
882 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO,
897 InsertInsnsWithoutSideEffectsBeforeUse(
Builder,
MI, *UseMO, InsertTruncAt);
900 MI.getOperand(0).setReg(ChosenDstReg);
906 assert(
MI.getOpcode() == TargetOpcode::G_AND);
917 if (
MRI.getType(Dst).isVector())
925 APInt MaskVal = MaybeMask->Value;
934 if (!LoadMI || !
MRI.hasOneNonDBGUse(LoadMI->
getDstReg()))
938 LLT RegTy =
MRI.getType(LoadReg);
946 if (MaskSizeBits > LoadSizeBits.
getValue())
966 else if (LoadSizeBits.
getValue() > MaskSizeBits ||
972 {TargetOpcode::G_ZEXTLOAD, {RegTy,
MRI.getType(PtrReg)}, {MemDesc}}))
976 B.setInstrAndDebugLoc(*LoadMI);
977 auto &MF =
B.getMF();
979 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, MemDesc.
MemoryTy);
980 B.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, Dst, PtrReg, *NewMMO);
989 "shouldn't consider debug uses");
997 if (DefOrUse ==
MBB.end())
999 return &*DefOrUse == &
DefMI;
1005 "shouldn't consider debug uses");
1008 else if (
DefMI.getParent() !=
UseMI.getParent())
1015 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1019 if (
MRI.getType(SrcReg).isVector())
1024 LoadUser = TruncSrc;
1026 uint64_t SizeInBits =
MI.getOperand(2).getImm();
1031 auto LoadSizeBits = LoadMI->getMemSizeInBits();
1033 MRI.getType(TruncSrc).getSizeInBits() < LoadSizeBits.getValue())
1035 if (LoadSizeBits == SizeInBits)
1042 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1043 Builder.buildCopy(
MI.getOperand(0).getReg(),
MI.getOperand(1).getReg());
1044 MI.eraseFromParent();
1048 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1049 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1052 LLT RegTy =
MRI.getType(DstReg);
1060 if (!LoadDef || !
MRI.hasOneNonDBGUse(SrcReg))
1063 uint64_t MemBits = LoadDef->getMemSizeInBits().getValue();
1068 unsigned NewSizeBits = std::min((
uint64_t)
MI.getOperand(2).getImm(), MemBits);
1071 if (NewSizeBits < 8)
1083 if (LoadDef->isSimple())
1085 else if (MemBits > NewSizeBits || MemBits == RegTy.
getSizeInBits())
1090 {
MRI.getType(LoadDef->getDstReg()),
1091 MRI.getType(LoadDef->getPointerReg())},
1095 MatchInfo = std::make_tuple(LoadDef->getDstReg(), NewSizeBits);
1100 MachineInstr &
MI, std::tuple<Register, unsigned> &MatchInfo)
const {
1101 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
1103 unsigned ScalarSizeBits;
1104 std::tie(LoadReg, ScalarSizeBits) = MatchInfo;
1113 auto &MMO = LoadDef->
getMMO();
1114 Builder.setInstrAndDebugLoc(*LoadDef);
1116 auto PtrInfo = MMO.getPointerInfo();
1117 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, ScalarSizeBits / 8);
1118 Builder.buildLoadInstr(TargetOpcode::G_SEXTLOAD,
MI.getOperand(0).getReg(),
1120 MI.eraseFromParent();
1131 auto *MF =
MI->getMF();
1138 AM.
BaseOffs = CstOff->getSExtValue();
1143 MF->getDataLayout(), AM,
1145 MF->getFunction().getContext()),
1146 MI->getMMO().getAddrSpace());
1151 case TargetOpcode::G_LOAD:
1152 return TargetOpcode::G_INDEXED_LOAD;
1153 case TargetOpcode::G_STORE:
1154 return TargetOpcode::G_INDEXED_STORE;
1155 case TargetOpcode::G_ZEXTLOAD:
1156 return TargetOpcode::G_INDEXED_ZEXTLOAD;
1157 case TargetOpcode::G_SEXTLOAD:
1158 return TargetOpcode::G_INDEXED_SEXTLOAD;
1164bool CombinerHelper::isIndexedLoadStoreLegal(
GLoadStore &LdSt)
const {
1174 if (IndexedOpc == TargetOpcode::G_INDEXED_STORE)
1175 OpTys = {PtrTy, Ty, Ty};
1177 OpTys = {Ty, PtrTy};
1179 LegalityQuery Q(IndexedOpc, OpTys, MemDescrs);
1185 cl::desc(
"Number of uses of a base pointer to check before it is no longer "
1186 "considered for post-indexing."));
1190 bool &RematOffset)
const {
1200 if (
MRI.hasOneNonDBGUse(Ptr))
1203 if (!isIndexedLoadStoreLegal(LdSt))
1210 auto *PtrDef =
MRI.getVRegDef(Ptr);
1212 unsigned NumUsesChecked = 0;
1213 for (
auto &
Use :
MRI.use_nodbg_instructions(Ptr)) {
1220 if (!PtrAdd ||
MRI.use_nodbg_empty(PtrAdd->getReg(0)))
1225 if (StoredValDef == &
Use)
1228 Offset = PtrAdd->getOffsetReg();
1230 !TLI.isIndexingLegal(LdSt, PtrAdd->getBaseReg(),
Offset,
1236 RematOffset =
false;
1240 if (OffsetDef->
getOpcode() != TargetOpcode::G_CONSTANT)
1245 for (
auto &BasePtrUse :
MRI.use_nodbg_instructions(PtrAdd->getBaseReg())) {
1246 if (&BasePtrUse == PtrDef)
1252 if (BasePtrLdSt && BasePtrLdSt != &LdSt &&
1254 isIndexedLoadStoreLegal(*BasePtrLdSt))
1260 Register PtrAddDefReg = BasePtrUseDef->getReg(0);
1261 for (
auto &BaseUseUse :
MRI.use_nodbg_instructions(PtrAddDefReg)) {
1264 if (BaseUseUse.getParent() != LdSt.
getParent())
1276 Addr = PtrAdd->getReg(0);
1277 Base = PtrAdd->getBaseReg();
1292 MRI.hasOneNonDBGUse(Addr))
1299 if (!isIndexedLoadStoreLegal(LdSt))
1303 if (BaseDef->
getOpcode() == TargetOpcode::G_FRAME_INDEX)
1308 if (
Base == St->getValueReg())
1313 if (St->getValueReg() == Addr)
1318 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr))
1319 if (AddrUse.getParent() != LdSt.
getParent())
1324 bool RealUse =
false;
1325 for (
auto &AddrUse :
MRI.use_nodbg_instructions(Addr)) {
1343 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
1353 assert(
MRI.getType(
MI.getOperand(0).getReg()) == VecEltTy);
1360 if (!LoadMI->isSimple())
1372 const unsigned MaxIter = 20;
1375 if (
II->isLoadFoldBarrier())
1377 if (Iter++ == MaxIter)
1393 int Elt = CVal->getZExtValue();
1406 Register VecPtr = LoadMI->getPointerReg();
1407 LLT PtrTy =
MRI.getType(VecPtr);
1415 {TargetOpcode::G_LOAD, {VecEltTy, PtrTy}, {MMDesc}}))
1438 B.buildLoad(Result, finalPtr, PtrInfo, Alignment);
1453 MatchInfo.
IsPre = findPreIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1455 if (!MatchInfo.
IsPre &&
1456 !findPostIndexCandidate(LdSt, MatchInfo.
Addr, MatchInfo.
Base,
1466 unsigned Opcode =
MI.getOpcode();
1467 bool IsStore = Opcode == TargetOpcode::G_STORE;
1473 auto *OldCst =
MRI.getVRegDef(MatchInfo.
Offset);
1475 *OldCst->getOperand(1).getCImm());
1476 MatchInfo.
Offset = NewCst.getReg(0);
1479 auto MIB =
Builder.buildInstr(NewOpcode);
1481 MIB.addDef(MatchInfo.
Addr);
1482 MIB.addUse(
MI.getOperand(0).getReg());
1484 MIB.addDef(
MI.getOperand(0).getReg());
1485 MIB.addDef(MatchInfo.
Addr);
1488 MIB.addUse(MatchInfo.
Base);
1489 MIB.addUse(MatchInfo.
Offset);
1490 MIB.addImm(MatchInfo.
IsPre);
1491 MIB->cloneMemRefs(*
MI.getMF(),
MI);
1492 MI.eraseFromParent();
1500 unsigned Opcode =
MI.getOpcode();
1501 bool IsDiv, IsSigned;
1506 case TargetOpcode::G_SDIV:
1507 case TargetOpcode::G_UDIV: {
1509 IsSigned = Opcode == TargetOpcode::G_SDIV;
1512 case TargetOpcode::G_SREM:
1513 case TargetOpcode::G_UREM: {
1515 IsSigned = Opcode == TargetOpcode::G_SREM;
1521 unsigned DivOpcode, RemOpcode, DivremOpcode;
1523 DivOpcode = TargetOpcode::G_SDIV;
1524 RemOpcode = TargetOpcode::G_SREM;
1525 DivremOpcode = TargetOpcode::G_SDIVREM;
1527 DivOpcode = TargetOpcode::G_UDIV;
1528 RemOpcode = TargetOpcode::G_UREM;
1529 DivremOpcode = TargetOpcode::G_UDIVREM;
1547 for (
auto &
UseMI :
MRI.use_nodbg_instructions(Src1)) {
1548 if (
MI.getParent() ==
UseMI.getParent() &&
1549 ((IsDiv &&
UseMI.getOpcode() == RemOpcode) ||
1550 (!IsDiv &&
UseMI.getOpcode() == DivOpcode)) &&
1563 unsigned Opcode =
MI.getOpcode();
1564 assert(OtherMI &&
"OtherMI shouldn't be empty.");
1567 if (Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_UDIV) {
1568 DestDivReg =
MI.getOperand(0).getReg();
1572 DestRemReg =
MI.getOperand(0).getReg();
1576 Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM;
1583 Builder.setInstrAndDebugLoc(*FirstInst);
1585 Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
1586 : TargetOpcode::G_UDIVREM,
1587 {DestDivReg, DestRemReg},
1589 MI.eraseFromParent();
1595 assert(
MI.getOpcode() == TargetOpcode::G_BR);
1612 if (BrIt ==
MBB->begin())
1614 assert(std::next(BrIt) ==
MBB->end() &&
"expected G_BR to be a terminator");
1616 BrCond = &*std::prev(BrIt);
1617 if (BrCond->
getOpcode() != TargetOpcode::G_BRCOND)
1623 return BrCondTarget !=
MI.getOperand(0).getMBB() &&
1624 MBB->isLayoutSuccessor(BrCondTarget);
1630 Builder.setInstrAndDebugLoc(*BrCond);
1635 auto True =
Builder.buildConstant(
1641 MI.getOperand(0).setMBB(FallthroughBB);
1656 return Helper.lowerMemcpyInline(
MI) ==
1661 unsigned MaxLen)
const {
1673 switch (
MI.getOpcode()) {
1676 case TargetOpcode::G_FNEG: {
1677 Result.changeSign();
1680 case TargetOpcode::G_FABS: {
1684 case TargetOpcode::G_FCEIL:
1687 case TargetOpcode::G_FFLOOR:
1690 case TargetOpcode::G_INTRINSIC_TRUNC:
1693 case TargetOpcode::G_INTRINSIC_ROUND:
1696 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
1699 case TargetOpcode::G_FRINT:
1700 case TargetOpcode::G_FNEARBYINT:
1704 case TargetOpcode::G_FPEXT:
1705 case TargetOpcode::G_FPTRUNC: {
1707 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1712 case TargetOpcode::G_FSQRT: {
1716 Result =
APFloat(sqrt(Result.convertToDouble()));
1719 case TargetOpcode::G_FLOG2: {
1739 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1740 MI.eraseFromParent();
1751 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1761 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1774 Type *AccessTy =
nullptr;
1775 auto &MF = *
MI.getMF();
1776 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1779 MF.getFunction().getContext());
1784 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1789 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1791 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1792 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1793 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1794 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1803 unsigned PtrAddFlags =
MI.getFlags();
1804 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1820 MatchInfo.
Flags = Flags;
1826 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1828 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1832 MI.getOperand(1).setReg(MatchInfo.
Base);
1833 MI.getOperand(2).setReg(NewOffset.getReg(0));
1847 unsigned Opcode =
MI.getOpcode();
1848 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1849 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1850 Opcode == TargetOpcode::G_USHLSAT) &&
1851 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1871 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1876 if (Opcode == TargetOpcode::G_USHLSAT &&
1877 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1885 unsigned Opcode =
MI.getOpcode();
1886 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1887 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1888 Opcode == TargetOpcode::G_USHLSAT) &&
1889 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1891 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1892 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1893 auto Imm = MatchInfo.
Imm;
1895 if (Imm >= ScalarSizeInBits) {
1897 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1898 Builder.buildConstant(
MI.getOperand(0), 0);
1899 MI.eraseFromParent();
1904 Imm = ScalarSizeInBits - 1;
1907 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1910 MI.getOperand(1).setReg(MatchInfo.
Reg);
1911 MI.getOperand(2).setReg(NewImm);
1927 unsigned ShiftOpcode =
MI.getOpcode();
1928 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1929 ShiftOpcode == TargetOpcode::G_ASHR ||
1930 ShiftOpcode == TargetOpcode::G_LSHR ||
1931 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1932 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1933 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1936 Register LogicDest =
MI.getOperand(1).getReg();
1937 if (!
MRI.hasOneNonDBGUse(LogicDest))
1941 unsigned LogicOpcode = LogicMI->
getOpcode();
1942 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1943 LogicOpcode != TargetOpcode::G_XOR)
1947 const Register C1 =
MI.getOperand(2).getReg();
1949 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1952 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1956 if (
MI->getOpcode() != ShiftOpcode ||
1957 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1966 ShiftVal = MaybeImmVal->Value.getSExtValue();
1977 if (matchFirstShift(LogicMIOp1, C0Val)) {
1979 MatchInfo.
Shift2 = LogicMIOp1;
1980 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1982 MatchInfo.
Shift2 = LogicMIOp2;
1986 MatchInfo.
ValSum = C0Val + C1Val;
1989 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
1992 MatchInfo.
Logic = LogicMI;
1998 unsigned Opcode =
MI.getOpcode();
1999 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
2000 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
2001 Opcode == TargetOpcode::G_SSHLSAT) &&
2002 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
2004 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
2005 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
2011 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2020 Register Shift2Const =
MI.getOperand(2).getReg();
2022 .buildInstr(Opcode, {DestType},
2032 MI.eraseFromParent();
2037 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2059 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2060 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2061 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2062 LLT SrcTy =
MRI.getType(SrcReg);
2064 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2065 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2066 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2074 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2078 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2093 LLT InnerShiftTy =
MRI.getType(InnerShift);
2095 if ((N1C + N001C).ult(InnerShiftSize)) {
2101 if ((N001C + OpSizeInBits) == InnerShiftSize)
2103 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2104 MatchInfo.
Mask =
true;
2114 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2121 if (MatchInfo.
Mask ==
true) {
2129 Builder.buildTrunc(Dst, Shift);
2130 MI.eraseFromParent();
2134 unsigned &ShiftVal)
const {
2135 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2141 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2142 return (
static_cast<int32_t
>(ShiftVal) != -1);
2146 unsigned &ShiftVal)
const {
2147 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2149 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2152 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2153 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2174 auto NegCst =
B.buildConstant(Ty, -Imm);
2176 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2177 MI.getOperand(2).setReg(NegCst.getReg(0));
2179 if (Imm.isMinSignedValue())
2189 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2204 if (!MaybeShiftAmtVal)
2208 LLT SrcTy =
MRI.getType(ExtSrc);
2218 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2219 MatchData.
Reg = ExtSrc;
2220 MatchData.
Imm = ShiftAmt;
2222 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2223 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2224 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2230 int64_t ShiftAmtVal = MatchData.
Imm;
2232 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2233 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2235 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2236 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2237 MI.eraseFromParent();
2244 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2248 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2251 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2252 if (MergedValues[
I] != Unmerge->getReg(
I))
2255 MatchInfo = Unmerge->getSourceReg();
2269 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2270 "Expected an unmerge");
2279 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2280 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2282 if (SrcMergeTy != Dst0Ty && !SameSize)
2286 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2287 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2293 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2294 "Expected an unmerge");
2296 "Not enough operands to replace all defs");
2297 unsigned NumElems =
MI.getNumOperands() - 1;
2299 LLT SrcTy =
MRI.getType(Operands[0]);
2300 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2301 bool CanReuseInputDirectly = DstTy == SrcTy;
2302 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2303 Register DstReg =
MI.getOperand(Idx).getReg();
2308 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2309 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2310 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2311 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2314 if (CanReuseInputDirectly)
2317 Builder.buildCast(DstReg, SrcReg);
2319 MI.eraseFromParent();
2324 unsigned SrcIdx =
MI.getNumOperands() - 1;
2325 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2327 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2328 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2336 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2339 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2341 Val = Val.
lshr(ShiftAmt);
2349 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2350 "Expected an unmerge");
2352 "Not enough operands to replace all defs");
2353 unsigned NumElems =
MI.getNumOperands() - 1;
2354 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2355 Register DstReg =
MI.getOperand(Idx).getReg();
2356 Builder.buildConstant(DstReg, Csts[Idx]);
2359 MI.eraseFromParent();
2365 unsigned SrcIdx =
MI.getNumOperands() - 1;
2366 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2368 unsigned NumElems =
MI.getNumOperands() - 1;
2369 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2370 Register DstReg =
MI.getOperand(Idx).getReg();
2371 B.buildUndef(DstReg);
2379 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2380 "Expected an unmerge");
2381 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2382 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2385 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2386 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2394 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2395 Register Dst0Reg =
MI.getOperand(0).getReg();
2396 Builder.buildTrunc(Dst0Reg, SrcReg);
2397 MI.eraseFromParent();
2401 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2402 "Expected an unmerge");
2403 Register Dst0Reg =
MI.getOperand(0).getReg();
2404 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2410 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2411 LLT SrcTy =
MRI.getType(SrcReg);
2412 if (SrcTy.isVector())
2422 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2427 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2428 "Expected an unmerge");
2430 Register Dst0Reg =
MI.getOperand(0).getReg();
2433 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2435 "Expecting a G_ZEXT");
2438 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2439 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2442 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2445 "ZExt src doesn't fit in destination");
2450 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2452 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2455 MI.eraseFromParent();
2459 unsigned TargetShiftSize,
2460 unsigned &ShiftVal)
const {
2461 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2462 MI.getOpcode() == TargetOpcode::G_LSHR ||
2463 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2465 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2470 unsigned Size = Ty.getSizeInBits();
2471 if (
Size <= TargetShiftSize)
2479 ShiftVal = MaybeImmVal->Value.getSExtValue();
2480 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2487 LLT Ty =
MRI.getType(SrcReg);
2488 unsigned Size = Ty.getSizeInBits();
2489 unsigned HalfSize =
Size / 2;
2490 assert(ShiftVal >= HalfSize);
2494 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2495 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2497 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2498 Register Narrowed = Unmerge.getReg(1);
2505 if (NarrowShiftAmt != 0) {
2506 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2507 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2510 auto Zero =
Builder.buildConstant(HalfTy, 0);
2511 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2512 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2513 Register Narrowed = Unmerge.getReg(0);
2518 if (NarrowShiftAmt != 0) {
2519 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2520 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2523 auto Zero =
Builder.buildConstant(HalfTy, 0);
2524 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2526 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2528 HalfTy, Unmerge.getReg(1),
2529 Builder.buildConstant(HalfTy, HalfSize - 1));
2531 if (ShiftVal == HalfSize) {
2534 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2535 }
else if (ShiftVal ==
Size - 1) {
2543 HalfTy, Unmerge.getReg(1),
2544 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2552 MI.eraseFromParent();
2568 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2570 LLT DstTy =
MRI.getType(DstReg);
2578 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2580 Builder.buildCopy(DstReg, Reg);
2581 MI.eraseFromParent();
2586 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2588 Builder.buildZExtOrTrunc(DstReg, Reg);
2589 MI.eraseFromParent();
2594 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2597 LLT IntTy =
MRI.getType(LHS);
2601 PtrReg.second =
false;
2602 for (
Register SrcReg : {LHS, RHS}) {
2606 LLT PtrTy =
MRI.getType(PtrReg.first);
2611 PtrReg.second =
true;
2623 const bool DoCommute = PtrReg.second;
2628 LLT PtrTy =
MRI.getType(LHS);
2630 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2631 Builder.buildPtrToInt(Dst, PtrAdd);
2632 MI.eraseFromParent();
2636 APInt &NewCst)
const {
2638 Register LHS = PtrAdd.getBaseReg();
2639 Register RHS = PtrAdd.getOffsetReg();
2645 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2648 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2657 APInt &NewCst)
const {
2661 Builder.buildConstant(Dst, NewCst);
2662 PtrAdd.eraseFromParent();
2667 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2672 SrcReg = OriginalSrcReg;
2673 LLT DstTy =
MRI.getType(DstReg);
2681 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2684 LLT DstTy =
MRI.getType(DstReg);
2689 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2690 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2700 if (ShiftSize > 32 && TruncSize < 32)
2713 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2714 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2718 if (!
MRI.hasOneNonDBGUse(SrcReg))
2721 LLT SrcTy =
MRI.getType(SrcReg);
2722 LLT DstTy =
MRI.getType(DstReg);
2731 case TargetOpcode::G_SHL: {
2740 case TargetOpcode::G_LSHR:
2741 case TargetOpcode::G_ASHR: {
2747 for (
auto &
User :
MRI.use_instructions(DstReg))
2748 if (
User.getOpcode() == TargetOpcode::G_STORE)
2752 if (NewShiftTy == SrcTy)
2766 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2769 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2774 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2776 LLT NewShiftTy = MatchInfo.second;
2779 LLT DstTy =
MRI.getType(Dst);
2783 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2787 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2790 if (NewShiftTy == DstTy)
2793 Builder.buildTrunc(Dst, NewShift);
2800 return MO.isReg() &&
2801 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2807 return !MO.isReg() ||
2808 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2813 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2815 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2819 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2820 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2825 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2826 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2832 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2833 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2834 "Expected an insert/extract element op");
2835 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2840 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2848 unsigned &
OpIdx)
const {
2854 OpIdx = Cst->isZero() ? 3 : 2;
2899 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2926 return MO.isReg() && MO.getReg().isPhysical();
2936 return I1->isIdenticalTo(*I2);
2944 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2951 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2963 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2964 MaybeCst->getSExtValue() ==
C;
2971 std::optional<FPValueAndVReg> MaybeCst;
2975 return MaybeCst->Value.isExactlyValue(
C);
2979 unsigned OpIdx)
const {
2980 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2985 MI.eraseFromParent();
2990 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2994 MI.eraseFromParent();
2998 unsigned ConstIdx)
const {
2999 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
3000 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3012 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
3013 MI.getOpcode() == TargetOpcode::G_FSHR) &&
3014 "This is not a funnel shift operation");
3016 Register ConstReg =
MI.getOperand(3).getReg();
3017 LLT ConstTy =
MRI.getType(ConstReg);
3018 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3021 assert((VRegAndVal) &&
"Value is not a constant");
3024 APInt NewConst = VRegAndVal->Value.
urem(
3029 MI.getOpcode(), {MI.getOperand(0)},
3030 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3032 MI.eraseFromParent();
3036 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3050 unsigned OpIdx)
const {
3052 return MO.
isReg() &&
3057 unsigned OpIdx)
const {
3064 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3066 MI.eraseFromParent();
3071 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3073 MI.eraseFromParent();
3077 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3079 MI.eraseFromParent();
3084 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3086 MI.eraseFromParent();
3090 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3092 MI.eraseFromParent();
3096 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3099 Register &NewLHS = std::get<0>(MatchInfo);
3100 Register &NewRHS = std::get<1>(MatchInfo);
3108 NewLHS = MaybeNewLHS;
3112 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3117 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3120 LLT DstTy =
MRI.getType(DstReg);
3129 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3130 TargetOpcode::G_INSERT_VECTOR_ELT)
3136 MatchInfo.
resize(NumElts);
3140 if (IntImm >= NumElts || IntImm < 0)
3142 if (!MatchInfo[IntImm])
3143 MatchInfo[IntImm] = TmpReg;
3147 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3149 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3158 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3165 auto GetUndef = [&]() {
3168 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3176 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3177 MI.eraseFromParent();
3181 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3183 std::tie(SubLHS, SubRHS) = MatchInfo;
3184 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3185 MI.eraseFromParent();
3196 unsigned LogicOpcode =
MI.getOpcode();
3197 assert(LogicOpcode == TargetOpcode::G_AND ||
3198 LogicOpcode == TargetOpcode::G_OR ||
3199 LogicOpcode == TargetOpcode::G_XOR);
3206 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3212 if (!LeftHandInst || !RightHandInst)
3214 unsigned HandOpcode = LeftHandInst->
getOpcode();
3215 if (HandOpcode != RightHandInst->
getOpcode())
3229 if (!XTy.
isValid() || XTy != YTy)
3234 switch (HandOpcode) {
3237 case TargetOpcode::G_ANYEXT:
3238 case TargetOpcode::G_SEXT:
3239 case TargetOpcode::G_ZEXT: {
3243 case TargetOpcode::G_TRUNC: {
3248 LLT DstTy =
MRI.getType(Dst);
3257 case TargetOpcode::G_AND:
3258 case TargetOpcode::G_ASHR:
3259 case TargetOpcode::G_LSHR:
3260 case TargetOpcode::G_SHL: {
3265 ExtraHandOpSrcReg = ZOp.
getReg();
3276 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3287 if (ExtraHandOpSrcReg.
isValid())
3299 "Expected at least one instr to build?");
3301 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3302 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3304 for (
auto &OperandFn : InstrToBuild.OperandFns)
3307 MI.eraseFromParent();
3311 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3312 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3313 int64_t ShlCst, AshrCst;
3319 if (ShlCst != AshrCst)
3322 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3324 MatchInfo = std::make_tuple(Src, ShlCst);
3329 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3330 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3333 std::tie(Src, ShiftAmt) = MatchInfo;
3334 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3335 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3336 MI.eraseFromParent();
3343 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3346 LLT Ty =
MRI.getType(Dst);
3358 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3361 auto Zero =
B.buildConstant(Ty, 0);
3384 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3408 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3415 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3432 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3450 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3457 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3468 unsigned ExtBits =
MI.getOperand(2).getImm();
3469 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3470 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3474 int64_t Cst,
bool IsVector,
bool IsFP) {
3476 return (ScalarSizeBits == 1 && Cst == -1) ||
3498 unsigned BuildUseCount = BV.getNumSources();
3499 if (BuildUseCount % 2 != 0)
3502 unsigned NumUnmerge = BuildUseCount / 2;
3508 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3511 UnmergeSrc = Unmerge->getSourceReg();
3513 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3514 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3521 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3526 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3527 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3530 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3533 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3538 if (Unmerge->getNumDefs() != NumUnmerge)
3542 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3545 if (
Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3556 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3557 B.setInstrAndDebugLoc(
MI);
3559 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3560 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3562 MI.eraseFromParent();
3584 unsigned NumOperands =
BuildMI->getNumSources();
3592 for (
I = 0;
I < NumOperands; ++
I) {
3593 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3594 auto SrcMIOpc = SrcMI->getOpcode();
3597 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3599 UnmergeMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3600 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3603 auto UnmergeSrcMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3604 if (UnmergeMI != UnmergeSrcMI)
3615 for (;
I < NumOperands; ++
I) {
3616 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3617 auto SrcMIOpc = SrcMI->getOpcode();
3619 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3625 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3632 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3633 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3641 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3644 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3656 LLT DstTy =
MRI.getType(DstReg);
3657 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3662 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3667 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3671 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3674 Builder.buildTrunc(DstReg, MidReg);
3675 MI.eraseFromParent();
3680 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3681 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3682 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3690 if (!
MRI.hasOneNonDBGUse(XorSrc))
3700 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3702 if (!
MRI.hasOneNonDBGUse(Reg))
3705 switch (Def->getOpcode()) {
3710 case TargetOpcode::G_ICMP:
3716 case TargetOpcode::G_FCMP:
3722 case TargetOpcode::G_AND:
3723 case TargetOpcode::G_OR:
3729 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3730 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3738 if (Ty.isVector()) {
3743 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3757 for (
Register Reg : RegsToNegate) {
3762 switch (Def->getOpcode()) {
3765 case TargetOpcode::G_ICMP:
3766 case TargetOpcode::G_FCMP: {
3773 case TargetOpcode::G_AND:
3774 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3776 case TargetOpcode::G_OR:
3777 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3784 MI.eraseFromParent();
3788 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3790 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3794 Register SharedReg =
MI.getOperand(2).getReg();
3808 if (!
MRI.hasOneNonDBGUse(AndReg))
3815 return Y == SharedReg;
3819 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3822 std::tie(
X,
Y) = MatchInfo;
3825 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3826 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3827 MI.getOperand(2).setReg(
Y);
3833 Register DstReg = PtrAdd.getReg(0);
3834 LLT Ty =
MRI.getType(DstReg);
3837 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3840 if (Ty.isPointer()) {
3842 return ConstVal && *ConstVal == 0;
3845 assert(Ty.isVector() &&
"Expecting a vector type");
3852 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3853 PtrAdd.eraseFromParent();
3860 Register Pow2Src1 =
MI.getOperand(2).getReg();
3861 LLT Ty =
MRI.getType(DstReg);
3864 auto NegOne =
Builder.buildConstant(Ty, -1);
3865 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3867 MI.eraseFromParent();
3871 unsigned &SelectOpNo)
const {
3881 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3882 !
MRI.hasOneNonDBGUse(LHS)) {
3883 OtherOperandReg = LHS;
3886 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3887 !
MRI.hasOneNonDBGUse(RHS))
3903 unsigned BinOpcode =
MI.getOpcode();
3908 bool CanFoldNonConst =
3909 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3914 if (CanFoldNonConst)
3935 LLT Ty =
MRI.getType(Dst);
3936 unsigned BinOpcode =
MI.getOpcode();
3943 if (SelectOperand == 1) {
3947 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3949 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3951 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3953 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3956 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3957 MI.eraseFromParent();
3960std::optional<SmallVector<Register, 8>>
3961CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3962 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3991 const unsigned MaxIter =
3993 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
4001 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
4002 return std::nullopt;
4018 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4019 return std::nullopt;
4031static std::optional<std::pair<GZExtLoad *, int64_t>>
4035 "Expected Reg to only have one non-debug use?");
4044 if (Shift % MemSizeInBits != 0)
4045 return std::nullopt;
4050 return std::nullopt;
4052 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4053 return std::nullopt;
4055 return std::make_pair(Load, Shift / MemSizeInBits);
4058std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4059CombinerHelper::findLoadOffsetsForLoadOrCombine(
4062 const unsigned MemSizeInBits)
const {
4065 SmallSetVector<const MachineInstr *, 8> Loads;
4071 GZExtLoad *LowestIdxLoad =
nullptr;
4074 SmallSet<int64_t, 8> SeenIdx;
4078 MachineBasicBlock *
MBB =
nullptr;
4079 const MachineMemOperand *MMO =
nullptr;
4082 GZExtLoad *EarliestLoad =
nullptr;
4085 GZExtLoad *LatestLoad =
nullptr;
4094 for (
auto Reg : RegsToVisit) {
4099 return std::nullopt;
4102 std::tie(Load, DstPos) = *LoadAndPos;
4106 MachineBasicBlock *LoadMBB =
Load->getParent();
4110 return std::nullopt;
4113 auto &LoadMMO =
Load->getMMO();
4117 return std::nullopt;
4124 LoadPtr =
Load->getOperand(1).getReg();
4129 if (!SeenIdx.
insert(Idx).second)
4130 return std::nullopt;
4137 if (BasePtr != LoadPtr)
4138 return std::nullopt;
4140 if (Idx < LowestIdx) {
4142 LowestIdxLoad =
Load;
4149 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4150 return std::nullopt;
4158 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4159 EarliestLoad =
Load;
4160 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4167 "Expected to find a load for each register?");
4168 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4169 LatestLoad &&
"Expected at least two loads?");
4178 const unsigned MaxIter = 20;
4184 if (
MI.isLoadFoldBarrier())
4185 return std::nullopt;
4186 if (Iter++ == MaxIter)
4187 return std::nullopt;
4190 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4196 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4209 LLT Ty =
MRI.getType(Dst);
4215 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4216 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4220 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4227 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4228 if (NarrowMemSizeInBits % 8 != 0)
4241 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4242 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4245 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4252 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4255 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4267 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4268 const unsigned ZeroByteOffset =
4272 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4273 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4274 ZeroOffsetIdx->second != LowestIdx)
4284 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4298 MIB.setInstrAndDebugLoc(*LatestLoad);
4299 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4300 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4302 MIB.buildBSwap(Dst, LoadDst);
4314 if (
MRI.getType(DstReg).isVector())
4318 if (!
MRI.hasOneNonDBGUse(DstReg))
4320 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4322 case TargetOpcode::G_ANYEXT:
4324 case TargetOpcode::G_ZEXT:
4325 case TargetOpcode::G_SEXT:
4332 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4339 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4341 switch (
DefMI->getOpcode()) {
4342 case TargetOpcode::G_LOAD:
4343 case TargetOpcode::G_TRUNC:
4344 case TargetOpcode::G_SEXT:
4345 case TargetOpcode::G_ZEXT:
4346 case TargetOpcode::G_ANYEXT:
4347 case TargetOpcode::G_CONSTANT:
4351 if (InSrcs.
size() > 2)
4365 LLT ExtTy =
MRI.getType(DstReg);
4372 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4373 auto SrcReg =
PHI.getIncomingValue(
I);
4374 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4375 if (!SrcMIs.
insert(SrcMI))
4379 auto *
MBB = SrcMI->getParent();
4381 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4382 InsertPt =
MBB->getFirstNonPHI();
4384 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4387 OldToNewSrcMap[SrcMI] = NewExt;
4392 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4393 NewPhi.addDef(DstReg);
4396 NewPhi.addMBB(MO.getMBB());
4399 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4400 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4408 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4412 LLT SrcTy =
MRI.getType(SrcVec);
4413 if (SrcTy.isScalableVector())
4417 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4420 unsigned VecIdx = Cst->Value.getZExtValue();
4425 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4429 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4430 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4434 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4446 LLT ScalarTy =
MRI.getType(Reg);
4448 LLT DstTy =
MRI.getType(DstReg);
4450 if (ScalarTy != DstTy) {
4452 Builder.buildTrunc(DstReg, Reg);
4453 MI.eraseFromParent();
4461 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4462 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4480 LLT DstTy =
MRI.getType(DstReg);
4485 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4490 unsigned Idx = Cst->getZExtValue();
4493 ExtractedElts.
set(Idx);
4494 SrcDstPairs.emplace_back(
4495 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4498 return ExtractedElts.
all();
4503 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4504 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4505 for (
auto &Pair : SrcDstPairs) {
4506 auto *ExtMI = Pair.second;
4508 ExtMI->eraseFromParent();
4510 MI.eraseFromParent();
4517 MI.eraseFromParent();
4527 bool AllowScalarConstants,
4529 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4532 LLT Ty =
MRI.getType(Dst);
4533 unsigned BitWidth = Ty.getScalarSizeInBits();
4535 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4536 unsigned FshOpc = 0;
4547 int64_t CstShlAmt = 0, CstLShrAmt;
4550 CstShlAmt + CstLShrAmt ==
BitWidth) {
4551 FshOpc = TargetOpcode::G_FSHR;
4557 FshOpc = TargetOpcode::G_FSHL;
4562 FshOpc = TargetOpcode::G_FSHR;
4567 LLT AmtTy =
MRI.getType(Amt);
4569 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4573 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4580 unsigned Opc =
MI.getOpcode();
4581 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4586 unsigned RotateOpc =
4587 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4592 unsigned Opc =
MI.getOpcode();
4593 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4594 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4596 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4597 : TargetOpcode::G_ROTR));
4598 MI.removeOperand(2);
4604 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4605 MI.getOpcode() == TargetOpcode::G_ROTR);
4607 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4609 bool OutOfRange =
false;
4610 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4612 OutOfRange |= CI->getValue().uge(Bitsize);
4619 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4620 MI.getOpcode() == TargetOpcode::G_ROTR);
4622 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4624 LLT AmtTy =
MRI.getType(Amt);
4625 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4626 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4628 MI.getOperand(2).setReg(Amt);
4633 int64_t &MatchInfo)
const {
4634 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4645 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4646 if (KnownRHS.isUnknown())
4649 std::optional<bool> KnownVal;
4650 if (KnownRHS.isZero()) {
4660 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4670 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4679 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4695 LLT DstTy =
MRI.getType(Dst);
4703 auto KnownLHS =
VT->getKnownBits(LHS);
4704 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4707 LLT LHSTy =
MRI.getType(LHS);
4710 unsigned Op = TargetOpcode::COPY;
4711 if (DstSize != LHSSize)
4712 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4723 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4727 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4733 int64_t AndMaskBits;
4741 if (AndMaskBits & OrMaskBits)
4747 if (
MI.getOperand(1).getReg() == AndMaskReg)
4748 MI.getOperand(2).setReg(AndMaskReg);
4749 MI.getOperand(1).setReg(Src);
4759 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4762 LLT Ty =
MRI.getType(Src);
4764 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4766 int64_t Width =
MI.getOperand(2).getImm();
4774 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4778 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4779 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4780 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4790 LLT Ty =
MRI.getType(Dst);
4794 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4797 int64_t AndImm, LSBImm;
4799 const unsigned Size = Ty.getScalarSizeInBits();
4806 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4807 if (MaybeMask & (MaybeMask + 1))
4816 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4817 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4818 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4826 const unsigned Opcode =
MI.getOpcode();
4827 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4829 const Register Dst =
MI.getOperand(0).getReg();
4831 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4832 ? TargetOpcode::G_SBFX
4833 : TargetOpcode::G_UBFX;
4836 LLT Ty =
MRI.getType(Dst);
4838 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4844 const unsigned Size = Ty.getScalarSizeInBits();
4854 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4858 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4862 const int64_t Pos = ShrAmt - ShlAmt;
4863 const int64_t Width =
Size - ShrAmt;
4866 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4867 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4868 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4876 const unsigned Opcode =
MI.getOpcode();
4877 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4879 const Register Dst =
MI.getOperand(0).getReg();
4880 LLT Ty =
MRI.getType(Dst);
4882 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4895 const unsigned Size = Ty.getScalarSizeInBits();
4896 if (ShrAmt < 0 || ShrAmt >=
Size)
4900 if (0 == (SMask >> ShrAmt)) {
4902 B.buildConstant(Dst, 0);
4908 uint64_t UMask = SMask;
4915 const int64_t Pos = ShrAmt;
4920 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4924 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4925 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4926 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4931bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4935 Register Src1Reg = PtrAdd.getBaseReg();
4940 Register Src2Reg = PtrAdd.getOffsetReg();
4942 if (
MRI.hasOneNonDBGUse(Src1Reg))
4952 const APInt &C1APIntVal = *C1;
4953 const APInt &C2APIntVal = *C2;
4954 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4956 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4959 MachineInstr *ConvUseMI = &
UseMI;
4960 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4961 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4962 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4964 if (!
MRI.hasOneNonDBGUse(DefReg))
4966 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4975 TargetLoweringBase::AddrMode AM;
4978 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4980 PtrAdd.getMF()->getFunction().getContext());
4981 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4982 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4988 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
5000 Register Src1Reg =
MI.getOperand(1).getReg();
5001 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5013 unsigned PtrAddFlags =
MI.getFlags();
5014 unsigned AddFlags = RHS->getFlags();
5027 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5030 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5032 MI.getOperand(1).setReg(NewBase.getReg(0));
5033 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5037 return !reassociationCanBreakAddressingModePattern(
MI);
5047 std::optional<ValueAndVReg> LHSCstOff;
5057 unsigned PtrAddFlags =
MI.getFlags();
5058 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5060 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5062 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5076 LHSPtrAdd->moveBefore(&
MI);
5079 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5081 MI.getOperand(2).setReg(NewCst.getReg(0));
5084 Observer.changingInstr(*LHSPtrAdd);
5085 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5086 LHSPtrAdd->setFlags(Flags);
5089 return !reassociationCanBreakAddressingModePattern(
MI);
5100 Register Src2Reg =
MI.getOperand(2).getReg();
5101 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5102 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5115 unsigned PtrAddFlags =
MI.getFlags();
5116 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5129 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5131 MI.getOperand(1).setReg(LHSSrc1);
5132 MI.getOperand(2).setReg(NewCst.getReg(0));
5136 return !reassociationCanBreakAddressingModePattern(
MI);
5174 LLT OpRHSTy =
MRI.getType(OpRHS);
5193 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5194 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5202 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5203 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5216 unsigned Opc =
MI.getOpcode();
5229 APInt &MatchInfo)
const {
5230 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5234 MatchInfo = *MaybeCst;
5242 APInt &MatchInfo)
const {
5248 MatchInfo = *MaybeCst;
5260 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5266 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5267 MI.getOpcode() == TargetOpcode::G_FMAD);
5268 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5285 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5308 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5312 LLT WideTy =
MRI.getType(Dst);
5316 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5332 case TargetOpcode::G_ADD:
5333 case TargetOpcode::G_SUB:
5334 case TargetOpcode::G_MUL:
5335 case TargetOpcode::G_AND:
5336 case TargetOpcode::G_OR:
5337 case TargetOpcode::G_XOR:
5345 auto Mask = Cst->Value;
5350 unsigned NarrowWidth = Mask.countr_one();
5356 auto &MF = *
MI.getMF();
5359 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5360 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5368 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5369 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5371 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5372 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5374 MI.getOperand(1).setReg(Ext.getReg(0));
5382 unsigned Opc =
MI.getOpcode();
5383 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5390 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5391 : TargetOpcode::G_SADDO;
5392 MI.setDesc(
Builder.getTII().get(NewOpc));
5393 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5402 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5403 MI.getOpcode() == TargetOpcode::G_SMULO);
5412 B.buildConstant(Dst, 0);
5413 B.buildConstant(Carry, 0);
5422 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5423 MI.getOpcode() == TargetOpcode::G_SADDE ||
5424 MI.getOpcode() == TargetOpcode::G_USUBE ||
5425 MI.getOpcode() == TargetOpcode::G_SSUBE);
5430 switch (
MI.getOpcode()) {
5431 case TargetOpcode::G_UADDE:
5432 NewOpcode = TargetOpcode::G_UADDO;
5434 case TargetOpcode::G_SADDE:
5435 NewOpcode = TargetOpcode::G_SADDO;
5437 case TargetOpcode::G_USUBE:
5438 NewOpcode = TargetOpcode::G_USUBO;
5440 case TargetOpcode::G_SSUBE:
5441 NewOpcode = TargetOpcode::G_SSUBO;
5445 MI.setDesc(
B.getTII().get(NewOpcode));
5446 MI.removeOperand(4);
5454 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5487 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5488 B.buildSub(Dst, Zero, ReplaceReg);
5497 unsigned Opcode =
MI.getOpcode();
5498 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5500 Register Dst = UDivorRem.getReg(0);
5501 Register LHS = UDivorRem.getReg(1);
5502 Register RHS = UDivorRem.getReg(2);
5503 LLT Ty =
MRI.getType(Dst);
5511 bool UseSRL =
false;
5516 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5518 if (IsSplat && !Factors.
empty()) {
5525 APInt Divisor = CI->getValue();
5534 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5535 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5545 if (Ty.isVector()) {
5546 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5547 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5550 Factor = Factors[0];
5558 return MIB.buildMul(Ty, Res, Factor);
5561 unsigned KnownLeadingZeros =
5562 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5564 bool UseNPQ =
false;
5566 auto BuildUDIVPattern = [&](
const Constant *
C) {
5568 const APInt &Divisor = CI->getValue();
5570 bool SelNPQ =
false;
5572 unsigned PreShift = 0, PostShift = 0;
5577 if (!Divisor.
isOne()) {
5583 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5585 Magic = std::move(magics.
Magic);
5588 "We shouldn't generate an undefined shift!");
5590 "We shouldn't generate an undefined shift!");
5594 SelNPQ = magics.
IsAdd;
5598 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5599 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5601 MIB.buildConstant(ScalarTy,
5606 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5614 assert(Matched &&
"Expected unary predicate match to succeed");
5616 Register PreShift, PostShift, MagicFactor, NPQFactor;
5619 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5620 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5621 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5622 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5625 "Non-build_vector operation should have been a scalar");
5626 PreShift = PreShifts[0];
5627 MagicFactor = MagicFactors[0];
5628 PostShift = PostShifts[0];
5632 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5635 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5638 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5643 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5645 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5647 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5650 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5651 auto One = MIB.buildConstant(Ty, 1);
5652 auto IsOne = MIB.buildICmp(
5654 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5655 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5657 if (Opcode == TargetOpcode::G_UREM) {
5658 auto Prod = MIB.buildMul(Ty, ret, RHS);
5659 return MIB.buildSub(Ty, LHS, Prod);
5665 unsigned Opcode =
MI.getOpcode();
5666 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5669 LLT DstTy =
MRI.getType(Dst);
5671 auto &MF = *
MI.getMF();
5672 AttributeList Attr = MF.getFunction().getAttributes();
5680 if (MF.getFunction().hasMinSize())
5683 if (Opcode == TargetOpcode::G_UDIV &&
5686 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5689 auto *RHSDef =
MRI.getVRegDef(RHS);
5700 {TargetOpcode::G_ICMP,
5704 if (Opcode == TargetOpcode::G_UREM &&
5710 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5719 unsigned Opcode =
MI.getOpcode();
5720 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5723 LLT DstTy =
MRI.getType(Dst);
5727 auto &MF = *
MI.getMF();
5728 AttributeList Attr = MF.getFunction().getAttributes();
5736 if (MF.getFunction().hasMinSize())
5740 if (Opcode == TargetOpcode::G_SDIV &&
5743 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5746 auto *RHSDef =
MRI.getVRegDef(RHS);
5754 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5757 if (Opcode == TargetOpcode::G_SREM &&
5763 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5772 unsigned Opcode =
MI.getOpcode();
5773 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5774 Opcode == TargetOpcode::G_SREM);
5776 Register Dst = SDivorRem.getReg(0);
5777 Register LHS = SDivorRem.getReg(1);
5778 Register RHS = SDivorRem.getReg(2);
5779 LLT Ty =
MRI.getType(Dst);
5786 bool UseSRA =
false;
5792 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5794 if (IsSplat && !ExactFactors.
empty()) {
5796 ExactFactors.
push_back(ExactFactors[0]);
5801 APInt Divisor = CI->getValue();
5811 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5812 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5820 assert(Matched &&
"Expected unary predicate match to succeed");
5823 if (Ty.isVector()) {
5824 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5825 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5827 Shift = ExactShifts[0];
5828 Factor = ExactFactors[0];
5836 return MIB.buildMul(Ty, Res, Factor);
5841 auto BuildSDIVPattern = [&](
const Constant *
C) {
5843 const APInt &Divisor = CI->getValue();
5847 int NumeratorFactor = 0;
5858 NumeratorFactor = 1;
5861 NumeratorFactor = -1;
5864 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5865 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5867 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5868 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5876 assert(Matched &&
"Expected unary predicate match to succeed");
5878 Register MagicFactor, Factor, Shift, ShiftMask;
5881 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5882 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5883 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5884 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5887 "Non-build_vector operation should have been a scalar");
5888 MagicFactor = MagicFactors[0];
5889 Factor = Factors[0];
5891 ShiftMask = ShiftMasks[0];
5895 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5898 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5899 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5902 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5905 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5906 auto T = MIB.buildLShr(Ty, Q, SignShift);
5907 T = MIB.buildAnd(Ty,
T, ShiftMask);
5908 auto ret = MIB.buildAdd(Ty, Q,
T);
5910 if (Opcode == TargetOpcode::G_SREM) {
5911 auto Prod = MIB.buildMul(Ty, ret, RHS);
5912 return MIB.buildSub(Ty, LHS, Prod);
5918 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5919 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5920 "Expected SDIV or UDIV");
5923 auto MatchPow2 = [&](
const Constant *
C) {
5925 return CI && (CI->getValue().isPowerOf2() ||
5926 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5932 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5937 LLT Ty =
MRI.getType(Dst);
5957 unsigned BitWidth = Ty.getScalarSizeInBits();
5958 auto Zero =
Builder.buildConstant(Ty, 0);
5961 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5962 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5964 auto Sign =
Builder.buildAShr(
5968 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5974 auto One =
Builder.buildConstant(Ty, 1);
5975 auto MinusOne =
Builder.buildConstant(Ty, -1);
5979 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5980 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5984 auto Neg =
Builder.buildNeg(Ty, AShr);
5986 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5987 MI.eraseFromParent();
5991 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5996 LLT Ty =
MRI.getType(Dst);
5999 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
6000 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
6001 MI.eraseFromParent();
6005 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
6008 LLT Ty =
MRI.getType(Dst);
6009 LLT RHSTy =
MRI.getType(RHS);
6011 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6013 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6028 LLT Ty =
MRI.getType(Dst);
6034 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6035 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6036 Builder.buildLShr(Dst, LHS, Trunc);
6037 MI.eraseFromParent();
6044 LLT DstTy =
MRI.getType(Dst);
6045 LLT SrcTy =
MRI.getType(Src);
6047 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6048 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6050 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6068 Builder.buildTruncSSatS(Dst, MatchInfo);
6069 MI.eraseFromParent();
6076 LLT DstTy =
MRI.getType(Dst);
6077 LLT SrcTy =
MRI.getType(Src);
6079 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6080 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6082 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6100 Builder.buildTruncSSatU(Dst, MatchInfo);
6101 MI.eraseFromParent();
6108 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6109 LLT SrcTy =
MRI.getType(Val);
6111 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6112 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6114 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6123 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6132 unsigned Opc =
MI.getOpcode();
6133 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6134 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6135 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6147 Opc = TargetOpcode::G_FSUB;
6152 Opc = TargetOpcode::G_FADD;
6158 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6159 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6168 MI.setDesc(
B.getTII().get(
Opc));
6169 MI.getOperand(1).setReg(
X);
6170 MI.getOperand(2).setReg(
Y);
6178 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6181 MatchInfo =
MI.getOperand(2).getReg();
6182 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6184 const auto LHSCst = Ty.isVector()
6191 if (LHSCst->Value.isNegZero())
6195 if (LHSCst->Value.isPosZero())
6205 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6212 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6220 MRI.use_instr_nodbg_end()) >
6222 MRI.use_instr_nodbg_end());
6226 bool &AllowFusionGlobally,
6228 bool CanReassociate)
const {
6230 auto *MF =
MI.getMF();
6231 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6233 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6241 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6244 if (!HasFMAD && !HasFMA)
6252 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6259 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6261 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6269 unsigned PreferredFusedOpcode =
6270 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6284 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6285 {LHS.MI->getOperand(1).getReg(),
6286 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6295 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6296 {RHS.MI->getOperand(1).getReg(),
6297 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6308 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6310 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6314 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6319 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6321 unsigned PreferredFusedOpcode =
6322 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6336 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6341 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6342 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6351 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6356 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6357 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6368 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6370 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6378 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6380 unsigned PreferredFusedOpcode =
6381 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6394 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6395 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6396 TargetOpcode::G_FMUL) &&
6397 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6398 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6403 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6404 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6405 TargetOpcode::G_FMUL) &&
6406 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6407 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6414 Register X = FMA->getOperand(1).getReg();
6415 Register Y = FMA->getOperand(2).getReg();
6420 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6421 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6422 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6434 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6436 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6443 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6444 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6450 unsigned PreferredFusedOpcode =
6451 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6464 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6465 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6467 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6469 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6476 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6480 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6485 LHS.MI->getOperand(1).getReg(),
6486 LHS.MI->getOperand(2).getReg(),
B);
6497 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6500 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6505 X =
B.buildFPExt(DstType,
X).getReg(0);
6506 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6517 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6521 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6526 RHS.MI->getOperand(1).getReg(),
6527 RHS.MI->getOperand(2).getReg(),
B);
6538 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6541 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6546 X =
B.buildFPExt(DstType,
X).getReg(0);
6547 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6561 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6563 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6571 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6575 int FirstMulHasFewerUses =
true;
6579 FirstMulHasFewerUses =
false;
6581 unsigned PreferredFusedOpcode =
6582 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6585 if (FirstMulHasFewerUses &&
6589 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6590 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6591 {LHS.MI->getOperand(1).getReg(),
6592 LHS.MI->getOperand(2).getReg(), NegZ});
6601 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6602 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6603 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6614 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6616 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6622 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6624 unsigned PreferredFusedOpcode =
6625 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6636 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6637 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6649 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6662 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6664 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6670 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6672 unsigned PreferredFusedOpcode =
6673 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6685 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6686 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6687 {FpExtX, FpExtY, NegZ});
6699 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6702 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6703 {NegY, FpExtZ, LHSReg});
6714 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6716 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6720 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6721 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6725 unsigned PreferredFusedOpcode =
6726 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6730 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6731 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6732 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6743 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6746 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6749 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6759 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6772 unsigned &IdxToPropagate)
const {
6774 switch (
MI.getOpcode()) {
6777 case TargetOpcode::G_FMINNUM:
6778 case TargetOpcode::G_FMAXNUM:
6779 PropagateNaN =
false;
6781 case TargetOpcode::G_FMINIMUM:
6782 case TargetOpcode::G_FMAXIMUM:
6783 PropagateNaN =
true;
6787 auto MatchNaN = [&](
unsigned Idx) {
6788 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6792 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6796 return MatchNaN(1) || MatchNaN(2);
6804 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6814 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6827 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6828 if (&U == &
MI || U.getParent() !=
MI.getParent())
6830 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6831 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6844 return MatchInfo.
size() >= MinUses;
6852 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6853 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6854 MatchInfo[0]->getOperand(2).getReg(),
6855 MatchInfo[0]->getFlags());
6860 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6861 Div->getOperand(0).getReg(),
MI->getFlags());
6862 MI->eraseFromParent();
6867 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6877 Reg == MaybeSameReg;
6879 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6900 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6909 return MRI.getType(MatchInfo) == DstVecTy;
6912 std::optional<ValueAndVReg> ShiftAmount;
6921 return MRI.getType(MatchInfo) == DstVecTy;
6936 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6943 std::optional<ValueAndVReg> ShiftAmt;
6949 LLT MatchTy =
MRI.getType(MatchInfo);
6950 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6951 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6954unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6956 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6957 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6958 "Expected a NaN behaviour?");
6968 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6969 return TargetOpcode::G_FMAXNUM;
6970 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6971 return TargetOpcode::G_FMAXIMUM;
6972 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6973 return TargetOpcode::G_FMAXNUM;
6974 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6975 return TargetOpcode::G_FMAXIMUM;
6981 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6982 return TargetOpcode::G_FMINNUM;
6983 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6984 return TargetOpcode::G_FMINIMUM;
6985 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6986 return TargetOpcode::G_FMINNUM;
6987 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6989 return TargetOpcode::G_FMINIMUM;
6993CombinerHelper::SelectPatternNaNBehaviour
6995 bool IsOrderedComparison)
const {
6999 if (!LHSSafe && !RHSSafe)
7000 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
7001 if (LHSSafe && RHSSafe)
7002 return SelectPatternNaNBehaviour::RETURNS_ANY;
7005 if (IsOrderedComparison)
7006 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
7007 : SelectPatternNaNBehaviour::RETURNS_OTHER;
7010 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
7011 : SelectPatternNaNBehaviour::RETURNS_NAN;
7020 LLT DstTy =
MRI.getType(Dst);
7033 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7035 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7037 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7040 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7041 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7042 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7043 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7045 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7048 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7053 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7058 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7060 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7064 MatchInfo = [=](MachineIRBuilder &
B) {
7065 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7073 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7080 Register TrueVal =
MI.getOperand(2).getReg();
7081 Register FalseVal =
MI.getOperand(3).getReg();
7082 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7087 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7100 if (MatchedSub &&
X != OpLHS)
7108 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7111 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7112 B.buildICmp(Pred, Dst,
Y, Zero);
7119static std::optional<unsigned>
7121 std::optional<int64_t> &Result) {
7122 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7123 Opcode == TargetOpcode::G_ASHR) &&
7124 "Expect G_SHL, G_LSHR or G_ASHR.");
7125 auto SignificantBits = 0;
7127 case TargetOpcode::G_SHL:
7131 case TargetOpcode::G_LSHR:
7135 case TargetOpcode::G_ASHR:
7144 Result = std::nullopt;
7155 Register ShiftVal =
MI.getOperand(1).getReg();
7156 Register ShiftReg =
MI.getOperand(2).getReg();
7157 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7158 auto IsShiftTooBig = [&](
const Constant *
C) {
7163 MatchInfo = std::nullopt;
7167 MI.getOpcode(), MatchInfo);
7168 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7174 unsigned LHSOpndIdx = 1;
7175 unsigned RHSOpndIdx = 2;
7176 switch (
MI.getOpcode()) {
7177 case TargetOpcode::G_UADDO:
7178 case TargetOpcode::G_SADDO:
7179 case TargetOpcode::G_UMULO:
7180 case TargetOpcode::G_SMULO:
7187 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7188 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7193 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7194 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7198 return MRI.getVRegDef(RHS)->getOpcode() !=
7199 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7206 std::optional<FPValueAndVReg> ValAndVReg;
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 LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7228 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7229 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7230 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7234bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7235 LLT SrcTy =
MRI.getType(Src);
7236 if (SrcTy.isFixedVector())
7237 return isConstantSplatVector(Src, 1, AllowUndefs);
7238 if (SrcTy.isScalar()) {
7242 return IConstant && IConstant->Value == 1;
7247bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7248 LLT SrcTy =
MRI.getType(Src);
7250 return isConstantSplatVector(Src, 0, AllowUndefs);
7255 return IConstant && IConstant->Value == 0;
7262bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7263 bool AllowUndefs)
const {
7269 for (
unsigned I = 0;
I < NumSources; ++
I) {
7270 GImplicitDef *ImplicitDef =
7272 if (ImplicitDef && AllowUndefs)
7274 if (ImplicitDef && !AllowUndefs)
7276 std::optional<ValueAndVReg> IConstant =
7278 if (IConstant && IConstant->Value == SplatValue)
7288CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7291 return IConstant->Value;
7295 return std::nullopt;
7298 std::optional<APInt>
Value = std::nullopt;
7299 for (
unsigned I = 0;
I < NumSources; ++
I) {
7300 std::optional<ValueAndVReg> IConstant =
7303 return std::nullopt;
7305 Value = IConstant->Value;
7306 else if (*
Value != IConstant->Value)
7307 return std::nullopt;
7313bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7323 for (
unsigned I = 0;
I < NumSources; ++
I) {
7324 std::optional<ValueAndVReg> IConstant =
7333bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7340 LLT CondTy =
MRI.getType(
Select->getCondReg());
7341 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7351 std::optional<ValueAndVReg> TrueOpt =
7353 std::optional<ValueAndVReg> FalseOpt =
7356 if (!TrueOpt || !FalseOpt)
7359 APInt TrueValue = TrueOpt->Value;
7360 APInt FalseValue = FalseOpt->Value;
7364 MatchInfo = [=](MachineIRBuilder &
B) {
7365 B.setInstrAndDebugLoc(*
Select);
7366 B.buildZExtOrTrunc(Dest,
Cond);
7373 MatchInfo = [=](MachineIRBuilder &
B) {
7374 B.setInstrAndDebugLoc(*
Select);
7375 B.buildSExtOrTrunc(Dest,
Cond);
7382 MatchInfo = [=](MachineIRBuilder &
B) {
7383 B.setInstrAndDebugLoc(*
Select);
7384 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7385 B.buildNot(Inner,
Cond);
7386 B.buildZExtOrTrunc(Dest, Inner);
7393 MatchInfo = [=](MachineIRBuilder &
B) {
7394 B.setInstrAndDebugLoc(*
Select);
7395 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7396 B.buildNot(Inner,
Cond);
7397 B.buildSExtOrTrunc(Dest, Inner);
7403 if (TrueValue - 1 == FalseValue) {
7404 MatchInfo = [=](MachineIRBuilder &
B) {
7405 B.setInstrAndDebugLoc(*
Select);
7406 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7407 B.buildZExtOrTrunc(Inner,
Cond);
7408 B.buildAdd(Dest, Inner, False);
7414 if (TrueValue + 1 == FalseValue) {
7415 MatchInfo = [=](MachineIRBuilder &
B) {
7416 B.setInstrAndDebugLoc(*
Select);
7417 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7418 B.buildSExtOrTrunc(Inner,
Cond);
7419 B.buildAdd(Dest, Inner, False);
7426 MatchInfo = [=](MachineIRBuilder &
B) {
7427 B.setInstrAndDebugLoc(*
Select);
7428 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7429 B.buildZExtOrTrunc(Inner,
Cond);
7432 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7433 B.buildShl(Dest, Inner, ShAmtC, Flags);
7440 MatchInfo = [=](MachineIRBuilder &
B) {
7441 B.setInstrAndDebugLoc(*
Select);
7443 B.buildNot(Not,
Cond);
7444 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7445 B.buildZExtOrTrunc(Inner, Not);
7448 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7449 B.buildShl(Dest, Inner, ShAmtC, Flags);
7456 MatchInfo = [=](MachineIRBuilder &
B) {
7457 B.setInstrAndDebugLoc(*
Select);
7458 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7459 B.buildSExtOrTrunc(Inner,
Cond);
7460 B.buildOr(Dest, Inner, False, Flags);
7467 MatchInfo = [=](MachineIRBuilder &
B) {
7468 B.setInstrAndDebugLoc(*
Select);
7470 B.buildNot(Not,
Cond);
7471 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7472 B.buildSExtOrTrunc(Inner, Not);
7473 B.buildOr(Dest, Inner, True, Flags);
7482bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7489 LLT CondTy =
MRI.getType(
Select->getCondReg());
7490 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7499 if (CondTy != TrueTy)
7504 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7505 MatchInfo = [=](MachineIRBuilder &
B) {
7506 B.setInstrAndDebugLoc(*
Select);
7507 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7508 B.buildZExtOrTrunc(Ext,
Cond);
7509 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7510 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7517 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7518 MatchInfo = [=](MachineIRBuilder &
B) {
7519 B.setInstrAndDebugLoc(*
Select);
7520 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7521 B.buildZExtOrTrunc(Ext,
Cond);
7522 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7523 B.buildAnd(DstReg, Ext, FreezeTrue);
7529 if (isOneOrOneSplat(False,
true)) {
7530 MatchInfo = [=](MachineIRBuilder &
B) {
7531 B.setInstrAndDebugLoc(*
Select);
7533 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7534 B.buildNot(Inner,
Cond);
7536 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7537 B.buildZExtOrTrunc(Ext, Inner);
7538 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7539 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7545 if (isZeroOrZeroSplat(True,
true)) {
7546 MatchInfo = [=](MachineIRBuilder &
B) {
7547 B.setInstrAndDebugLoc(*
Select);
7549 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7550 B.buildNot(Inner,
Cond);
7552 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7553 B.buildZExtOrTrunc(Ext, Inner);
7554 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7555 B.buildAnd(DstReg, Ext, FreezeFalse);
7571 LLT DstTy =
MRI.getType(DstReg);
7577 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7586 Register CmpLHS = Cmp->getLHSReg();
7587 Register CmpRHS = Cmp->getRHSReg();
7590 if (True == CmpRHS && False == CmpLHS) {
7598 if (True != CmpLHS || False != CmpRHS)
7638 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7639 Register DestReg =
MI.getOperand(0).getReg();
7640 LLT DestTy =
MRI.getType(DestReg);
7652 if (
isLegal({NewOpc, {DestTy}})) {
7654 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7666 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7669 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7679bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7681 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7682 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7686 unsigned Flags = Logic->
getFlags();
7699 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7705 std::optional<ValueAndVReg> MaybeC1 =
7709 C1 = MaybeC1->Value;
7711 std::optional<ValueAndVReg> MaybeC2 =
7715 C2 = MaybeC2->Value;
7722 LLT CmpOperandTy =
MRI.getType(R1);
7736 std::optional<APInt> Offset1;
7737 std::optional<APInt> Offset2;
7740 std::optional<ValueAndVReg> MaybeOffset1 =
7743 R1 =
Add->getLHSReg();
7744 Offset1 = MaybeOffset1->Value;
7748 std::optional<ValueAndVReg> MaybeOffset2 =
7751 R2 =
Add->getLHSReg();
7752 Offset2 = MaybeOffset2->Value;
7771 bool CreateMask =
false;
7784 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7797 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7806 MatchInfo = [=](MachineIRBuilder &
B) {
7807 if (CreateMask &&
Offset != 0) {
7808 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7809 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7810 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7811 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7812 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7813 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7814 B.buildZExtOrTrunc(DstReg, ICmp);
7815 }
else if (CreateMask &&
Offset == 0) {
7816 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7817 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7818 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7819 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7820 B.buildZExtOrTrunc(DstReg, ICmp);
7821 }
else if (!CreateMask &&
Offset != 0) {
7822 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7823 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7824 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7825 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7826 B.buildZExtOrTrunc(DstReg, ICmp);
7827 }
else if (!CreateMask &&
Offset == 0) {
7828 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7829 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7830 B.buildZExtOrTrunc(DstReg, ICmp);
7838bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7844 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7856 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7862 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7863 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7864 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7865 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7876 if (LHS0 == RHS1 && LHS1 == RHS0) {
7882 if (LHS0 == RHS0 && LHS1 == RHS1) {
7886 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7888 MatchInfo = [=](MachineIRBuilder &
B) {
7893 auto False =
B.buildConstant(CmpTy, 0);
7894 B.buildZExtOrTrunc(DestReg, False);
7901 B.buildZExtOrTrunc(DestReg, True);
7903 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7904 B.buildZExtOrTrunc(DestReg, Cmp);
7916 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7919 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7928 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7931 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7946 bool IsSigned =
Add->isSigned();
7947 LLT DstTy =
MRI.getType(Dst);
7948 LLT CarryTy =
MRI.getType(Carry);
7951 if (
MRI.use_nodbg_empty(Carry) &&
7954 B.buildAdd(Dst, LHS, RHS);
7955 B.buildUndef(Carry);
7961 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7964 B.buildSAddo(Dst, Carry, RHS, LHS);
7970 B.buildUAddo(Dst, Carry, RHS, LHS);
7975 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7976 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7982 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7983 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7985 B.buildConstant(Dst, Result);
7986 B.buildConstant(Carry, Overflow);
7994 B.buildCopy(Dst, LHS);
7995 B.buildConstant(Carry, 0);
8004 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
8007 std::optional<APInt> MaybeAddRHS =
8008 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
8011 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
8012 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8016 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8017 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8023 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8024 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8049 B.buildConstant(Carry, 0);
8056 B.buildAdd(Dst, LHS, RHS);
8057 B.buildConstant(Carry, 1);
8069 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8072 B.buildConstant(Carry, 0);
8088 B.buildConstant(Carry, 0);
8095 B.buildAdd(Dst, LHS, RHS);
8096 B.buildConstant(Carry, 1);
8114 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8120 auto [Dst,
Base] =
MI.getFirst2Regs();
8121 LLT Ty =
MRI.getType(Dst);
8125 Builder.buildFConstant(Dst, 1.0);
8126 MI.removeFromParent();
8138 std::optional<SrcOp> Res;
8140 while (ExpVal > 0) {
8145 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8148 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8155 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8159 MI.eraseFromParent();
8168 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8175 LLT DstTy =
MRI.getType(Dst);
8178 auto Const =
B.buildConstant(DstTy, C1 - C2);
8179 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8191 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8198 LLT DstTy =
MRI.getType(Dst);
8201 auto Const =
B.buildConstant(DstTy, C2 - C1);
8202 B.buildSub(Dst, Const,
Add->getLHSReg());
8214 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8221 LLT DstTy =
MRI.getType(Dst);
8224 auto Const =
B.buildConstant(DstTy, C1 + C2);
8237 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8244 LLT DstTy =
MRI.getType(Dst);
8247 auto Const =
B.buildConstant(DstTy, C1 - C2);
8260 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8267 LLT DstTy =
MRI.getType(Dst);
8270 auto Const =
B.buildConstant(DstTy, C2 - C1);
8271 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8318 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8322 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8325 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8326 LLT SmallBvTy = DstTy;
8330 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8335 {TargetOpcode::G_ANYEXT,
8347 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8348 Ops.push_back(AnyExt.getReg(0));
8366 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8367 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8368 const unsigned NumDstElts = OrigMask.
size();
8369 for (
unsigned i = 0; i != NumDstElts; ++i) {
8370 int Idx = OrigMask[i];
8371 if (Idx >= (
int)NumSrcElems) {
8382 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8383 std::move(NewMask));
8390 const unsigned MaskSize = Mask.size();
8391 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8396 if (Idx < (
int)NumElems)
8397 Mask[
I] = Idx + NumElems;
8399 Mask[
I] = Idx - NumElems;
8409 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8412 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8415 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8416 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8418 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8422 const unsigned NumSrcElems = Src1Ty.getNumElements();
8424 bool TouchesSrc1 =
false;
8425 bool TouchesSrc2 =
false;
8426 const unsigned NumElems = Mask.size();
8427 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8431 if (Mask[Idx] < (
int)NumSrcElems)
8437 if (TouchesSrc1 == TouchesSrc2)
8440 Register NewSrc1 = Shuffle.getSrc1Reg();
8443 NewSrc1 = Shuffle.getSrc2Reg();
8448 auto Undef =
B.buildUndef(Src1Ty);
8449 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1,
Undef, NewMask);
8463 LLT DstTy =
MRI.getType(Dst);
8464 LLT CarryTy =
MRI.getType(Carry);
8486 B.buildConstant(Carry, 0);
8493 B.buildSub(Dst, LHS, RHS);
8511 B.buildConstant(Carry, 0);
8518 B.buildSub(Dst, LHS, RHS);
8535 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8536 "Expected G_CTLZ variant");
8541 LLT Ty =
MRI.getType(Dst);
8542 LLT SrcTy =
MRI.getType(Src);
8544 if (!(Ty.isValid() && Ty.isScalar()))
8553 switch (
LI->getAction(Query).Action) {
8564 bool NeedAdd =
true;
8572 unsigned BitWidth = Ty.getScalarSizeInBits();
8583 B.buildCTLS(Dst,
X);
8587 auto Ctls =
B.buildCTLS(Ty,
X);
8588 auto One =
B.buildConstant(Ty, 1);
8590 B.buildAdd(Dst, Ctls, One);
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool hasMoreUses(const MachineInstr &MI0, const MachineInstr &MI1, const MachineRegisterInfo &MRI)
static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally)
Checks if MI is TargetOpcode::G_FMUL and contractable either due to global flags or MachineInstr flag...
static unsigned getIndexedOpc(unsigned LdStOpc)
static APFloat constantFoldFpUnary(const MachineInstr &MI, const MachineRegisterInfo &MRI, const APFloat &Val)
static std::optional< std::pair< GZExtLoad *, int64_t > > matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI)
Helper function for findLoadOffsetsForLoadOrCombine.
static std::optional< unsigned > getMinUselessShift(KnownBits ValueKB, unsigned Opcode, std::optional< int64_t > &Result)
Return the minimum useless shift amount that results in complete loss of the source value.
static Register peekThroughBitcast(Register Reg, const MachineRegisterInfo &MRI)
static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I)
static cl::opt< bool > ForceLegalIndexing("force-legal-indexing", cl::Hidden, cl::init(false), cl::desc("Force all indexed operations to be " "legal for the GlobalISel combiner"))
static void commuteMask(MutableArrayRef< int > Mask, const unsigned NumElems)
static cl::opt< unsigned > PostIndexUseThreshold("post-index-use-threshold", cl::Hidden, cl::init(32), cl::desc("Number of uses of a base pointer to check before it is no longer " "considered for post-indexing."))
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
static unsigned getExtLoadOpcForExtend(unsigned ExtOpc)
static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits, int64_t Cst, bool IsVector, bool IsFP)
static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy)
static bool canFoldInAddressingMode(GLoadStore *MI, const TargetLowering &TLI, MachineRegisterInfo &MRI)
Return true if 'MI' is a load or a store that may be fold it's address operand into the load / store ...
static unsigned littleEndianByteAt(const unsigned ByteWidth, const unsigned I)
static Register buildLogBase2(Register V, MachineIRBuilder &MIB)
Determines the LogBase2 value for a non-null input value using the transform: LogBase2(V) = (EltBits ...
This contains common combine transformations that may be used in a combine pass,or by the target else...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Interface for Targets to specify which operations they can successfully select and how the others sho...
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)
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file implements a set that has insertion order iteration characteristics.
This file implements the SmallBitVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
This file describes how to lower LLVM code to machine code.
static constexpr roundingMode rmTowardZero
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmTowardNegative
static constexpr roundingMode rmNearestTiesToEven
static constexpr roundingMode rmTowardPositive
static constexpr roundingMode rmNearestTiesToAway
const fltSemantics & getSemantics() const
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend, roundingMode RM)
APInt bitcastToAPInt() const
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
uint64_t getZExtValue() const
Get zero extended value.
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
int32_t exactLogBase2() const
void ashrInPlace(unsigned ShiftAmt)
Arithmetic right-shift this APInt by ShiftAmt in place.
unsigned countr_zero() const
Count the number of trailing zero bits.
unsigned countl_zero() const
The APInt version of std::countl_zero.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
bool isStrictlyPositive() const
Determine if this APInt Value is positive.
LLVM_ABI APInt multiplicativeInverse() const
bool isMask(unsigned numBits) const
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
bool isOne() const
Determine if this is a value of 1.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
int64_t getSExtValue() const
Get sign extended value.
void lshrInPlace(unsigned ShiftAmt)
Logical right-shift this APInt by ShiftAmt in place.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
unsigned countr_one() const
Count the number of trailing one bits.
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - 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.
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRepeatedFPDivisor(MachineInstr &MI, SmallVector< MachineInstr * > &MatchInfo) const
bool matchFoldC2MinusAPlusC1(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match expression trees of the form.
const RegisterBank * getRegBank(Register Reg) const
Get the register bank of Reg.
void applyPtrAddZero(MachineInstr &MI) const
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2) const
Return true if MOP1 and MOP2 are register operands are defined by equivalent instructions.
void applyUDivOrURemByConst(MachineInstr &MI) const
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
bool matchUnmergeValuesAnyExtBuildVector(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchCtls(MachineInstr &CtlzMI, BuildFnTy &MatchInfo) const
bool matchSelectSameVal(MachineInstr &MI) const
Optimize (cond ? x : x) -> x.
bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*ADDE x, y, 0) -> (G_*ADDO x, y) (G_*SUBE x, y, 0) -> (G_*SUBO x, y)
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width.
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
void applySimplifyURemByPow2(MachineInstr &MI) const
Combine G_UREM x, (known power of 2) to an add and bitmasking.
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI) const
Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0.
bool matchPtrAddZero(MachineInstr &MI) const
}
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.
void applyXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, bool &HasFMAD, bool &Aggressive, bool CanReassociate=false) const
bool matchFoldAPlusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
void applyCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
bool matchShiftsTooBig(MachineInstr &MI, std::optional< int64_t > &MatchInfo) const
Match shifts greater or equal to the range (the bitwidth of the result datatype, or the effective bit...
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) (fadd (fpext (fmul x,...
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
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.
void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement) const
Delete MI and replace all of its uses with Replacement.
void applyCombineShuffleToBuildVector(MachineInstr &MI) const
Replace MI with a build_vector.
bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed load.
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
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.
bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate commutative binary operations like G_ADD.
void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCommuteConstantToRHS(MachineInstr &MI) const
Match constant LHS ops that should be commuted.
const DataLayout & getDataLayout() const
bool matchBinOpSameVal(MachineInstr &MI) const
Optimize (x op x) -> x.
bool matchSimplifyNegMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
Tranform (neg (min/max x, (neg x))) into (max/min x, (neg x)).
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...
void applyUMulHToLShr(MachineInstr &MI) const
void applyNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
Fold (shift (shift base, x), y) -> (shift base (x+y))
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const
Return true if all register explicit use operands on MI are defined by a G_IMPLICIT_DEF.
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI precedes UseMI or they are the same instruction.
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool matchTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
const TargetLowering & getTargetLowering() const
bool matchShuffleUndefRHS(MachineInstr &MI, BuildFnTy &MatchInfo) const
Remove references to rhs if it is undef.
void applyBuildInstructionSteps(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Replace MI with a series of instructions described in MatchInfo.
void applySDivByPow2(MachineInstr &MI) const
void applySimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
void applyUDivByPow2(MachineInstr &MI) const
Given an G_UDIV MI expressing an unsigned divided by a pow2 constant, return expressions that impleme...
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ors.
bool matchLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo, MachineInstr &ShiftMI) const
Fold (lshr (trunc (lshr x, C1)), C2) -> trunc (shift x, (C1 + C2))
bool matchSimplifyAddToSub(MachineInstr &MI, std::tuple< Register, Register > &MatchInfo) const
Return true if MI is a G_ADD which can be simplified to a G_SUB.
void replaceInstWithConstant(MachineInstr &MI, int64_t C) const
Replace an instruction with a G_CONSTANT with value C.
bool tryEmitMemcpyInline(MachineInstr &MI) const
Emit loads and stores that perform the given memcpy.
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,...
void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx) const
Checks if constant at ConstIdx is larger than MI 's bitwidth.
void applyCombineCopy(MachineInstr &MI) const
bool matchAddSubSameReg(MachineInstr &MI, Register &Src) const
Transform G_ADD(x, G_SUB(y, x)) to y.
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData) const
void applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fmul x, y), z) -> (fma x, y, -z) (fsub (fmul x, y), z) -> (fmad x,...
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,...
bool matchSextTruncSextLoad(MachineInstr &MI) const
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo) const
Fold away a merge of an unmerge of the corresponding values.
bool matchCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, Register &UnmergeSrc) const
bool matchDivByPow2(MachineInstr &MI, bool IsSigned) const
Given an G_SDIV MI expressing a signed divided by a pow2 constant, return expressions that implements...
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd x, fneg(y)) -> (fsub x, y) (fadd fneg(x), y) -> (fsub y, x) (fsub x,...
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match (and (load x), mask) -> zextload x.
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fadd (fmul x, y), z) -> (fma x, y, z) (fadd (fmul x, y), z) -> (fmad x,...
bool matchCombineCopy(MachineInstr &MI) const
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo) const
bool matchXorOfAndWithSameReg(MachineInstr &MI, std::pair< Register, Register > &MatchInfo) const
Fold (xor (and x, y), y) -> (and (not x), y) {.
bool matchCombineShuffleVector(MachineInstr &MI, SmallVectorImpl< Register > &Ops) const
Check if the G_SHUFFLE_VECTOR MI can be replaced by a concat_vectors.
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair< Register, bool > &PtrRegAndCommute) const
Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) Transform G_ADD y,...
void replaceInstWithFConstant(MachineInstr &MI, double C) const
Replace an instruction with a G_FCONSTANT with value C.
bool matchFunnelShiftToRotate(MachineInstr &MI) const
Match an FSHL or FSHR that can be combined to a ROTR or ROTL rotate.
bool matchOrShiftToFunnelShift(MachineInstr &MI, bool AllowScalarConstants, BuildFnTy &MatchInfo) const
bool matchRedundantSExtInReg(MachineInstr &MI) const
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
void applyFunnelShiftConstantModulo(MachineInstr &MI) const
Replaces the shift amount in MI with ShiftAmt % BW.
bool matchFoldC1Minus2MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineShlOfExtend(MachineInstr &MI, const RegisterImmPair &MatchData) const
void applyUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchShuffleDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
Turn shuffle a, b, mask -> shuffle undef, b, mask iff mask does not reference a.
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
Transform a multiply by a power-of-2 value to a left shift.
void applyCombineShuffleVector(MachineInstr &MI, ArrayRef< Register > Ops) const
Replace MI with a concat_vectors with Ops.
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst) const
bool matchCombineUnmergeUndef(MachineInstr &MI, std::function< void(MachineIRBuilder &)> &MatchInfo) const
Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo) const
SelectOperand is the operand in binary operator MI that is the select to fold.
bool matchFoldAMinusC1MinusC2(const MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo) const
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_UMULO x, 2) -> (G_UADDO x, x) (G_SMULO x, 2) -> (G_SADDO x, x)
bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector< Register > &Ops) const
void applySextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
bool tryCombineCopy(MachineInstr &MI) const
If MI is COPY, try to combine it.
bool matchTruncUSatU(MachineInstr &MI, MachineInstr &MinMI) const
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Reassociate pointer calculations with G_ADD involved, to allow better addressing mode usage.
bool isPreLegalize() const
bool matchUndefShuffleVectorMask(MachineInstr &MI) const
Return true if a G_SHUFFLE_VECTOR instruction MI has an undef mask.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const
Return true if any explicit use operand on MI is defined by a G_IMPLICIT_DEF.
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg) const
Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
bool matchCombineSubToAdd(MachineInstr &MI, BuildFnTy &MatchInfo) const
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...
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is known to be a power of 2.
bool matchCombineConcatVectors(MachineInstr &MI, SmallVector< Register > &Ops) const
If MI is G_CONCAT_VECTORS, try to combine it.
bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) const
Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index.
bool matchExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
LLVMContext & getContext() const
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl< Register > &RegsToNegate) const
Combine inverting a result of a compare into the opposite cond code.
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple< Register, unsigned > &MatchInfo) const
Match sext_inreg(load p), imm -> sextload p.
bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine select to integer min/max.
void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst) const
Transform fp_instr(cst) to constant result of the fp operation.
bool isLegal(const LegalityQuery &Query) const
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo) const
bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, Register Op1, BuildFnTy &MatchInfo) const
Try to reassociate to reassociate operands of a commutative binop.
void eraseInst(MachineInstr &MI) const
Erase MI.
bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP *&MatchInfo) const
Do constant FP folding when opportunities are exposed after MIR building.
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchUseVectorTruncate(MachineInstr &MI, Register &MatchInfo) const
bool matchUndefStore(MachineInstr &MI) const
Return true if a G_STORE instruction MI is storing an undef value.
MachineRegisterInfo & MRI
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) const
Transform PtrToInt(IntToPtr(x)) to x.
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI) const
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.
MachineInstr * buildUDivOrURemUsingMul(MachineInstr &MI) const
Given an G_UDIV MI or G_UREM MI expressing a divide by constant, return an expression that implements...
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg) const
bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo) const
Push a binary operator through a select on constants.
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount) const
bool tryCombineExtendingLoads(MachineInstr &MI) const
If MI is extend that consumes the result of a load, try to combine it.
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo) const
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: shr (and x, n), k -> ubfx x, pos, width.
void applyTruncSSatS(MachineInstr &MI, Register &MatchInfo) const
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const
Do constant folding when opportunities are exposed after MIR building.
bool tryCombineShuffleVector(MachineInstr &MI) const
Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
void applyRotateOutOfRange(MachineInstr &MI) const
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, InstructionStepsMatchInfo &MatchInfo) const
Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: and (lshr x, cst), mask -> ubfx x, cst, width.
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool matchUndefSelectCmp(MachineInstr &MI) const
Return true if a G_SELECT instruction MI has an undef comparison.
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const
void replaceInstWithUndef(MachineInstr &MI) const
Replace an instruction with a G_IMPLICIT_DEF.
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) !...
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...
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine addos.
void applyAshShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine selects.
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo) const
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) const
Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) const
bool matchRotateOutOfRange(MachineInstr &MI) const
void applyExpandFPowI(MachineInstr &MI, int64_t Exponent) const
Expands FPOWI into a series of multiplications and a division if the exponent is negative.
void setRegBank(Register Reg, const RegisterBank *RegBank) const
Set the register bank of Reg.
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) const
Return true if a G_SELECT instruction MI has a constant comparison.
bool matchCommuteFPConstantToRHS(MachineInstr &MI) const
Match constant LHS FP ops that should be commuted.
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI) const
bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info) const
bool matchRedundantOr(MachineInstr &MI, Register &Replacement) const
void applyTruncSSatU(MachineInstr &MI, Register &MatchInfo) const
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fpext (fneg (fmul x, y))), z) -> (fneg (fma (fpext x), (fpext y),...
bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo) const
void applyCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
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.
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal) const
void applyCombineBuildUnmerge(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, Register &UnmergeSrc) const
bool matchUMulHToLShr(MachineInstr &MI) const
MachineDominatorTree * MDT
void applyFunnelShiftToRotate(MachineInstr &MI) const
bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applyRepeatedFPDivisor(SmallVector< MachineInstr * > &MatchInfo) const
bool matchTruncUSatUToFPTOUISat(MachineInstr &MI, MachineInstr &SrcMI) const
const RegisterBankInfo * RBI
bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) const
Match: (G_*MULO x, 0) -> 0 + no carry out.
bool matchCombineUnmergeConstant(MachineInstr &MI, SmallVectorImpl< APInt > &Csts) const
Transform G_UNMERGE Constant -> Constant1, Constant2, ...
void applyShiftOfShiftedLogic(MachineInstr &MI, ShiftOfShiftedLogic &MatchInfo) const
const TargetRegisterInfo * TRI
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement) const
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI) const
Returns true if DefMI dominates UseMI.
GISelChangeObserver & Observer
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo) const
Use a function which takes in a MachineIRBuilder to perform a combine.
bool matchCombineTruncOfShift(MachineInstr &MI, std::pair< MachineInstr *, LLT > &MatchInfo) const
Transform trunc (shl x, K) to shl (trunc x), K if K < VT.getScalarSizeInBits().
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.
bool matchUDivOrURemByConst(MachineInstr &MI) const
Combine G_UDIV or G_UREM by constant into a multiply by magic constant.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Combine ands.
bool matchSuboCarryOut(const MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo) const
Constant fold G_FMA/G_FMAD.
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) (fsub (fneg (fmul,...
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg) const
Transform zext(trunc(x)) to x.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is undef.
void applyLshrOfTruncOfLshr(MachineInstr &MI, LshrOfTruncOfLshr &MatchInfo) const
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0) const
Optimize memcpy intrinsics et al, e.g.
bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, BuildFnTy &MatchInfo) const
void applySDivOrSRemByConst(MachineInstr &MI) const
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...
bool isLegalOrHasWidenScalar(const LegalityQuery &Query) const
bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo) const
Transform: (x + y) - y -> x (x + y) - x -> y x - (y + x) -> 0 - y x - (x + z) -> 0 - z.
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, MachineInstr *RHS, BuildFnTy &MatchInfo) const
bool matchOverlappingAnd(MachineInstr &MI, BuildFnTy &MatchInfo) const
Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) const
Transform anyext(trunc(x)) to x.
void applyExtractAllEltsFromBuildVector(MachineInstr &MI, SmallVectorImpl< std::pair< Register, MachineInstr * > > &MatchInfo) const
MachineIRBuilder & Builder
void applyCommuteBinOpOperands(MachineInstr &MI) const
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const
Delete MI and replace all of its uses with its OpIdx-th operand.
void applySextTruncSextLoad(MachineInstr &MI) const
const MachineFunction & getMachineFunction() const
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, BuildFnTy &MatchInfo) const
bool matchSDivOrSRemByConst(MachineInstr &MI) const
Combine G_SDIV or G_SREM by constant into a multiply by magic constant.
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond) const
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal) const
bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent) const
Match FPOWI if it's safe to extend it into a series of multiplications.
void applyCombineInsertVecElts(MachineInstr &MI, SmallVectorImpl< Register > &MatchInfo) const
bool matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
void applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, SmallVectorImpl< Register > &Operands) const
bool matchAshrShlToSextInreg(MachineInstr &MI, std::tuple< Register, int64_t > &MatchInfo) const
Match ashr (shl x, C), C -> sext_inreg (C)
void applyCombineUnmergeZExtToZExt(MachineInstr &MI) const
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
This class represents a range of values.
LLVM_ABI std::optional< ConstantRange > exactUnionWith(const ConstantRange &CR) const
Union the two ranges and return the result if it can be represented exactly, otherwise return std::nu...
LLVM_ABI ConstantRange subtract(const APInt &CI) const
Subtract the specified constant from the endpoints of this constant range.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
const APInt & getLower() const
Return the lower value for this range.
LLVM_ABI OverflowResult unsignedSubMayOverflow(const ConstantRange &Other) const
Return whether unsigned sub of the two ranges always/never overflows.
LLVM_ABI OverflowResult unsignedAddMayOverflow(const ConstantRange &Other) const
Return whether unsigned add of the two ranges always/never overflows.
LLVM_ABI bool isWrappedSet() const
Return true if this set wraps around the unsigned domain.
const APInt & getUpper() const
Return the upper value for this range.
static LLVM_ABI ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &Other)
Produce the exact range such that all values in the returned range satisfy the given predicate with a...
LLVM_ABI OverflowResult signedAddMayOverflow(const ConstantRange &Other) const
Return whether signed add of the two ranges always/never overflows.
@ NeverOverflows
Never overflows.
@ AlwaysOverflowsHigh
Always overflows in the direction of signed/unsigned max value.
@ AlwaysOverflowsLow
Always overflows in the direction of signed/unsigned min value.
@ MayOverflow
May or may not overflow.
LLVM_ABI OverflowResult signedSubMayOverflow(const ConstantRange &Other) const
Return whether signed sub of the two ranges always/never overflows.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Represents overflowing add operations.
Represents an integer addition.
Represents a logical and.
CmpInst::Predicate getCond() const
Register getLHSReg() const
Register getRHSReg() const
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getCarryOutReg() const
Register getRHSReg() const
Register getLHSReg() const
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
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.
bool isSimple() const
Returns true if the memory operation is neither atomic or volatile.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_MERGE_VALUES.
Register getCondReg() const
Represents overflowing sub operations.
Represents an integer subtraction.
Represents a G_UNMERGE_VALUES.
unsigned getNumDefs() const
Returns the number of def registers.
Register getSourceReg() const
Get the unmerge source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
constexpr bool isScalableVector() const
Returns true if the LLT is a scalable vector.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr bool isByteSized() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
constexpr ElementCount getElementCount() const
constexpr 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.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr LLT getScalarType() const
This is an important class for using LLVM in a threaded context.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen=0)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
TypeSize getValue() const
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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.
Helper class to build MachineInstr.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildCTLZ(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_CTLZ Op0, Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
const MachineBasicBlock * getParent() const
LLVM_ABI bool isDereferenceableInvariantLoad() const
Return true if this load instruction never traps and points to a memory location whose value doesn't ...
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
mop_range uses()
Returns all operands which may be register uses.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
unsigned getAddrSpace() const
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
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.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
bool all() const
Returns true if all bits are set.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual bool isTruncateFree(Type *FromTy, Type *ToTy) const
Return true if it's free to truncate a value of type FromTy to type ToTy.
virtual LLVM_READONLY LLT getPreferredShiftAmountTy(LLT ShiftValueTy) const
Return the preferred type to use for a shift opcode, given the shifted amount type is ShiftValueTy.
bool isBeneficialToExpandPowI(int64_t Exponent, bool OptForSize) const
Return true if it is beneficial to expand an @llvm.powi.
virtual bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AddrSpace, Instruction *I=nullptr) const
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual unsigned combineRepeatedFPDivisors() const
Indicate whether this target prefers to combine FDIVs with the same divisor.
virtual const TargetLowering * getTargetLowering() const
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
@ 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.
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
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< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
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.
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)
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)
class_match< BinaryOperator > m_BinOp()
Match an arbitrary binary operation and ignore it.
Not(const Pred &P) -> Not< Pred >
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
LLVM_ABI bool isBuildVectorAllZeros(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndef=false)
Return true if the specified instruction is a G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all of the...
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
static double log2(double V)
LLVM_ABI 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...
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
LLVM_ABI bool isNullOrNullSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowUndefs=false)
Return true if the value is a constant 0 integer or a splatted vector of a constant 0 integer (with n...
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
LLVM_ABI bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, bool IsFP)
Returns true if given the TargetLowering's boolean contents information, the value Val contains a tru...
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
constexpr bool has_single_bit(T Value) noexcept
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
LLVM_ABI bool isConstantOrConstantVector(const MachineInstr &MI, const MachineRegisterInfo &MRI, bool AllowFP=true, bool AllowOpaqueConstants=true)
Return true if the specified instruction is known to be a constant, or a vector of constants.
SmallVector< std::function< void(MachineInstrBuilder &)>, 4 > OperandBuildSteps
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
LLVM_ABI bool canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlagsAndMetadata=true)
canCreateUndefOrPoison returns true if Op can create undef or poison from non-undef & non-poison oper...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto instructionsWithoutDebug(IterT It, IterT End, bool SkipPseudoOp=true)
Construct a range iterator which begins at It and moves forwards until End is reached,...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
LLVM_ABI std::optional< APInt > ConstantFoldCastOp(unsigned Opcode, LLT DstTy, const Register Op0, const MachineRegisterInfo &MRI)
LLVM_ABI unsigned getInverseGMinMaxOpcode(unsigned MinMaxOpc)
Returns the inverse opcode of MinMaxOpc, which is a generic min/max opcode like G_SMIN.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
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...
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a float constant integer or a splat vector of float constant integers.
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 bool isKnownNeverNaN(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if the floating-point scalar value is not a NaN or if the floating-point vector value has...
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 bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL, bool OrZero=false, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return true if the given value is known to have exactly one bit set when defined.
LLVM_ABI Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the source register for Reg, folding away any trivial copies.
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
unsigned getFCmpCode(CmpInst::Predicate CC)
Similar to getICmpCode but for FCmpInst.
LLVM_ABI std::optional< int64_t > getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Simple struct used to hold a Register value and the instruction which defines it.
SmallVector< InstructionBuildSteps, 2 > InstrsToBuild
Describes instructions to be built during a combine.
bool isNonNegative() const
Returns true if this value is known to be non-negative.
unsigned countMinLeadingOnes() const
Returns the minimum number of leading one bits.
unsigned countMinTrailingZeros() const
Returns the minimum number of trailing zero bits.
bool isUnknown() const
Returns true if we don't know any bits.
unsigned getBitWidth() const
Get the bit width of this value.
unsigned countMinLeadingZeros() const
Returns the minimum number of leading zero bits.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
bool isNegative() const
Returns true if this value is known to be negative.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
This class contains a discriminated union of information about pointers in memory operands,...
LLVM_ABI unsigned getAddrSpace() const
Return the LLVM IR address space number that this pointer points into.
MachinePointerInfo getWithOffset(int64_t O) const
const RegisterBank * Bank
Register LogicNonShiftReg
Magic data for optimising signed division by a constant.
unsigned ShiftAmount
shift amount
static LLVM_ABI SignedDivisionByConstantInfo get(const APInt &D)
Calculate the magic numbers required to implement a signed integer division by a constant as a sequen...
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
Magic data for optimising unsigned division by a constant.
unsigned PreShift
pre-shift amount
static LLVM_ABI UnsignedDivisionByConstantInfo get(const APInt &D, unsigned LeadingZeros=0, bool AllowEvenDivisorOptimization=true)
Calculate the magic numbers required to implement an unsigned integer division by a constant as a seq...
unsigned PostShift
post-shift amount