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);
344 Undef =
Builder.buildUndef(OpType.getScalarType());
346 assert(
MRI.getType(Undef->getOperand(0).getReg()) ==
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_FPEXT:
1685 case TargetOpcode::G_FPTRUNC: {
1687 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
1692 case TargetOpcode::G_FSQRT: {
1696 Result =
APFloat(sqrt(Result.convertToDouble()));
1699 case TargetOpcode::G_FLOG2: {
1719 Builder.buildFConstant(
MI.getOperand(0), *NewCst);
1720 MI.eraseFromParent();
1731 if (
MI.getOpcode() != TargetOpcode::G_PTR_ADD)
1741 if (!Add2Def || Add2Def->
getOpcode() != TargetOpcode::G_PTR_ADD)
1754 Type *AccessTy =
nullptr;
1755 auto &MF = *
MI.getMF();
1756 for (
auto &
UseMI :
MRI.use_nodbg_instructions(
MI.getOperand(0).getReg())) {
1759 MF.getFunction().getContext());
1764 APInt CombinedImm = MaybeImmVal->Value + MaybeImm2Val->Value;
1769 AMOld.
BaseOffs = MaybeImmVal->Value.getSExtValue();
1771 unsigned AS =
MRI.getType(Add2).getAddressSpace();
1772 const auto &TLI = *MF.getSubtarget().getTargetLowering();
1773 if (TLI.isLegalAddressingMode(MF.getDataLayout(), AMOld, AccessTy, AS) &&
1774 !TLI.isLegalAddressingMode(MF.getDataLayout(), AMNew, AccessTy, AS))
1783 unsigned PtrAddFlags =
MI.getFlags();
1784 unsigned LHSPtrAddFlags = Add2Def->
getFlags();
1800 MatchInfo.
Flags = Flags;
1806 assert(
MI.getOpcode() == TargetOpcode::G_PTR_ADD &&
"Expected G_PTR_ADD");
1808 LLT OffsetTy =
MRI.getType(
MI.getOperand(2).getReg());
1812 MI.getOperand(1).setReg(MatchInfo.
Base);
1813 MI.getOperand(2).setReg(NewOffset.getReg(0));
1827 unsigned Opcode =
MI.getOpcode();
1828 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1829 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1830 Opcode == TargetOpcode::G_USHLSAT) &&
1831 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1851 (MaybeImmVal->Value.getZExtValue() + MaybeImm2Val->Value).getZExtValue();
1856 if (Opcode == TargetOpcode::G_USHLSAT &&
1857 MatchInfo.
Imm >=
MRI.getType(Shl2).getScalarSizeInBits())
1865 unsigned Opcode =
MI.getOpcode();
1866 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1867 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_SSHLSAT ||
1868 Opcode == TargetOpcode::G_USHLSAT) &&
1869 "Expected G_SHL, G_ASHR, G_LSHR, G_SSHLSAT or G_USHLSAT");
1871 LLT Ty =
MRI.getType(
MI.getOperand(1).getReg());
1872 unsigned const ScalarSizeInBits = Ty.getScalarSizeInBits();
1873 auto Imm = MatchInfo.
Imm;
1875 if (Imm >= ScalarSizeInBits) {
1877 if (Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR) {
1878 Builder.buildConstant(
MI.getOperand(0), 0);
1879 MI.eraseFromParent();
1884 Imm = ScalarSizeInBits - 1;
1887 LLT ImmTy =
MRI.getType(
MI.getOperand(2).getReg());
1890 MI.getOperand(1).setReg(MatchInfo.
Reg);
1891 MI.getOperand(2).setReg(NewImm);
1907 unsigned ShiftOpcode =
MI.getOpcode();
1908 assert((ShiftOpcode == TargetOpcode::G_SHL ||
1909 ShiftOpcode == TargetOpcode::G_ASHR ||
1910 ShiftOpcode == TargetOpcode::G_LSHR ||
1911 ShiftOpcode == TargetOpcode::G_USHLSAT ||
1912 ShiftOpcode == TargetOpcode::G_SSHLSAT) &&
1913 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1916 Register LogicDest =
MI.getOperand(1).getReg();
1917 if (!
MRI.hasOneNonDBGUse(LogicDest))
1921 unsigned LogicOpcode = LogicMI->
getOpcode();
1922 if (LogicOpcode != TargetOpcode::G_AND && LogicOpcode != TargetOpcode::G_OR &&
1923 LogicOpcode != TargetOpcode::G_XOR)
1927 const Register C1 =
MI.getOperand(2).getReg();
1929 if (!MaybeImmVal || MaybeImmVal->Value == 0)
1932 const uint64_t C1Val = MaybeImmVal->Value.getZExtValue();
1936 if (
MI->getOpcode() != ShiftOpcode ||
1937 !
MRI.hasOneNonDBGUse(
MI->getOperand(0).getReg()))
1946 ShiftVal = MaybeImmVal->Value.getSExtValue();
1957 if (matchFirstShift(LogicMIOp1, C0Val)) {
1959 MatchInfo.
Shift2 = LogicMIOp1;
1960 }
else if (matchFirstShift(LogicMIOp2, C0Val)) {
1962 MatchInfo.
Shift2 = LogicMIOp2;
1966 MatchInfo.
ValSum = C0Val + C1Val;
1969 if (MatchInfo.
ValSum >=
MRI.getType(LogicDest).getScalarSizeInBits())
1972 MatchInfo.
Logic = LogicMI;
1978 unsigned Opcode =
MI.getOpcode();
1979 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_ASHR ||
1980 Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_USHLSAT ||
1981 Opcode == TargetOpcode::G_SSHLSAT) &&
1982 "Expected G_SHL, G_ASHR, G_LSHR, G_USHLSAT and G_SSHLSAT");
1984 LLT ShlType =
MRI.getType(
MI.getOperand(2).getReg());
1985 LLT DestType =
MRI.getType(
MI.getOperand(0).getReg());
1991 Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).
getReg(0);
2000 Register Shift2Const =
MI.getOperand(2).getReg();
2002 .buildInstr(Opcode, {DestType},
2012 MI.eraseFromParent();
2017 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
"Expected G_SHL");
2039 auto *SrcDef =
MRI.getVRegDef(SrcReg);
2040 assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
2041 SrcDef->getOpcode() == TargetOpcode::G_OR) &&
"Unexpected op");
2042 LLT SrcTy =
MRI.getType(SrcReg);
2044 auto S1 =
B.buildShl(SrcTy,
X, ShiftReg);
2045 auto S2 =
B.buildShl(SrcTy, C1, ShiftReg);
2046 B.buildInstr(SrcDef->getOpcode(), {DstReg}, {S1, S2});
2054 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2058 unsigned OpSizeInBits =
MRI.getType(N0).getScalarSizeInBits();
2073 LLT InnerShiftTy =
MRI.getType(InnerShift);
2075 if ((N1C + N001C).ult(InnerShiftSize)) {
2081 if ((N001C + OpSizeInBits) == InnerShiftSize)
2083 if (
MRI.hasOneUse(N0) &&
MRI.hasOneUse(InnerShift)) {
2084 MatchInfo.
Mask =
true;
2094 assert(
MI.getOpcode() == TargetOpcode::G_LSHR &&
"Expected a G_LSHR");
2101 if (MatchInfo.
Mask ==
true) {
2109 Builder.buildTrunc(Dst, Shift);
2110 MI.eraseFromParent();
2114 unsigned &ShiftVal)
const {
2115 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2121 ShiftVal = MaybeImmVal->Value.exactLogBase2();
2122 return (
static_cast<int32_t
>(ShiftVal) != -1);
2126 unsigned &ShiftVal)
const {
2127 assert(
MI.getOpcode() == TargetOpcode::G_MUL &&
"Expected a G_MUL");
2129 LLT ShiftTy =
MRI.getType(
MI.getOperand(0).getReg());
2132 MI.setDesc(MIB.
getTII().
get(TargetOpcode::G_SHL));
2133 MI.getOperand(2).setReg(ShiftCst.getReg(0));
2154 auto NegCst =
B.buildConstant(Ty, -Imm);
2156 MI.setDesc(
B.getTII().get(TargetOpcode::G_ADD));
2157 MI.getOperand(2).setReg(NegCst.getReg(0));
2159 if (Imm.isMinSignedValue())
2169 assert(
MI.getOpcode() == TargetOpcode::G_SHL &&
VT);
2184 if (!MaybeShiftAmtVal)
2188 LLT SrcTy =
MRI.getType(ExtSrc);
2198 int64_t ShiftAmt = MaybeShiftAmtVal->getSExtValue();
2199 MatchData.
Reg = ExtSrc;
2200 MatchData.
Imm = ShiftAmt;
2202 unsigned MinLeadingZeros =
VT->getKnownZeroes(ExtSrc).countl_one();
2203 unsigned SrcTySize =
MRI.getType(ExtSrc).getScalarSizeInBits();
2204 return MinLeadingZeros >= ShiftAmt && ShiftAmt < SrcTySize;
2210 int64_t ShiftAmtVal = MatchData.
Imm;
2212 LLT ExtSrcTy =
MRI.getType(ExtSrcReg);
2213 auto ShiftAmt =
Builder.buildConstant(ExtSrcTy, ShiftAmtVal);
2215 Builder.buildShl(ExtSrcTy, ExtSrcReg, ShiftAmt,
MI.getFlags());
2216 Builder.buildZExt(
MI.getOperand(0), NarrowShift);
2217 MI.eraseFromParent();
2224 for (
unsigned I = 0;
I <
Merge.getNumSources(); ++
I)
2228 if (!Unmerge || Unmerge->getNumDefs() !=
Merge.getNumSources())
2231 for (
unsigned I = 0;
I < MergedValues.
size(); ++
I)
2232 if (MergedValues[
I] != Unmerge->getReg(
I))
2235 MatchInfo = Unmerge->getSourceReg();
2249 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2250 "Expected an unmerge");
2259 LLT SrcMergeTy =
MRI.getType(SrcInstr->getSourceReg(0));
2260 LLT Dst0Ty =
MRI.getType(Unmerge.getReg(0));
2262 if (SrcMergeTy != Dst0Ty && !SameSize)
2266 for (
unsigned Idx = 0; Idx < SrcInstr->getNumSources(); ++Idx)
2267 Operands.
push_back(SrcInstr->getSourceReg(Idx));
2273 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2274 "Expected an unmerge");
2276 "Not enough operands to replace all defs");
2277 unsigned NumElems =
MI.getNumOperands() - 1;
2279 LLT SrcTy =
MRI.getType(Operands[0]);
2280 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2281 bool CanReuseInputDirectly = DstTy == SrcTy;
2282 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2283 Register DstReg =
MI.getOperand(Idx).getReg();
2288 const auto &DstCB =
MRI.getRegClassOrRegBank(DstReg);
2289 if (!DstCB.isNull() && DstCB !=
MRI.getRegClassOrRegBank(SrcReg)) {
2290 SrcReg =
Builder.buildCopy(
MRI.getType(SrcReg), SrcReg).getReg(0);
2291 MRI.setRegClassOrRegBank(SrcReg, DstCB);
2294 if (CanReuseInputDirectly)
2297 Builder.buildCast(DstReg, SrcReg);
2299 MI.eraseFromParent();
2304 unsigned SrcIdx =
MI.getNumOperands() - 1;
2305 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2307 if (SrcInstr->
getOpcode() != TargetOpcode::G_CONSTANT &&
2308 SrcInstr->
getOpcode() != TargetOpcode::G_FCONSTANT)
2316 LLT Dst0Ty =
MRI.getType(
MI.getOperand(0).getReg());
2319 for (
unsigned Idx = 0; Idx != SrcIdx; ++Idx) {
2321 Val = Val.
lshr(ShiftAmt);
2329 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2330 "Expected an unmerge");
2332 "Not enough operands to replace all defs");
2333 unsigned NumElems =
MI.getNumOperands() - 1;
2334 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2335 Register DstReg =
MI.getOperand(Idx).getReg();
2336 Builder.buildConstant(DstReg, Csts[Idx]);
2339 MI.eraseFromParent();
2345 unsigned SrcIdx =
MI.getNumOperands() - 1;
2346 Register SrcReg =
MI.getOperand(SrcIdx).getReg();
2348 unsigned NumElems =
MI.getNumOperands() - 1;
2349 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
2350 Register DstReg =
MI.getOperand(Idx).getReg();
2351 B.buildUndef(DstReg);
2359 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2360 "Expected an unmerge");
2361 if (
MRI.getType(
MI.getOperand(0).getReg()).isVector() ||
2362 MRI.getType(
MI.getOperand(
MI.getNumDefs()).getReg()).isVector())
2365 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2366 if (!
MRI.use_nodbg_empty(
MI.getOperand(Idx).getReg()))
2374 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2375 Register Dst0Reg =
MI.getOperand(0).getReg();
2376 Builder.buildTrunc(Dst0Reg, SrcReg);
2377 MI.eraseFromParent();
2381 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2382 "Expected an unmerge");
2383 Register Dst0Reg =
MI.getOperand(0).getReg();
2384 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2390 Register SrcReg =
MI.getOperand(
MI.getNumDefs()).getReg();
2391 LLT SrcTy =
MRI.getType(SrcReg);
2392 if (SrcTy.isVector())
2402 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2407 assert(
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
2408 "Expected an unmerge");
2410 Register Dst0Reg =
MI.getOperand(0).getReg();
2413 MRI.getVRegDef(
MI.getOperand(
MI.getNumDefs()).getReg());
2415 "Expecting a G_ZEXT");
2418 LLT Dst0Ty =
MRI.getType(Dst0Reg);
2419 LLT ZExtSrcTy =
MRI.getType(ZExtSrcReg);
2422 Builder.buildZExt(Dst0Reg, ZExtSrcReg);
2425 "ZExt src doesn't fit in destination");
2430 for (
unsigned Idx = 1, EndIdx =
MI.getNumDefs(); Idx != EndIdx; ++Idx) {
2432 ZeroReg =
Builder.buildConstant(Dst0Ty, 0).getReg(0);
2435 MI.eraseFromParent();
2439 unsigned TargetShiftSize,
2440 unsigned &ShiftVal)
const {
2441 assert((
MI.getOpcode() == TargetOpcode::G_SHL ||
2442 MI.getOpcode() == TargetOpcode::G_LSHR ||
2443 MI.getOpcode() == TargetOpcode::G_ASHR) &&
"Expected a shift");
2445 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
2450 unsigned Size = Ty.getSizeInBits();
2451 if (
Size <= TargetShiftSize)
2459 ShiftVal = MaybeImmVal->Value.getSExtValue();
2460 return ShiftVal >=
Size / 2 && ShiftVal <
Size;
2467 LLT Ty =
MRI.getType(SrcReg);
2468 unsigned Size = Ty.getSizeInBits();
2469 unsigned HalfSize =
Size / 2;
2470 assert(ShiftVal >= HalfSize);
2474 auto Unmerge =
Builder.buildUnmerge(HalfTy, SrcReg);
2475 unsigned NarrowShiftAmt = ShiftVal - HalfSize;
2477 if (
MI.getOpcode() == TargetOpcode::G_LSHR) {
2478 Register Narrowed = Unmerge.getReg(1);
2485 if (NarrowShiftAmt != 0) {
2486 Narrowed =
Builder.buildLShr(HalfTy, Narrowed,
2487 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2490 auto Zero =
Builder.buildConstant(HalfTy, 0);
2491 Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero});
2492 }
else if (
MI.getOpcode() == TargetOpcode::G_SHL) {
2493 Register Narrowed = Unmerge.getReg(0);
2498 if (NarrowShiftAmt != 0) {
2499 Narrowed =
Builder.buildShl(HalfTy, Narrowed,
2500 Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
2503 auto Zero =
Builder.buildConstant(HalfTy, 0);
2504 Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
2506 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
2508 HalfTy, Unmerge.getReg(1),
2509 Builder.buildConstant(HalfTy, HalfSize - 1));
2511 if (ShiftVal == HalfSize) {
2514 Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1),
Hi});
2515 }
else if (ShiftVal ==
Size - 1) {
2523 HalfTy, Unmerge.getReg(1),
2524 Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
2532 MI.eraseFromParent();
2548 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2550 LLT DstTy =
MRI.getType(DstReg);
2558 assert(
MI.getOpcode() == TargetOpcode::G_INTTOPTR &&
"Expected a G_INTTOPTR");
2560 Builder.buildCopy(DstReg, Reg);
2561 MI.eraseFromParent();
2566 assert(
MI.getOpcode() == TargetOpcode::G_PTRTOINT &&
"Expected a G_PTRTOINT");
2568 Builder.buildZExtOrTrunc(DstReg, Reg);
2569 MI.eraseFromParent();
2574 assert(
MI.getOpcode() == TargetOpcode::G_ADD);
2577 LLT IntTy =
MRI.getType(LHS);
2581 PtrReg.second =
false;
2582 for (
Register SrcReg : {LHS, RHS}) {
2586 LLT PtrTy =
MRI.getType(PtrReg.first);
2591 PtrReg.second =
true;
2603 const bool DoCommute = PtrReg.second;
2608 LLT PtrTy =
MRI.getType(LHS);
2610 auto PtrAdd =
Builder.buildPtrAdd(PtrTy, LHS, RHS);
2611 Builder.buildPtrToInt(Dst, PtrAdd);
2612 MI.eraseFromParent();
2616 APInt &NewCst)
const {
2618 Register LHS = PtrAdd.getBaseReg();
2619 Register RHS = PtrAdd.getOffsetReg();
2625 auto DstTy =
MRI.getType(PtrAdd.getReg(0));
2628 NewCst += RHSCst->
sextOrTrunc(DstTy.getSizeInBits());
2637 APInt &NewCst)
const {
2641 Builder.buildConstant(Dst, NewCst);
2642 PtrAdd.eraseFromParent();
2647 assert(
MI.getOpcode() == TargetOpcode::G_ANYEXT &&
"Expected a G_ANYEXT");
2652 SrcReg = OriginalSrcReg;
2653 LLT DstTy =
MRI.getType(DstReg);
2661 assert(
MI.getOpcode() == TargetOpcode::G_ZEXT &&
"Expected a G_ZEXT");
2664 LLT DstTy =
MRI.getType(DstReg);
2669 unsigned SrcSize =
MRI.getType(SrcReg).getScalarSizeInBits();
2670 return VT->getKnownBits(Reg).countMinLeadingZeros() >= DstSize - SrcSize;
2680 if (ShiftSize > 32 && TruncSize < 32)
2693 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2694 assert(
MI.getOpcode() == TargetOpcode::G_TRUNC &&
"Expected a G_TRUNC");
2698 if (!
MRI.hasOneNonDBGUse(SrcReg))
2701 LLT SrcTy =
MRI.getType(SrcReg);
2702 LLT DstTy =
MRI.getType(DstReg);
2711 case TargetOpcode::G_SHL: {
2720 case TargetOpcode::G_LSHR:
2721 case TargetOpcode::G_ASHR: {
2727 for (
auto &
User :
MRI.use_instructions(DstReg))
2728 if (
User.getOpcode() == TargetOpcode::G_STORE)
2732 if (NewShiftTy == SrcTy)
2746 {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}}))
2749 MatchInfo = std::make_pair(SrcMI, NewShiftTy);
2754 MachineInstr &
MI, std::pair<MachineInstr *, LLT> &MatchInfo)
const {
2756 LLT NewShiftTy = MatchInfo.second;
2759 LLT DstTy =
MRI.getType(Dst);
2763 ShiftSrc =
Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0);
2767 .buildInstr(ShiftMI->
getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt})
2770 if (NewShiftTy == DstTy)
2773 Builder.buildTrunc(Dst, NewShift);
2780 return MO.isReg() &&
2781 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2787 return !MO.isReg() ||
2788 getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
2793 assert(
MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
2795 return all_of(Mask, [](
int Elt) {
return Elt < 0; });
2799 assert(
MI.getOpcode() == TargetOpcode::G_STORE);
2800 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(0).getReg(),
2805 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
2806 return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
MI.getOperand(1).getReg(),
2812 assert((
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT ||
2813 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) &&
2814 "Expected an insert/extract element op");
2815 LLT VecTy =
MRI.getType(
MI.getOperand(1).getReg());
2820 MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
2828 unsigned &
OpIdx)
const {
2834 OpIdx = Cst->isZero() ? 3 : 2;
2879 if (I1->mayLoadOrStore() && !I1->isDereferenceableInvariantLoad())
2906 return MO.isReg() && MO.getReg().isPhysical();
2916 return I1->isIdenticalTo(*I2);
2924 if (
Builder.getTII().produceSameValue(*I1, *I2, &
MRI)) {
2931 return I1->findRegisterDefOperandIdx(InstAndDef1->Reg,
nullptr) ==
2943 return MaybeCst && MaybeCst->getBitWidth() <= 64 &&
2944 MaybeCst->getSExtValue() ==
C;
2951 std::optional<FPValueAndVReg> MaybeCst;
2955 return MaybeCst->Value.isExactlyValue(
C);
2959 unsigned OpIdx)
const {
2960 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2965 MI.eraseFromParent();
2970 assert(
MI.getNumExplicitDefs() == 1 &&
"Expected one explicit def?");
2974 MI.eraseFromParent();
2978 unsigned ConstIdx)
const {
2979 Register ConstReg =
MI.getOperand(ConstIdx).getReg();
2980 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
2992 assert((
MI.getOpcode() == TargetOpcode::G_FSHL ||
2993 MI.getOpcode() == TargetOpcode::G_FSHR) &&
2994 "This is not a funnel shift operation");
2996 Register ConstReg =
MI.getOperand(3).getReg();
2997 LLT ConstTy =
MRI.getType(ConstReg);
2998 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3001 assert((VRegAndVal) &&
"Value is not a constant");
3004 APInt NewConst = VRegAndVal->Value.
urem(
3009 MI.getOpcode(), {MI.getOperand(0)},
3010 {MI.getOperand(1), MI.getOperand(2), NewConstInstr.getReg(0)});
3012 MI.eraseFromParent();
3016 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
3030 unsigned OpIdx)
const {
3037 unsigned OpIdx)
const {
3039 return MO.
isReg() &&
3044 unsigned OpIdx)
const {
3051 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3053 MI.eraseFromParent();
3058 assert(
MI.getNumDefs() == 1 &&
"Expected only one def?");
3060 MI.eraseFromParent();
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();
3083 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3086 Register &NewLHS = std::get<0>(MatchInfo);
3087 Register &NewRHS = std::get<1>(MatchInfo);
3095 NewLHS = MaybeNewLHS;
3099 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
3104 assert(
MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT &&
3107 LLT DstTy =
MRI.getType(DstReg);
3116 if (
MRI.hasOneUse(DstReg) &&
MRI.use_instr_begin(DstReg)->getOpcode() ==
3117 TargetOpcode::G_INSERT_VECTOR_ELT)
3123 MatchInfo.
resize(NumElts);
3127 if (IntImm >= NumElts || IntImm < 0)
3129 if (!MatchInfo[IntImm])
3130 MatchInfo[IntImm] = TmpReg;
3134 if (CurrInst->
getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
3136 if (TmpInst->
getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
3145 return TmpInst->
getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
3152 auto GetUndef = [&]() {
3155 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3163 Builder.buildBuildVector(
MI.getOperand(0).getReg(), MatchInfo);
3164 MI.eraseFromParent();
3168 MachineInstr &
MI, std::tuple<Register, Register> &MatchInfo)
const {
3170 std::tie(SubLHS, SubRHS) = MatchInfo;
3171 Builder.buildSub(
MI.getOperand(0).getReg(), SubLHS, SubRHS);
3172 MI.eraseFromParent();
3183 unsigned LogicOpcode =
MI.getOpcode();
3184 assert(LogicOpcode == TargetOpcode::G_AND ||
3185 LogicOpcode == TargetOpcode::G_OR ||
3186 LogicOpcode == TargetOpcode::G_XOR);
3193 if (!
MRI.hasOneNonDBGUse(LHSReg) || !
MRI.hasOneNonDBGUse(RHSReg))
3199 if (!LeftHandInst || !RightHandInst)
3201 unsigned HandOpcode = LeftHandInst->
getOpcode();
3202 if (HandOpcode != RightHandInst->
getOpcode())
3216 if (!XTy.
isValid() || XTy != YTy)
3221 switch (HandOpcode) {
3224 case TargetOpcode::G_ANYEXT:
3225 case TargetOpcode::G_SEXT:
3226 case TargetOpcode::G_ZEXT: {
3230 case TargetOpcode::G_TRUNC: {
3235 LLT DstTy =
MRI.getType(Dst);
3244 case TargetOpcode::G_AND:
3245 case TargetOpcode::G_ASHR:
3246 case TargetOpcode::G_LSHR:
3247 case TargetOpcode::G_SHL: {
3252 ExtraHandOpSrcReg = ZOp.
getReg();
3263 auto NewLogicDst =
MRI.createGenericVirtualRegister(XTy);
3274 if (ExtraHandOpSrcReg.
isValid())
3286 "Expected at least one instr to build?");
3288 assert(InstrToBuild.Opcode &&
"Expected a valid opcode?");
3289 assert(InstrToBuild.OperandFns.size() &&
"Expected at least one operand?");
3291 for (
auto &OperandFn : InstrToBuild.OperandFns)
3294 MI.eraseFromParent();
3298 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3299 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3300 int64_t ShlCst, AshrCst;
3306 if (ShlCst != AshrCst)
3309 {TargetOpcode::G_SEXT_INREG, {
MRI.getType(Src)}}))
3311 MatchInfo = std::make_tuple(Src, ShlCst);
3316 MachineInstr &
MI, std::tuple<Register, int64_t> &MatchInfo)
const {
3317 assert(
MI.getOpcode() == TargetOpcode::G_ASHR);
3320 std::tie(Src, ShiftAmt) = MatchInfo;
3321 unsigned Size =
MRI.getType(Src).getScalarSizeInBits();
3322 Builder.buildSExtInReg(
MI.getOperand(0).getReg(), Src,
Size - ShiftAmt);
3323 MI.eraseFromParent();
3330 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3333 LLT Ty =
MRI.getType(Dst);
3345 B.buildAnd(Dst, R,
B.buildConstant(Ty, C1 & C2));
3348 auto Zero =
B.buildConstant(Ty, 0);
3371 assert(
MI.getOpcode() == TargetOpcode::G_AND);
3395 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3402 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3419 assert(
MI.getOpcode() == TargetOpcode::G_OR);
3437 (LHSBits.
One | RHSBits.
Zero).isAllOnes()) {
3444 (LHSBits.
Zero | RHSBits.
One).isAllOnes()) {
3455 unsigned ExtBits =
MI.getOperand(2).getImm();
3456 unsigned TypeSize =
MRI.getType(Src).getScalarSizeInBits();
3457 return VT->computeNumSignBits(Src) >= (
TypeSize - ExtBits + 1);
3461 int64_t Cst,
bool IsVector,
bool IsFP) {
3463 return (ScalarSizeBits == 1 && Cst == -1) ||
3485 unsigned BuildUseCount = BV.getNumSources();
3486 if (BuildUseCount % 2 != 0)
3489 unsigned NumUnmerge = BuildUseCount / 2;
3495 if (!Unmerge || Unmerge->getNumDefs() != NumUnmerge)
3498 UnmergeSrc = Unmerge->getSourceReg();
3500 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
3501 LLT UnmergeSrcTy =
MRI.getType(UnmergeSrc);
3508 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {DstTy, UnmergeSrcTy}}))
3513 for (
unsigned I = 0;
I < NumUnmerge; ++
I) {
3514 auto MaybeUnmergeReg = BV.getSourceReg(
I);
3517 if (!LoopUnmerge || LoopUnmerge != Unmerge)
3520 if (LoopUnmerge->getOperand(
I).getReg() != MaybeUnmergeReg)
3525 if (Unmerge->getNumDefs() != NumUnmerge)
3529 for (
unsigned I = NumUnmerge;
I < BuildUseCount; ++
I) {
3532 if (Undef->getOpcode() != TargetOpcode::G_IMPLICIT_DEF)
3543 assert(UnmergeSrc &&
"Expected there to be one matching G_UNMERGE_VALUES");
3544 B.setInstrAndDebugLoc(
MI);
3546 Register UndefVec =
B.buildUndef(
MRI.getType(UnmergeSrc)).getReg(0);
3547 B.buildConcatVectors(
MI.getOperand(0), {UnmergeSrc, UndefVec});
3549 MI.eraseFromParent();
3571 unsigned NumOperands =
BuildMI->getNumSources();
3579 for (
I = 0;
I < NumOperands; ++
I) {
3580 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3581 auto SrcMIOpc = SrcMI->getOpcode();
3584 if (SrcMIOpc == TargetOpcode::G_TRUNC) {
3586 UnmergeMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3587 if (UnmergeMI->
getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
3590 auto UnmergeSrcMI =
MRI.getVRegDef(SrcMI->getOperand(1).getReg());
3591 if (UnmergeMI != UnmergeSrcMI)
3602 for (;
I < NumOperands; ++
I) {
3603 auto SrcMI =
MRI.getVRegDef(
BuildMI->getSourceReg(
I));
3604 auto SrcMIOpc = SrcMI->getOpcode();
3606 if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
3612 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3619 LLT UnmergeDstEltTy =
MRI.getType(UnmergeDstReg);
3620 if (UnmergeSrcEltTy != UnmergeDstEltTy)
3628 !
isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
3631 if (!
isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
3643 LLT DstTy =
MRI.getType(DstReg);
3644 LLT UnmergeSrcTy =
MRI.getType(MatchInfo);
3649 if (DstTyNumElt / UnmergeSrcTyNumElt == 1) {
3654 for (
unsigned I = 1;
I < DstTyNumElt / UnmergeSrcTyNumElt; ++
I)
3658 MidReg =
Builder.buildConcatVectors(MidTy, ConcatRegs).getReg(0);
3661 Builder.buildTrunc(DstReg, MidReg);
3662 MI.eraseFromParent();
3667 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3668 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
3669 const auto &TLI = *
Builder.getMF().getSubtarget().getTargetLowering();
3677 if (!
MRI.hasOneNonDBGUse(XorSrc))
3687 for (
unsigned I = 0;
I < RegsToNegate.
size(); ++
I) {
3689 if (!
MRI.hasOneNonDBGUse(Reg))
3692 switch (Def->getOpcode()) {
3697 case TargetOpcode::G_ICMP:
3703 case TargetOpcode::G_FCMP:
3709 case TargetOpcode::G_AND:
3710 case TargetOpcode::G_OR:
3716 RegsToNegate.
push_back(Def->getOperand(1).getReg());
3717 RegsToNegate.
push_back(Def->getOperand(2).getReg());
3725 if (Ty.isVector()) {
3730 if (!
isConstValidTrue(TLI, Ty.getScalarSizeInBits(), *MaybeCst,
true, IsFP))
3744 for (
Register Reg : RegsToNegate) {
3749 switch (Def->getOpcode()) {
3752 case TargetOpcode::G_ICMP:
3753 case TargetOpcode::G_FCMP: {
3760 case TargetOpcode::G_AND:
3761 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_OR));
3763 case TargetOpcode::G_OR:
3764 Def->setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3771 MI.eraseFromParent();
3775 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3777 assert(
MI.getOpcode() == TargetOpcode::G_XOR);
3781 Register SharedReg =
MI.getOperand(2).getReg();
3795 if (!
MRI.hasOneNonDBGUse(AndReg))
3802 return Y == SharedReg;
3806 MachineInstr &
MI, std::pair<Register, Register> &MatchInfo)
const {
3809 std::tie(
X,
Y) = MatchInfo;
3812 MI.setDesc(
Builder.getTII().get(TargetOpcode::G_AND));
3813 MI.getOperand(1).setReg(Not->getOperand(0).getReg());
3814 MI.getOperand(2).setReg(
Y);
3820 Register DstReg = PtrAdd.getReg(0);
3821 LLT Ty =
MRI.getType(DstReg);
3824 if (
DL.isNonIntegralAddressSpace(Ty.getScalarType().getAddressSpace()))
3827 if (Ty.isPointer()) {
3829 return ConstVal && *ConstVal == 0;
3832 assert(Ty.isVector() &&
"Expecting a vector type");
3839 Builder.buildIntToPtr(PtrAdd.getReg(0), PtrAdd.getOffsetReg());
3840 PtrAdd.eraseFromParent();
3847 Register Pow2Src1 =
MI.getOperand(2).getReg();
3848 LLT Ty =
MRI.getType(DstReg);
3851 auto NegOne =
Builder.buildConstant(Ty, -1);
3852 auto Add =
Builder.buildAdd(Ty, Pow2Src1, NegOne);
3854 MI.eraseFromParent();
3858 unsigned &SelectOpNo)
const {
3868 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3869 !
MRI.hasOneNonDBGUse(LHS)) {
3870 OtherOperandReg = LHS;
3873 if (
Select->getOpcode() != TargetOpcode::G_SELECT ||
3874 !
MRI.hasOneNonDBGUse(RHS))
3890 unsigned BinOpcode =
MI.getOpcode();
3895 bool CanFoldNonConst =
3896 (BinOpcode == TargetOpcode::G_AND || BinOpcode == TargetOpcode::G_OR) &&
3901 if (CanFoldNonConst)
3922 LLT Ty =
MRI.getType(Dst);
3923 unsigned BinOpcode =
MI.getOpcode();
3930 if (SelectOperand == 1) {
3934 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {SelectTrue, RHS}).
getReg(0);
3936 Builder.buildInstr(BinOpcode, {Ty}, {SelectFalse, RHS}).
getReg(0);
3938 FoldTrue =
Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectTrue}).
getReg(0);
3940 Builder.buildInstr(BinOpcode, {Ty}, {LHS, SelectFalse}).
getReg(0);
3943 Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse,
MI.getFlags());
3944 MI.eraseFromParent();
3947std::optional<SmallVector<Register, 8>>
3948CombinerHelper::findCandidatesForLoadOrCombine(
const MachineInstr *Root)
const {
3949 assert(Root->
getOpcode() == TargetOpcode::G_OR &&
"Expected G_OR only!");
3978 const unsigned MaxIter =
3980 for (
unsigned Iter = 0; Iter < MaxIter; ++Iter) {
3988 if (!
MRI.hasOneNonDBGUse(OrLHS) || !
MRI.hasOneNonDBGUse(OrRHS))
3989 return std::nullopt;
4005 if (RegsToVisit.
empty() || RegsToVisit.
size() % 2 != 0)
4006 return std::nullopt;
4018static std::optional<std::pair<GZExtLoad *, int64_t>>
4022 "Expected Reg to only have one non-debug use?");
4031 if (Shift % MemSizeInBits != 0)
4032 return std::nullopt;
4037 return std::nullopt;
4039 if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits)
4040 return std::nullopt;
4042 return std::make_pair(Load, Shift / MemSizeInBits);
4045std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
4046CombinerHelper::findLoadOffsetsForLoadOrCombine(
4049 const unsigned MemSizeInBits)
const {
4052 SmallSetVector<const MachineInstr *, 8> Loads;
4058 GZExtLoad *LowestIdxLoad =
nullptr;
4061 SmallSet<int64_t, 8> SeenIdx;
4065 MachineBasicBlock *
MBB =
nullptr;
4066 const MachineMemOperand *MMO =
nullptr;
4069 GZExtLoad *EarliestLoad =
nullptr;
4072 GZExtLoad *LatestLoad =
nullptr;
4081 for (
auto Reg : RegsToVisit) {
4086 return std::nullopt;
4089 std::tie(Load, DstPos) = *LoadAndPos;
4093 MachineBasicBlock *LoadMBB =
Load->getParent();
4097 return std::nullopt;
4100 auto &LoadMMO =
Load->getMMO();
4104 return std::nullopt;
4111 LoadPtr =
Load->getOperand(1).getReg();
4116 if (!SeenIdx.
insert(Idx).second)
4117 return std::nullopt;
4124 if (BasePtr != LoadPtr)
4125 return std::nullopt;
4127 if (Idx < LowestIdx) {
4129 LowestIdxLoad =
Load;
4136 if (!MemOffset2Idx.
try_emplace(DstPos, Idx).second)
4137 return std::nullopt;
4145 if (!EarliestLoad ||
dominates(*Load, *EarliestLoad))
4146 EarliestLoad =
Load;
4147 if (!LatestLoad ||
dominates(*LatestLoad, *Load))
4154 "Expected to find a load for each register?");
4155 assert(EarliestLoad != LatestLoad && EarliestLoad &&
4156 LatestLoad &&
"Expected at least two loads?");
4165 const unsigned MaxIter = 20;
4171 if (
MI.isLoadFoldBarrier())
4172 return std::nullopt;
4173 if (Iter++ == MaxIter)
4174 return std::nullopt;
4177 return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad);
4183 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4196 LLT Ty =
MRI.getType(Dst);
4202 const unsigned WideMemSizeInBits = Ty.getSizeInBits();
4203 if (WideMemSizeInBits < 16 || WideMemSizeInBits % 8 != 0)
4207 auto RegsToVisit = findCandidatesForLoadOrCombine(&
MI);
4214 const unsigned NarrowMemSizeInBits = WideMemSizeInBits / RegsToVisit->size();
4215 if (NarrowMemSizeInBits % 8 != 0)
4228 auto MaybeLoadInfo = findLoadOffsetsForLoadOrCombine(
4229 MemOffset2Idx, *RegsToVisit, NarrowMemSizeInBits);
4232 std::tie(LowestIdxLoad, LowestIdx, LatestLoad) = *MaybeLoadInfo;
4239 std::optional<bool> IsBigEndian =
isBigEndian(MemOffset2Idx, LowestIdx);
4242 bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian;
4254 const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
4255 const unsigned ZeroByteOffset =
4259 auto ZeroOffsetIdx = MemOffset2Idx.
find(ZeroByteOffset);
4260 if (ZeroOffsetIdx == MemOffset2Idx.
end() ||
4261 ZeroOffsetIdx->second != LowestIdx)
4271 {TargetOpcode::G_LOAD, {Ty,
MRI.getType(Ptr)}, {MMDesc}}))
4285 MIB.setInstrAndDebugLoc(*LatestLoad);
4286 Register LoadDst = NeedsBSwap ?
MRI.cloneVirtualRegister(Dst) : Dst;
4287 MIB.buildLoad(LoadDst, Ptr, *NewMMO);
4289 MIB.buildBSwap(Dst, LoadDst);
4301 if (
MRI.getType(DstReg).isVector())
4305 if (!
MRI.hasOneNonDBGUse(DstReg))
4307 ExtMI = &*
MRI.use_instr_nodbg_begin(DstReg);
4309 case TargetOpcode::G_ANYEXT:
4311 case TargetOpcode::G_ZEXT:
4312 case TargetOpcode::G_SEXT:
4319 if (
Builder.getTII().isExtendLikelyToBeFolded(*ExtMI,
MRI))
4326 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4328 switch (
DefMI->getOpcode()) {
4329 case TargetOpcode::G_LOAD:
4330 case TargetOpcode::G_TRUNC:
4331 case TargetOpcode::G_SEXT:
4332 case TargetOpcode::G_ZEXT:
4333 case TargetOpcode::G_ANYEXT:
4334 case TargetOpcode::G_CONSTANT:
4338 if (InSrcs.
size() > 2)
4352 LLT ExtTy =
MRI.getType(DstReg);
4359 for (
unsigned I = 0;
I <
PHI.getNumIncomingValues(); ++
I) {
4360 auto SrcReg =
PHI.getIncomingValue(
I);
4361 auto *SrcMI =
MRI.getVRegDef(SrcReg);
4362 if (!SrcMIs.
insert(SrcMI))
4366 auto *
MBB = SrcMI->getParent();
4368 if (InsertPt !=
MBB->end() && InsertPt->isPHI())
4369 InsertPt =
MBB->getFirstNonPHI();
4371 Builder.setInsertPt(*SrcMI->getParent(), InsertPt);
4374 OldToNewSrcMap[SrcMI] = NewExt;
4379 auto NewPhi =
Builder.buildInstrNoInsert(TargetOpcode::G_PHI);
4380 NewPhi.addDef(DstReg);
4383 NewPhi.addMBB(MO.getMBB());
4386 auto *NewSrc = OldToNewSrcMap[
MRI.getVRegDef(MO.getReg())];
4387 NewPhi.addUse(NewSrc->getOperand(0).getReg());
4395 assert(
MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT);
4399 LLT SrcTy =
MRI.getType(SrcVec);
4400 if (SrcTy.isScalableVector())
4404 if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements())
4407 unsigned VecIdx = Cst->Value.getZExtValue();
4412 if (SrcVecMI->
getOpcode() == TargetOpcode::G_TRUNC) {
4416 if (SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR &&
4417 SrcVecMI->
getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC)
4421 if (!
MRI.hasOneNonDBGUse(SrcVec) &&
4433 LLT ScalarTy =
MRI.getType(Reg);
4435 LLT DstTy =
MRI.getType(DstReg);
4437 if (ScalarTy != DstTy) {
4439 Builder.buildTrunc(DstReg, Reg);
4440 MI.eraseFromParent();
4448 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4449 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4467 LLT DstTy =
MRI.getType(DstReg);
4472 if (
II.getOpcode() != TargetOpcode::G_EXTRACT_VECTOR_ELT)
4477 unsigned Idx = Cst->getZExtValue();
4480 ExtractedElts.
set(Idx);
4481 SrcDstPairs.emplace_back(
4482 std::make_pair(
MI.getOperand(Idx + 1).getReg(), &
II));
4485 return ExtractedElts.
all();
4490 SmallVectorImpl<std::pair<Register, MachineInstr *>> &SrcDstPairs)
const {
4491 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
4492 for (
auto &Pair : SrcDstPairs) {
4493 auto *ExtMI = Pair.second;
4495 ExtMI->eraseFromParent();
4497 MI.eraseFromParent();
4504 MI.eraseFromParent();
4514 bool AllowScalarConstants,
4516 assert(
MI.getOpcode() == TargetOpcode::G_OR);
4519 LLT Ty =
MRI.getType(Dst);
4520 unsigned BitWidth = Ty.getScalarSizeInBits();
4522 Register ShlSrc, ShlAmt, LShrSrc, LShrAmt, Amt;
4523 unsigned FshOpc = 0;
4534 int64_t CstShlAmt = 0, CstLShrAmt;
4537 CstShlAmt + CstLShrAmt ==
BitWidth) {
4538 FshOpc = TargetOpcode::G_FSHR;
4544 FshOpc = TargetOpcode::G_FSHL;
4549 FshOpc = TargetOpcode::G_FSHR;
4554 LLT AmtTy =
MRI.getType(Amt);
4556 (!AllowScalarConstants || CstShlAmt == 0 || !Ty.isScalar()))
4560 B.buildInstr(FshOpc, {Dst}, {ShlSrc, LShrSrc, Amt});
4567 unsigned Opc =
MI.getOpcode();
4568 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4573 unsigned RotateOpc =
4574 Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
4579 unsigned Opc =
MI.getOpcode();
4580 assert(
Opc == TargetOpcode::G_FSHL ||
Opc == TargetOpcode::G_FSHR);
4581 bool IsFSHL =
Opc == TargetOpcode::G_FSHL;
4583 MI.setDesc(
Builder.getTII().get(IsFSHL ? TargetOpcode::G_ROTL
4584 : TargetOpcode::G_ROTR));
4585 MI.removeOperand(2);
4591 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4592 MI.getOpcode() == TargetOpcode::G_ROTR);
4594 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4596 bool OutOfRange =
false;
4597 auto MatchOutOfRange = [Bitsize, &OutOfRange](
const Constant *
C) {
4599 OutOfRange |= CI->getValue().uge(Bitsize);
4606 assert(
MI.getOpcode() == TargetOpcode::G_ROTL ||
4607 MI.getOpcode() == TargetOpcode::G_ROTR);
4609 MRI.getType(
MI.getOperand(0).getReg()).getScalarSizeInBits();
4611 LLT AmtTy =
MRI.getType(Amt);
4612 auto Bits =
Builder.buildConstant(AmtTy, Bitsize);
4613 Amt =
Builder.buildURem(AmtTy,
MI.getOperand(2).getReg(), Bits).getReg(0);
4615 MI.getOperand(2).setReg(Amt);
4620 int64_t &MatchInfo)
const {
4621 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4632 auto KnownRHS =
VT->getKnownBits(
MI.getOperand(3).getReg());
4633 if (KnownRHS.isUnknown())
4636 std::optional<bool> KnownVal;
4637 if (KnownRHS.isZero()) {
4647 auto KnownLHS =
VT->getKnownBits(
MI.getOperand(2).getReg());
4657 MRI.getType(
MI.getOperand(0).getReg()).isVector(),
4666 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
4682 LLT DstTy =
MRI.getType(Dst);
4690 auto KnownLHS =
VT->getKnownBits(LHS);
4691 if (KnownLHS.getMinValue() != 0 || KnownLHS.getMaxValue() != 1)
4694 LLT LHSTy =
MRI.getType(LHS);
4697 unsigned Op = TargetOpcode::COPY;
4698 if (DstSize != LHSSize)
4699 Op = DstSize < LHSSize ? TargetOpcode::G_TRUNC : TargetOpcode::G_ZEXT;
4710 assert(
MI.getOpcode() == TargetOpcode::G_AND);
4714 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
4720 int64_t AndMaskBits;
4728 if (AndMaskBits & OrMaskBits)
4734 if (
MI.getOperand(1).getReg() == AndMaskReg)
4735 MI.getOperand(2).setReg(AndMaskReg);
4736 MI.getOperand(1).setReg(Src);
4746 assert(
MI.getOpcode() == TargetOpcode::G_SEXT_INREG);
4749 LLT Ty =
MRI.getType(Src);
4751 if (!
LI || !
LI->isLegalOrCustom({TargetOpcode::G_SBFX, {Ty, ExtractTy}}))
4753 int64_t Width =
MI.getOperand(2).getImm();
4761 if (ShiftImm < 0 || ShiftImm + Width > Ty.getScalarSizeInBits())
4765 auto Cst1 =
B.buildConstant(ExtractTy, ShiftImm);
4766 auto Cst2 =
B.buildConstant(ExtractTy, Width);
4767 B.buildSbfx(Dst, ShiftSrc, Cst1, Cst2);
4777 LLT Ty =
MRI.getType(Dst);
4781 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4784 int64_t AndImm, LSBImm;
4786 const unsigned Size = Ty.getScalarSizeInBits();
4793 auto MaybeMask =
static_cast<uint64_t>(AndImm);
4794 if (MaybeMask & (MaybeMask + 1))
4803 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4804 auto LSBCst =
B.buildConstant(ExtractTy, LSBImm);
4805 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {ShiftSrc, LSBCst, WidthCst});
4813 const unsigned Opcode =
MI.getOpcode();
4814 assert(Opcode == TargetOpcode::G_ASHR || Opcode == TargetOpcode::G_LSHR);
4816 const Register Dst =
MI.getOperand(0).getReg();
4818 const unsigned ExtrOpcode = Opcode == TargetOpcode::G_ASHR
4819 ? TargetOpcode::G_SBFX
4820 : TargetOpcode::G_UBFX;
4823 LLT Ty =
MRI.getType(Dst);
4825 if (!
LI || !
LI->isLegalOrCustom({ExtrOpcode, {Ty, ExtractTy}}))
4831 const unsigned Size = Ty.getScalarSizeInBits();
4841 if (ShlAmt < 0 || ShlAmt > ShrAmt || ShrAmt >=
Size)
4845 if (Opcode == TargetOpcode::G_ASHR && ShlAmt == ShrAmt)
4849 const int64_t Pos = ShrAmt - ShlAmt;
4850 const int64_t Width =
Size - ShrAmt;
4853 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4854 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4855 B.buildInstr(ExtrOpcode, {Dst}, {ShlSrc, PosCst, WidthCst});
4863 const unsigned Opcode =
MI.getOpcode();
4864 assert(Opcode == TargetOpcode::G_LSHR || Opcode == TargetOpcode::G_ASHR);
4866 const Register Dst =
MI.getOperand(0).getReg();
4867 LLT Ty =
MRI.getType(Dst);
4869 if (
LI && !
LI->isLegalOrCustom({TargetOpcode::G_UBFX, {Ty, ExtractTy}}))
4882 const unsigned Size = Ty.getScalarSizeInBits();
4883 if (ShrAmt < 0 || ShrAmt >=
Size)
4887 if (0 == (SMask >> ShrAmt)) {
4889 B.buildConstant(Dst, 0);
4895 uint64_t UMask = SMask;
4902 const int64_t Pos = ShrAmt;
4907 if (Opcode == TargetOpcode::G_ASHR && Width + ShrAmt ==
Size)
4911 auto WidthCst =
B.buildConstant(ExtractTy, Width);
4912 auto PosCst =
B.buildConstant(ExtractTy, Pos);
4913 B.buildInstr(TargetOpcode::G_UBFX, {Dst}, {AndSrc, PosCst, WidthCst});
4918bool CombinerHelper::reassociationCanBreakAddressingModePattern(
4922 Register Src1Reg = PtrAdd.getBaseReg();
4927 Register Src2Reg = PtrAdd.getOffsetReg();
4929 if (
MRI.hasOneNonDBGUse(Src1Reg))
4939 const APInt &C1APIntVal = *C1;
4940 const APInt &C2APIntVal = *C2;
4941 const int64_t CombinedValue = (C1APIntVal + C2APIntVal).getSExtValue();
4943 for (
auto &
UseMI :
MRI.use_nodbg_instructions(PtrAdd.getReg(0))) {
4946 MachineInstr *ConvUseMI = &
UseMI;
4947 unsigned ConvUseOpc = ConvUseMI->
getOpcode();
4948 while (ConvUseOpc == TargetOpcode::G_INTTOPTR ||
4949 ConvUseOpc == TargetOpcode::G_PTRTOINT) {
4951 if (!
MRI.hasOneNonDBGUse(DefReg))
4953 ConvUseMI = &*
MRI.use_instr_nodbg_begin(DefReg);
4962 TargetLoweringBase::AddrMode AM;
4965 unsigned AS =
MRI.getType(LdStMI->getPointerReg()).getAddressSpace();
4967 PtrAdd.getMF()->getFunction().getContext());
4968 const auto &TLI = *PtrAdd.getMF()->getSubtarget().getTargetLowering();
4969 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4975 if (!TLI.isLegalAddressingMode(PtrAdd.getMF()->getDataLayout(), AM,
4987 Register Src1Reg =
MI.getOperand(1).getReg();
4988 if (RHS->getOpcode() != TargetOpcode::G_ADD)
5000 unsigned PtrAddFlags =
MI.getFlags();
5001 unsigned AddFlags = RHS->getFlags();
5014 LLT PtrTy =
MRI.getType(
MI.getOperand(0).getReg());
5017 Builder.buildPtrAdd(PtrTy, Src1Reg, RHS->getOperand(1).getReg(), Flags);
5019 MI.getOperand(1).setReg(NewBase.getReg(0));
5020 MI.getOperand(2).setReg(RHS->getOperand(2).getReg());
5024 return !reassociationCanBreakAddressingModePattern(
MI);
5034 std::optional<ValueAndVReg> LHSCstOff;
5044 unsigned PtrAddFlags =
MI.getFlags();
5045 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5047 bool IsNoUSWrap = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5049 bool IsInBounds = IsNoUWrap && (PtrAddFlags & LHSPtrAddFlags &
5063 LHSPtrAdd->moveBefore(&
MI);
5066 auto NewCst =
B.buildConstant(
MRI.getType(RHSReg), LHSCstOff->Value);
5068 MI.getOperand(2).setReg(NewCst.getReg(0));
5071 Observer.changingInstr(*LHSPtrAdd);
5072 LHSPtrAdd->getOperand(2).setReg(RHSReg);
5073 LHSPtrAdd->setFlags(Flags);
5076 return !reassociationCanBreakAddressingModePattern(
MI);
5087 Register Src2Reg =
MI.getOperand(2).getReg();
5088 Register LHSSrc1 = LHSPtrAdd->getBaseReg();
5089 Register LHSSrc2 = LHSPtrAdd->getOffsetReg();
5102 unsigned PtrAddFlags =
MI.getFlags();
5103 unsigned LHSPtrAddFlags = LHSPtrAdd->getFlags();
5116 auto NewCst =
B.buildConstant(
MRI.getType(Src2Reg), *C1 + *C2);
5118 MI.getOperand(1).setReg(LHSSrc1);
5119 MI.getOperand(2).setReg(NewCst.getReg(0));
5123 return !reassociationCanBreakAddressingModePattern(
MI);
5161 LLT OpRHSTy =
MRI.getType(OpRHS);
5180 auto NewCst =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSRHS, OpRHS});
5181 B.buildInstr(
Opc, {DstReg}, {OpLHSLHS, NewCst});
5189 auto NewLHSLHS =
B.buildInstr(
Opc, {OpRHSTy}, {OpLHSLHS, OpRHS});
5190 B.buildInstr(
Opc, {DstReg}, {NewLHSLHS, OpLHSRHS});
5203 unsigned Opc =
MI.getOpcode();
5216 APInt &MatchInfo)
const {
5217 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
5221 MatchInfo = *MaybeCst;
5229 APInt &MatchInfo)
const {
5235 MatchInfo = *MaybeCst;
5247 ConstantFP::get(
MI.getMF()->getFunction().getContext(), *MaybeCst);
5253 assert(
MI.getOpcode() == TargetOpcode::G_FMA ||
5254 MI.getOpcode() == TargetOpcode::G_FMAD);
5255 auto [
_, Op1, Op2, Op3] =
MI.getFirst4Regs();
5272 MatchInfo = ConstantFP::get(
MI.getMF()->getFunction().getContext(), Op1F);
5295 assert(
MI.getOpcode() == TargetOpcode::G_AND);
5299 LLT WideTy =
MRI.getType(Dst);
5303 if (!WideTy.
isScalar() || !
MRI.hasOneNonDBGUse(AndLHS))
5319 case TargetOpcode::G_ADD:
5320 case TargetOpcode::G_SUB:
5321 case TargetOpcode::G_MUL:
5322 case TargetOpcode::G_AND:
5323 case TargetOpcode::G_OR:
5324 case TargetOpcode::G_XOR:
5332 auto Mask = Cst->Value;
5337 unsigned NarrowWidth = Mask.countr_one();
5343 auto &MF = *
MI.getMF();
5346 if (!TLI.isTruncateFree(WideTy, NarrowTy, Ctx) ||
5347 !TLI.isZExtFree(NarrowTy, WideTy, Ctx))
5355 auto NarrowLHS =
Builder.buildTrunc(NarrowTy, BinOpLHS);
5356 auto NarrowRHS =
Builder.buildTrunc(NarrowTy, BinOpRHS);
5358 Builder.buildInstr(LHSOpc, {NarrowTy}, {NarrowLHS, NarrowRHS});
5359 auto Ext =
Builder.buildZExt(WideTy, NarrowBinOp);
5361 MI.getOperand(1).setReg(Ext.getReg(0));
5369 unsigned Opc =
MI.getOpcode();
5370 assert(
Opc == TargetOpcode::G_UMULO ||
Opc == TargetOpcode::G_SMULO);
5377 unsigned NewOpc =
Opc == TargetOpcode::G_UMULO ? TargetOpcode::G_UADDO
5378 : TargetOpcode::G_SADDO;
5379 MI.setDesc(
Builder.getTII().get(NewOpc));
5380 MI.getOperand(3).setReg(
MI.getOperand(2).getReg());
5389 assert(
MI.getOpcode() == TargetOpcode::G_UMULO ||
5390 MI.getOpcode() == TargetOpcode::G_SMULO);
5399 B.buildConstant(Dst, 0);
5400 B.buildConstant(Carry, 0);
5409 assert(
MI.getOpcode() == TargetOpcode::G_UADDE ||
5410 MI.getOpcode() == TargetOpcode::G_SADDE ||
5411 MI.getOpcode() == TargetOpcode::G_USUBE ||
5412 MI.getOpcode() == TargetOpcode::G_SSUBE);
5417 switch (
MI.getOpcode()) {
5418 case TargetOpcode::G_UADDE:
5419 NewOpcode = TargetOpcode::G_UADDO;
5421 case TargetOpcode::G_SADDE:
5422 NewOpcode = TargetOpcode::G_SADDO;
5424 case TargetOpcode::G_USUBE:
5425 NewOpcode = TargetOpcode::G_USUBO;
5427 case TargetOpcode::G_SSUBE:
5428 NewOpcode = TargetOpcode::G_SSUBO;
5432 MI.setDesc(
B.getTII().get(NewOpcode));
5433 MI.removeOperand(4);
5441 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
5474 auto Zero =
B.buildConstant(
MRI.getType(Dst), 0);
5475 B.buildSub(Dst, Zero, ReplaceReg);
5484 unsigned Opcode =
MI.getOpcode();
5485 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5487 Register Dst = UDivorRem.getReg(0);
5488 Register LHS = UDivorRem.getReg(1);
5489 Register RHS = UDivorRem.getReg(2);
5490 LLT Ty =
MRI.getType(Dst);
5498 bool UseSRL =
false;
5503 auto BuildExactUDIVPattern = [&](
const Constant *
C) {
5505 if (IsSplat && !Factors.
empty()) {
5512 APInt Divisor = CI->getValue();
5521 Shifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5522 Factors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5532 if (Ty.isVector()) {
5533 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5534 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5537 Factor = Factors[0];
5545 return MIB.buildMul(Ty, Res, Factor);
5548 unsigned KnownLeadingZeros =
5549 VT ?
VT->getKnownBits(LHS).countMinLeadingZeros() : 0;
5551 bool UseNPQ =
false;
5553 auto BuildUDIVPattern = [&](
const Constant *
C) {
5555 const APInt &Divisor = CI->getValue();
5557 bool SelNPQ =
false;
5559 unsigned PreShift = 0, PostShift = 0;
5564 if (!Divisor.
isOne()) {
5570 Divisor, std::min(KnownLeadingZeros, Divisor.
countl_zero()));
5572 Magic = std::move(magics.
Magic);
5575 "We shouldn't generate an undefined shift!");
5577 "We shouldn't generate an undefined shift!");
5581 SelNPQ = magics.
IsAdd;
5585 MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0));
5586 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0));
5588 MIB.buildConstant(ScalarTy,
5593 MIB.buildConstant(ScalarShiftAmtTy, PostShift).getReg(0));
5601 assert(Matched &&
"Expected unary predicate match to succeed");
5603 Register PreShift, PostShift, MagicFactor, NPQFactor;
5606 PreShift = MIB.buildBuildVector(ShiftAmtTy, PreShifts).getReg(0);
5607 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5608 NPQFactor = MIB.buildBuildVector(Ty, NPQFactors).getReg(0);
5609 PostShift = MIB.buildBuildVector(ShiftAmtTy, PostShifts).getReg(0);
5612 "Non-build_vector operation should have been a scalar");
5613 PreShift = PreShifts[0];
5614 MagicFactor = MagicFactors[0];
5615 PostShift = PostShifts[0];
5619 Q = MIB.buildLShr(Ty, Q, PreShift).getReg(0);
5622 Q = MIB.buildUMulH(Ty, Q, MagicFactor).getReg(0);
5625 Register NPQ = MIB.buildSub(Ty, LHS, Q).getReg(0);
5630 NPQ = MIB.buildUMulH(Ty, NPQ, NPQFactor).getReg(0);
5632 NPQ = MIB.buildLShr(Ty, NPQ, MIB.buildConstant(ShiftAmtTy, 1)).getReg(0);
5634 Q = MIB.buildAdd(Ty, NPQ, Q).getReg(0);
5637 Q = MIB.buildLShr(Ty, Q, PostShift).getReg(0);
5638 auto One = MIB.buildConstant(Ty, 1);
5639 auto IsOne = MIB.buildICmp(
5641 Ty.isScalar() ?
LLT::scalar(1) : Ty.changeElementSize(1), RHS, One);
5642 auto ret = MIB.buildSelect(Ty, IsOne, LHS, Q);
5644 if (Opcode == TargetOpcode::G_UREM) {
5645 auto Prod = MIB.buildMul(Ty, ret, RHS);
5646 return MIB.buildSub(Ty, LHS, Prod);
5652 unsigned Opcode =
MI.getOpcode();
5653 assert(Opcode == TargetOpcode::G_UDIV || Opcode == TargetOpcode::G_UREM);
5656 LLT DstTy =
MRI.getType(Dst);
5658 auto &MF = *
MI.getMF();
5659 AttributeList Attr = MF.getFunction().getAttributes();
5667 if (MF.getFunction().hasMinSize())
5670 if (Opcode == TargetOpcode::G_UDIV &&
5673 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5676 auto *RHSDef =
MRI.getVRegDef(RHS);
5687 {TargetOpcode::G_ICMP,
5691 if (Opcode == TargetOpcode::G_UREM &&
5697 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5706 unsigned Opcode =
MI.getOpcode();
5707 assert(Opcode == TargetOpcode::G_SDIV || Opcode == TargetOpcode::G_SREM);
5710 LLT DstTy =
MRI.getType(Dst);
5714 auto &MF = *
MI.getMF();
5715 AttributeList Attr = MF.getFunction().getAttributes();
5723 if (MF.getFunction().hasMinSize())
5727 if (Opcode == TargetOpcode::G_SDIV &&
5730 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5733 auto *RHSDef =
MRI.getVRegDef(RHS);
5741 if (!
isLegal({TargetOpcode::G_SMULH, {DstTy}}) &&
5744 if (Opcode == TargetOpcode::G_SREM &&
5750 MRI, RHS, [](
const Constant *
C) {
return C && !
C->isNullValue(); });
5759 unsigned Opcode =
MI.getOpcode();
5760 assert(
MI.getOpcode() == TargetOpcode::G_SDIV ||
5761 Opcode == TargetOpcode::G_SREM);
5763 Register Dst = SDivorRem.getReg(0);
5764 Register LHS = SDivorRem.getReg(1);
5765 Register RHS = SDivorRem.getReg(2);
5766 LLT Ty =
MRI.getType(Dst);
5773 bool UseSRA =
false;
5779 auto BuildExactSDIVPattern = [&](
const Constant *
C) {
5781 if (IsSplat && !ExactFactors.
empty()) {
5783 ExactFactors.
push_back(ExactFactors[0]);
5788 APInt Divisor = CI->getValue();
5798 ExactShifts.
push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0));
5799 ExactFactors.
push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0));
5807 assert(Matched &&
"Expected unary predicate match to succeed");
5810 if (Ty.isVector()) {
5811 Shift = MIB.buildBuildVector(ShiftAmtTy, ExactShifts).getReg(0);
5812 Factor = MIB.buildBuildVector(Ty, ExactFactors).getReg(0);
5814 Shift = ExactShifts[0];
5815 Factor = ExactFactors[0];
5823 return MIB.buildMul(Ty, Res, Factor);
5828 auto BuildSDIVPattern = [&](
const Constant *
C) {
5830 const APInt &Divisor = CI->getValue();
5834 int NumeratorFactor = 0;
5845 NumeratorFactor = 1;
5848 NumeratorFactor = -1;
5851 MagicFactors.
push_back(MIB.buildConstant(ScalarTy, Magics.
Magic).getReg(0));
5852 Factors.
push_back(MIB.buildConstant(ScalarTy, NumeratorFactor).getReg(0));
5854 MIB.buildConstant(ScalarShiftAmtTy, Magics.
ShiftAmount).getReg(0));
5855 ShiftMasks.
push_back(MIB.buildConstant(ScalarTy, ShiftMask).getReg(0));
5863 assert(Matched &&
"Expected unary predicate match to succeed");
5865 Register MagicFactor, Factor, Shift, ShiftMask;
5868 MagicFactor = MIB.buildBuildVector(Ty, MagicFactors).getReg(0);
5869 Factor = MIB.buildBuildVector(Ty, Factors).getReg(0);
5870 Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0);
5871 ShiftMask = MIB.buildBuildVector(Ty, ShiftMasks).getReg(0);
5874 "Non-build_vector operation should have been a scalar");
5875 MagicFactor = MagicFactors[0];
5876 Factor = Factors[0];
5878 ShiftMask = ShiftMasks[0];
5882 Q = MIB.buildSMulH(Ty, LHS, MagicFactor).getReg(0);
5885 Factor = MIB.buildMul(Ty, LHS, Factor).getReg(0);
5886 Q = MIB.buildAdd(Ty, Q, Factor).getReg(0);
5889 Q = MIB.buildAShr(Ty, Q, Shift).getReg(0);
5892 auto SignShift = MIB.buildConstant(ShiftAmtTy, EltBits - 1);
5893 auto T = MIB.buildLShr(Ty, Q, SignShift);
5894 T = MIB.buildAnd(Ty,
T, ShiftMask);
5895 auto ret = MIB.buildAdd(Ty, Q,
T);
5897 if (Opcode == TargetOpcode::G_SREM) {
5898 auto Prod = MIB.buildMul(Ty, ret, RHS);
5899 return MIB.buildSub(Ty, LHS, Prod);
5905 assert((
MI.getOpcode() == TargetOpcode::G_SDIV ||
5906 MI.getOpcode() == TargetOpcode::G_UDIV) &&
5907 "Expected SDIV or UDIV");
5910 auto MatchPow2 = [&](
const Constant *
C) {
5912 return CI && (CI->getValue().isPowerOf2() ||
5913 (IsSigned && CI->getValue().isNegatedPowerOf2()));
5919 assert(
MI.getOpcode() == TargetOpcode::G_SDIV &&
"Expected SDIV");
5924 LLT Ty =
MRI.getType(Dst);
5944 unsigned BitWidth = Ty.getScalarSizeInBits();
5945 auto Zero =
Builder.buildConstant(Ty, 0);
5948 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5949 auto Inexact =
Builder.buildSub(ShiftAmtTy, Bits, C1);
5951 auto Sign =
Builder.buildAShr(
5955 auto LSrl =
Builder.buildLShr(Ty, Sign, Inexact);
5961 auto One =
Builder.buildConstant(Ty, 1);
5962 auto MinusOne =
Builder.buildConstant(Ty, -1);
5966 auto IsOneOrMinusOne =
Builder.buildOr(CCVT, IsOne, IsMinusOne);
5967 AShr =
Builder.buildSelect(Ty, IsOneOrMinusOne, LHS, AShr);
5971 auto Neg =
Builder.buildNeg(Ty, AShr);
5973 Builder.buildSelect(
MI.getOperand(0).getReg(), IsNeg, Neg, AShr);
5974 MI.eraseFromParent();
5978 assert(
MI.getOpcode() == TargetOpcode::G_UDIV &&
"Expected UDIV");
5983 LLT Ty =
MRI.getType(Dst);
5986 auto C1 =
Builder.buildCTTZ(ShiftAmtTy, RHS);
5987 Builder.buildLShr(
MI.getOperand(0).getReg(), LHS, C1);
5988 MI.eraseFromParent();
5992 assert(
MI.getOpcode() == TargetOpcode::G_UMULH);
5995 LLT Ty =
MRI.getType(Dst);
5996 LLT RHSTy =
MRI.getType(RHS);
5998 auto MatchPow2ExceptOne = [&](
const Constant *
C) {
6000 return CI->getValue().isPowerOf2() && !CI->getValue().isOne();
6015 LLT Ty =
MRI.getType(Dst);
6021 Builder.buildSub(Ty,
Builder.buildConstant(Ty, NumEltBits), LogBase2);
6022 auto Trunc =
Builder.buildZExtOrTrunc(ShiftAmtTy, ShiftAmt);
6023 Builder.buildLShr(Dst, LHS, Trunc);
6024 MI.eraseFromParent();
6031 LLT DstTy =
MRI.getType(Dst);
6032 LLT SrcTy =
MRI.getType(Src);
6034 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6035 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6037 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_S, {DstTy, SrcTy}}))
6055 Builder.buildTruncSSatS(Dst, MatchInfo);
6056 MI.eraseFromParent();
6063 LLT DstTy =
MRI.getType(Dst);
6064 LLT SrcTy =
MRI.getType(Src);
6066 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6067 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6069 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6087 Builder.buildTruncSSatU(Dst, MatchInfo);
6088 MI.eraseFromParent();
6095 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6096 LLT SrcTy =
MRI.getType(Val);
6098 unsigned NumSrcBits = SrcTy.getScalarSizeInBits();
6099 assert(NumSrcBits > NumDstBits &&
"Unexpected types for truncate operation");
6101 if (!
LI || !
isLegal({TargetOpcode::G_TRUNC_SSAT_U, {DstTy, SrcTy}}))
6110 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6119 unsigned Opc =
MI.getOpcode();
6120 assert(
Opc == TargetOpcode::G_FADD ||
Opc == TargetOpcode::G_FSUB ||
6121 Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6122 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA);
6134 Opc = TargetOpcode::G_FSUB;
6139 Opc = TargetOpcode::G_FADD;
6145 else if ((
Opc == TargetOpcode::G_FMUL ||
Opc == TargetOpcode::G_FDIV ||
6146 Opc == TargetOpcode::G_FMAD ||
Opc == TargetOpcode::G_FMA) &&
6155 MI.setDesc(
B.getTII().get(
Opc));
6156 MI.getOperand(1).setReg(
X);
6157 MI.getOperand(2).setReg(
Y);
6165 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6168 MatchInfo =
MI.getOperand(2).getReg();
6169 LLT Ty =
MRI.getType(
MI.getOperand(0).getReg());
6171 const auto LHSCst = Ty.isVector()
6178 if (LHSCst->Value.isNegZero())
6182 if (LHSCst->Value.isPosZero())
6192 Dst,
Builder.buildFCanonicalize(
MRI.getType(Dst), MatchInfo).getReg(0));
6199 if (
MI.getOpcode() != TargetOpcode::G_FMUL)
6207 MRI.use_instr_nodbg_end()) >
6209 MRI.use_instr_nodbg_end());
6213 bool &AllowFusionGlobally,
6215 bool CanReassociate)
const {
6217 auto *MF =
MI.getMF();
6218 const auto &TLI = *MF->getSubtarget().getTargetLowering();
6220 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6228 bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) &&
6231 if (!HasFMAD && !HasFMA)
6239 Aggressive = TLI.enableAggressiveFMAFusion(DstType);
6246 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6248 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6256 unsigned PreferredFusedOpcode =
6257 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6271 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6272 {LHS.MI->getOperand(1).getReg(),
6273 LHS.MI->getOperand(2).getReg(), RHS.Reg});
6282 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6283 {RHS.MI->getOperand(1).getReg(),
6284 RHS.MI->getOperand(2).getReg(), LHS.Reg});
6295 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6297 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6301 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6306 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6308 unsigned PreferredFusedOpcode =
6309 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6323 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6328 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6329 {FpExtX.getReg(0), FpExtY.getReg(0), RHS.Reg});
6338 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6343 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6344 {FpExtX.getReg(0), FpExtY.getReg(0), LHS.Reg});
6355 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6357 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6365 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6367 unsigned PreferredFusedOpcode =
6368 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6381 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6382 (
MRI.getVRegDef(LHS.MI->getOperand(3).getReg())->getOpcode() ==
6383 TargetOpcode::G_FMUL) &&
6384 MRI.hasOneNonDBGUse(LHS.MI->getOperand(0).getReg()) &&
6385 MRI.hasOneNonDBGUse(LHS.MI->getOperand(3).getReg())) {
6390 else if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6391 (
MRI.getVRegDef(RHS.MI->getOperand(3).getReg())->getOpcode() ==
6392 TargetOpcode::G_FMUL) &&
6393 MRI.hasOneNonDBGUse(RHS.MI->getOperand(0).getReg()) &&
6394 MRI.hasOneNonDBGUse(RHS.MI->getOperand(3).getReg())) {
6401 Register X = FMA->getOperand(1).getReg();
6402 Register Y = FMA->getOperand(2).getReg();
6407 Register InnerFMA =
MRI.createGenericVirtualRegister(DstTy);
6408 B.buildInstr(PreferredFusedOpcode, {InnerFMA}, {U, V, Z});
6409 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6421 assert(
MI.getOpcode() == TargetOpcode::G_FADD);
6423 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6430 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6431 LLT DstType =
MRI.getType(
MI.getOperand(0).getReg());
6437 unsigned PreferredFusedOpcode =
6438 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6451 Register FpExtU =
B.buildFPExt(DstType, U).getReg(0);
6452 Register FpExtV =
B.buildFPExt(DstType, V).getReg(0);
6454 B.buildInstr(PreferredFusedOpcode, {DstType}, {FpExtU, FpExtV, Z})
6456 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6463 if (LHS.MI->getOpcode() == PreferredFusedOpcode &&
6467 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6472 LHS.MI->getOperand(1).getReg(),
6473 LHS.MI->getOperand(2).getReg(),
B);
6484 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6487 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6492 X =
B.buildFPExt(DstType,
X).getReg(0);
6493 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6504 if (RHS.MI->getOpcode() == PreferredFusedOpcode &&
6508 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6513 RHS.MI->getOperand(1).getReg(),
6514 RHS.MI->getOperand(2).getReg(),
B);
6525 FMAMI->
getOpcode() == PreferredFusedOpcode) {
6528 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstType,
6533 X =
B.buildFPExt(DstType,
X).getReg(0);
6534 Y =
B.buildFPExt(DstType,
Y).getReg(0);
6548 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6550 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6558 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6562 int FirstMulHasFewerUses =
true;
6566 FirstMulHasFewerUses =
false;
6568 unsigned PreferredFusedOpcode =
6569 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6572 if (FirstMulHasFewerUses &&
6576 Register NegZ =
B.buildFNeg(DstTy, RHS.Reg).getReg(0);
6577 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6578 {LHS.MI->getOperand(1).getReg(),
6579 LHS.MI->getOperand(2).getReg(), NegZ});
6588 B.buildFNeg(DstTy, RHS.MI->getOperand(1).getReg()).getReg(0);
6589 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6590 {NegY, RHS.MI->getOperand(2).getReg(), LHS.Reg});
6601 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6603 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6609 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6611 unsigned PreferredFusedOpcode =
6612 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6623 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6624 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6636 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6649 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6651 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6657 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6659 unsigned PreferredFusedOpcode =
6660 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6672 Register NegZ =
B.buildFNeg(DstTy, RHSReg).getReg(0);
6673 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6674 {FpExtX, FpExtY, NegZ});
6686 Register NegY =
B.buildFNeg(DstTy, FpExtY).getReg(0);
6689 B.buildInstr(PreferredFusedOpcode, {
MI.getOperand(0).getReg()},
6690 {NegY, FpExtZ, LHSReg});
6701 assert(
MI.getOpcode() == TargetOpcode::G_FSUB);
6703 bool AllowFusionGlobally, HasFMAD,
Aggressive;
6707 const auto &TLI = *
MI.getMF()->getSubtarget().getTargetLowering();
6708 LLT DstTy =
MRI.getType(
MI.getOperand(0).getReg());
6712 unsigned PreferredFusedOpcode =
6713 HasFMAD ? TargetOpcode::G_FMAD : TargetOpcode::G_FMA;
6717 Register FpExtX =
B.buildFPExt(DstTy,
X).getReg(0);
6718 Register FpExtY =
B.buildFPExt(DstTy,
Y).getReg(0);
6719 B.buildInstr(PreferredFusedOpcode, {Dst}, {FpExtX, FpExtY, Z});
6730 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6733 Register FMAReg =
MRI.createGenericVirtualRegister(DstTy);
6736 B.buildFNeg(
MI.getOperand(0).getReg(), FMAReg);
6746 TLI.isFPExtFoldable(
MI, PreferredFusedOpcode, DstTy,
6759 unsigned &IdxToPropagate)
const {
6761 switch (
MI.getOpcode()) {
6764 case TargetOpcode::G_FMINNUM:
6765 case TargetOpcode::G_FMAXNUM:
6766 PropagateNaN =
false;
6768 case TargetOpcode::G_FMINIMUM:
6769 case TargetOpcode::G_FMAXIMUM:
6770 PropagateNaN =
true;
6774 auto MatchNaN = [&](
unsigned Idx) {
6775 Register MaybeNaNReg =
MI.getOperand(Idx).getReg();
6779 IdxToPropagate = PropagateNaN ? Idx : (Idx == 1 ? 2 : 1);
6783 return MatchNaN(1) || MatchNaN(2);
6791 assert(
MI.getOpcode() == TargetOpcode::G_FDIV);
6801 if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
6814 for (
auto &U :
MRI.use_nodbg_instructions(
Y)) {
6815 if (&U == &
MI || U.getParent() !=
MI.getParent())
6817 if (U.getOpcode() == TargetOpcode::G_FDIV &&
6818 U.getOperand(2).getReg() ==
Y && U.getOperand(1).getReg() !=
Y) {
6831 return MatchInfo.
size() >= MinUses;
6839 LLT Ty =
MRI.getType(MatchInfo[0]->getOperand(0).
getReg());
6840 auto Div =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0),
6841 MatchInfo[0]->getOperand(2).getReg(),
6842 MatchInfo[0]->getFlags());
6847 Builder.buildFMul(
MI->getOperand(0).getReg(),
MI->getOperand(1).getReg(),
6848 Div->getOperand(0).getReg(),
MI->getFlags());
6849 MI->eraseFromParent();
6854 assert(
MI.getOpcode() == TargetOpcode::G_ADD &&
"Expected a G_ADD");
6864 Reg == MaybeSameReg;
6866 return CheckFold(LHS, RHS) || CheckFold(RHS, LHS);
6887 LLT DstVecTy =
MRI.getType(
MI.getOperand(0).getReg());
6896 return MRI.getType(MatchInfo) == DstVecTy;
6899 std::optional<ValueAndVReg> ShiftAmount;
6908 return MRI.getType(MatchInfo) == DstVecTy;
6923 return MRI.getType(MatchInfo) ==
MRI.getType(
MI.getOperand(0).getReg());
6930 std::optional<ValueAndVReg> ShiftAmt;
6936 LLT MatchTy =
MRI.getType(MatchInfo);
6937 return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() &&
6938 MatchTy ==
MRI.getType(
MI.getOperand(0).getReg());
6941unsigned CombinerHelper::getFPMinMaxOpcForSelect(
6943 SelectPatternNaNBehaviour VsNaNRetVal)
const {
6944 assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE &&
6945 "Expected a NaN behaviour?");
6955 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6956 return TargetOpcode::G_FMAXNUM;
6957 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6958 return TargetOpcode::G_FMAXIMUM;
6959 if (
isLegal({TargetOpcode::G_FMAXNUM, {DstTy}}))
6960 return TargetOpcode::G_FMAXNUM;
6961 if (
isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}}))
6962 return TargetOpcode::G_FMAXIMUM;
6968 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER)
6969 return TargetOpcode::G_FMINNUM;
6970 if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN)
6971 return TargetOpcode::G_FMINIMUM;
6972 if (
isLegal({TargetOpcode::G_FMINNUM, {DstTy}}))
6973 return TargetOpcode::G_FMINNUM;
6974 if (!
isLegal({TargetOpcode::G_FMINIMUM, {DstTy}}))
6976 return TargetOpcode::G_FMINIMUM;
6980CombinerHelper::SelectPatternNaNBehaviour
6982 bool IsOrderedComparison)
const {
6986 if (!LHSSafe && !RHSSafe)
6987 return SelectPatternNaNBehaviour::NOT_APPLICABLE;
6988 if (LHSSafe && RHSSafe)
6989 return SelectPatternNaNBehaviour::RETURNS_ANY;
6992 if (IsOrderedComparison)
6993 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN
6994 : SelectPatternNaNBehaviour::RETURNS_OTHER;
6997 return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER
6998 : SelectPatternNaNBehaviour::RETURNS_NAN;
7007 LLT DstTy =
MRI.getType(Dst);
7020 SelectPatternNaNBehaviour ResWithKnownNaNInfo =
7022 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE)
7024 if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
7027 if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN)
7028 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER;
7029 else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER)
7030 ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN;
7032 if (TrueVal != CmpLHS || FalseVal != CmpRHS)
7035 unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo);
7040 if (
Opc != TargetOpcode::G_FMAXIMUM &&
Opc != TargetOpcode::G_FMINIMUM) {
7045 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) {
7047 if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero())
7051 MatchInfo = [=](MachineIRBuilder &
B) {
7052 B.buildInstr(
Opc, {Dst}, {CmpLHS, CmpRHS});
7060 assert(
MI.getOpcode() == TargetOpcode::G_SELECT);
7067 Register TrueVal =
MI.getOperand(2).getReg();
7068 Register FalseVal =
MI.getOperand(3).getReg();
7069 return matchFPSelectToMinMax(Dst,
Cond, TrueVal, FalseVal, MatchInfo);
7074 assert(
MI.getOpcode() == TargetOpcode::G_ICMP);
7087 if (MatchedSub &&
X != OpLHS)
7095 Y =
X == OpLHS ? OpRHS :
X == OpRHS ? OpLHS :
Register();
7098 auto Zero =
B.buildConstant(
MRI.getType(
Y), 0);
7099 B.buildICmp(Pred, Dst,
Y, Zero);
7106static std::optional<unsigned>
7108 std::optional<int64_t> &Result) {
7109 assert((Opcode == TargetOpcode::G_SHL || Opcode == TargetOpcode::G_LSHR ||
7110 Opcode == TargetOpcode::G_ASHR) &&
7111 "Expect G_SHL, G_LSHR or G_ASHR.");
7112 auto SignificantBits = 0;
7114 case TargetOpcode::G_SHL:
7118 case TargetOpcode::G_LSHR:
7122 case TargetOpcode::G_ASHR:
7131 Result = std::nullopt;
7142 Register ShiftVal =
MI.getOperand(1).getReg();
7143 Register ShiftReg =
MI.getOperand(2).getReg();
7144 LLT ResTy =
MRI.getType(
MI.getOperand(0).getReg());
7145 auto IsShiftTooBig = [&](
const Constant *
C) {
7150 MatchInfo = std::nullopt;
7154 MI.getOpcode(), MatchInfo);
7155 return OptMaxUsefulShift && CI->uge(*OptMaxUsefulShift);
7161 unsigned LHSOpndIdx = 1;
7162 unsigned RHSOpndIdx = 2;
7163 switch (
MI.getOpcode()) {
7164 case TargetOpcode::G_UADDO:
7165 case TargetOpcode::G_SADDO:
7166 case TargetOpcode::G_UMULO:
7167 case TargetOpcode::G_SMULO:
7174 Register LHS =
MI.getOperand(LHSOpndIdx).getReg();
7175 Register RHS =
MI.getOperand(RHSOpndIdx).getReg();
7180 if (
MRI.getVRegDef(LHS)->getOpcode() !=
7181 TargetOpcode::G_CONSTANT_FOLD_BARRIER)
7185 return MRI.getVRegDef(RHS)->getOpcode() !=
7186 TargetOpcode::G_CONSTANT_FOLD_BARRIER &&
7193 std::optional<FPValueAndVReg> ValAndVReg;
7201 unsigned LHSOpndIdx = 1;
7202 unsigned RHSOpndIdx = 2;
7203 switch (
MI.getOpcode()) {
7204 case TargetOpcode::G_UADDO:
7205 case TargetOpcode::G_SADDO:
7206 case TargetOpcode::G_UMULO:
7207 case TargetOpcode::G_SMULO:
7214 Register LHSReg =
MI.getOperand(LHSOpndIdx).getReg();
7215 Register RHSReg =
MI.getOperand(RHSOpndIdx).getReg();
7216 MI.getOperand(LHSOpndIdx).setReg(RHSReg);
7217 MI.getOperand(RHSOpndIdx).setReg(LHSReg);
7221bool CombinerHelper::isOneOrOneSplat(
Register Src,
bool AllowUndefs)
const {
7222 LLT SrcTy =
MRI.getType(Src);
7223 if (SrcTy.isFixedVector())
7224 return isConstantSplatVector(Src, 1, AllowUndefs);
7225 if (SrcTy.isScalar()) {
7229 return IConstant && IConstant->Value == 1;
7234bool CombinerHelper::isZeroOrZeroSplat(
Register Src,
bool AllowUndefs)
const {
7235 LLT SrcTy =
MRI.getType(Src);
7237 return isConstantSplatVector(Src, 0, AllowUndefs);
7242 return IConstant && IConstant->Value == 0;
7249bool CombinerHelper::isConstantSplatVector(
Register Src, int64_t SplatValue,
7250 bool AllowUndefs)
const {
7256 for (
unsigned I = 0;
I < NumSources; ++
I) {
7257 GImplicitDef *ImplicitDef =
7259 if (ImplicitDef && AllowUndefs)
7261 if (ImplicitDef && !AllowUndefs)
7263 std::optional<ValueAndVReg> IConstant =
7265 if (IConstant && IConstant->Value == SplatValue)
7275CombinerHelper::getConstantOrConstantSplatVector(
Register Src)
const {
7278 return IConstant->Value;
7282 return std::nullopt;
7285 std::optional<APInt>
Value = std::nullopt;
7286 for (
unsigned I = 0;
I < NumSources; ++
I) {
7287 std::optional<ValueAndVReg> IConstant =
7290 return std::nullopt;
7292 Value = IConstant->Value;
7293 else if (*
Value != IConstant->Value)
7294 return std::nullopt;
7300bool CombinerHelper::isConstantOrConstantVectorI(
Register Src)
const {
7310 for (
unsigned I = 0;
I < NumSources; ++
I) {
7311 std::optional<ValueAndVReg> IConstant =
7320bool CombinerHelper::tryFoldSelectOfConstants(
GSelect *
Select,
7327 LLT CondTy =
MRI.getType(
Select->getCondReg());
7328 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7338 std::optional<ValueAndVReg> TrueOpt =
7340 std::optional<ValueAndVReg> FalseOpt =
7343 if (!TrueOpt || !FalseOpt)
7346 APInt TrueValue = TrueOpt->Value;
7347 APInt FalseValue = FalseOpt->Value;
7351 MatchInfo = [=](MachineIRBuilder &
B) {
7352 B.setInstrAndDebugLoc(*
Select);
7353 B.buildZExtOrTrunc(Dest,
Cond);
7360 MatchInfo = [=](MachineIRBuilder &
B) {
7361 B.setInstrAndDebugLoc(*
Select);
7362 B.buildSExtOrTrunc(Dest,
Cond);
7369 MatchInfo = [=](MachineIRBuilder &
B) {
7370 B.setInstrAndDebugLoc(*
Select);
7371 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7372 B.buildNot(Inner,
Cond);
7373 B.buildZExtOrTrunc(Dest, Inner);
7380 MatchInfo = [=](MachineIRBuilder &
B) {
7381 B.setInstrAndDebugLoc(*
Select);
7382 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7383 B.buildNot(Inner,
Cond);
7384 B.buildSExtOrTrunc(Dest, Inner);
7390 if (TrueValue - 1 == FalseValue) {
7391 MatchInfo = [=](MachineIRBuilder &
B) {
7392 B.setInstrAndDebugLoc(*
Select);
7393 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7394 B.buildZExtOrTrunc(Inner,
Cond);
7395 B.buildAdd(Dest, Inner, False);
7401 if (TrueValue + 1 == FalseValue) {
7402 MatchInfo = [=](MachineIRBuilder &
B) {
7403 B.setInstrAndDebugLoc(*
Select);
7404 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7405 B.buildSExtOrTrunc(Inner,
Cond);
7406 B.buildAdd(Dest, Inner, False);
7413 MatchInfo = [=](MachineIRBuilder &
B) {
7414 B.setInstrAndDebugLoc(*
Select);
7415 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7416 B.buildZExtOrTrunc(Inner,
Cond);
7419 auto ShAmtC =
B.buildConstant(ShiftTy, TrueValue.
exactLogBase2());
7420 B.buildShl(Dest, Inner, ShAmtC, Flags);
7427 MatchInfo = [=](MachineIRBuilder &
B) {
7428 B.setInstrAndDebugLoc(*
Select);
7430 B.buildNot(Not,
Cond);
7431 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7432 B.buildZExtOrTrunc(Inner, Not);
7435 auto ShAmtC =
B.buildConstant(ShiftTy, FalseValue.
exactLogBase2());
7436 B.buildShl(Dest, Inner, ShAmtC, Flags);
7443 MatchInfo = [=](MachineIRBuilder &
B) {
7444 B.setInstrAndDebugLoc(*
Select);
7445 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7446 B.buildSExtOrTrunc(Inner,
Cond);
7447 B.buildOr(Dest, Inner, False, Flags);
7454 MatchInfo = [=](MachineIRBuilder &
B) {
7455 B.setInstrAndDebugLoc(*
Select);
7457 B.buildNot(Not,
Cond);
7458 Register Inner =
MRI.createGenericVirtualRegister(TrueTy);
7459 B.buildSExtOrTrunc(Inner, Not);
7460 B.buildOr(Dest, Inner, True, Flags);
7469bool CombinerHelper::tryFoldBoolSelectToLogic(
GSelect *
Select,
7476 LLT CondTy =
MRI.getType(
Select->getCondReg());
7477 LLT TrueTy =
MRI.getType(
Select->getTrueReg());
7486 if (CondTy != TrueTy)
7491 if ((
Cond == True) || isOneOrOneSplat(True,
true)) {
7492 MatchInfo = [=](MachineIRBuilder &
B) {
7493 B.setInstrAndDebugLoc(*
Select);
7494 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7495 B.buildZExtOrTrunc(Ext,
Cond);
7496 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7497 B.buildOr(DstReg, Ext, FreezeFalse, Flags);
7504 if ((
Cond == False) || isZeroOrZeroSplat(False,
true)) {
7505 MatchInfo = [=](MachineIRBuilder &
B) {
7506 B.setInstrAndDebugLoc(*
Select);
7507 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7508 B.buildZExtOrTrunc(Ext,
Cond);
7509 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7510 B.buildAnd(DstReg, Ext, FreezeTrue);
7516 if (isOneOrOneSplat(False,
true)) {
7517 MatchInfo = [=](MachineIRBuilder &
B) {
7518 B.setInstrAndDebugLoc(*
Select);
7520 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7521 B.buildNot(Inner,
Cond);
7523 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7524 B.buildZExtOrTrunc(Ext, Inner);
7525 auto FreezeTrue =
B.buildFreeze(TrueTy, True);
7526 B.buildOr(DstReg, Ext, FreezeTrue, Flags);
7532 if (isZeroOrZeroSplat(True,
true)) {
7533 MatchInfo = [=](MachineIRBuilder &
B) {
7534 B.setInstrAndDebugLoc(*
Select);
7536 Register Inner =
MRI.createGenericVirtualRegister(CondTy);
7537 B.buildNot(Inner,
Cond);
7539 Register Ext =
MRI.createGenericVirtualRegister(TrueTy);
7540 B.buildZExtOrTrunc(Ext, Inner);
7541 auto FreezeFalse =
B.buildFreeze(TrueTy, False);
7542 B.buildAnd(DstReg, Ext, FreezeFalse);
7558 LLT DstTy =
MRI.getType(DstReg);
7564 if (!
MRI.hasOneNonDBGUse(Cmp->getReg(0)))
7573 Register CmpLHS = Cmp->getLHSReg();
7574 Register CmpRHS = Cmp->getRHSReg();
7577 if (True == CmpRHS && False == CmpLHS) {
7585 if (True != CmpLHS || False != CmpRHS)
7625 assert(
MI.getOpcode() == TargetOpcode::G_SUB);
7626 Register DestReg =
MI.getOperand(0).getReg();
7627 LLT DestTy =
MRI.getType(DestReg);
7639 if (
isLegal({NewOpc, {DestTy}})) {
7641 B.buildInstr(NewOpc, {DestReg}, {
X, Sub0});
7653 if (tryFoldSelectOfConstants(
Select, MatchInfo))
7656 if (tryFoldBoolSelectToLogic(
Select, MatchInfo))
7666bool CombinerHelper::tryFoldAndOrOrICmpsUsingRanges(
7668 assert(Logic->
getOpcode() != TargetOpcode::G_XOR &&
"unexpected xor");
7669 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7673 unsigned Flags = Logic->
getFlags();
7686 if (!
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7692 std::optional<ValueAndVReg> MaybeC1 =
7696 C1 = MaybeC1->Value;
7698 std::optional<ValueAndVReg> MaybeC2 =
7702 C2 = MaybeC2->Value;
7709 LLT CmpOperandTy =
MRI.getType(R1);
7723 std::optional<APInt> Offset1;
7724 std::optional<APInt> Offset2;
7727 std::optional<ValueAndVReg> MaybeOffset1 =
7730 R1 =
Add->getLHSReg();
7731 Offset1 = MaybeOffset1->Value;
7735 std::optional<ValueAndVReg> MaybeOffset2 =
7738 R2 =
Add->getLHSReg();
7739 Offset2 = MaybeOffset2->Value;
7758 bool CreateMask =
false;
7771 if (!LowerDiff.
isPowerOf2() || LowerDiff != UpperDiff ||
7784 CR->getEquivalentICmp(NewPred, NewC,
Offset);
7793 MatchInfo = [=](MachineIRBuilder &
B) {
7794 if (CreateMask &&
Offset != 0) {
7795 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7796 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7797 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7798 auto Add =
B.buildAdd(CmpOperandTy,
And, OffsetC, Flags);
7799 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7800 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7801 B.buildZExtOrTrunc(DstReg, ICmp);
7802 }
else if (CreateMask &&
Offset == 0) {
7803 auto TildeLowerDiff =
B.buildConstant(CmpOperandTy, ~LowerDiff);
7804 auto And =
B.buildAnd(CmpOperandTy, R1, TildeLowerDiff);
7805 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7806 auto ICmp =
B.buildICmp(NewPred, CmpTy,
And, NewCon);
7807 B.buildZExtOrTrunc(DstReg, ICmp);
7808 }
else if (!CreateMask &&
Offset != 0) {
7809 auto OffsetC =
B.buildConstant(CmpOperandTy,
Offset);
7810 auto Add =
B.buildAdd(CmpOperandTy, R1, OffsetC, Flags);
7811 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7812 auto ICmp =
B.buildICmp(NewPred, CmpTy,
Add, NewCon);
7813 B.buildZExtOrTrunc(DstReg, ICmp);
7814 }
else if (!CreateMask &&
Offset == 0) {
7815 auto NewCon =
B.buildConstant(CmpOperandTy, NewC);
7816 auto ICmp =
B.buildICmp(NewPred, CmpTy, R1, NewCon);
7817 B.buildZExtOrTrunc(DstReg, ICmp);
7825bool CombinerHelper::tryFoldLogicOfFCmps(
GLogicalBinOp *Logic,
7831 bool IsAnd = Logic->
getOpcode() == TargetOpcode::G_AND;
7843 LLT CmpTy =
MRI.getType(Cmp1->
getReg(0));
7849 {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
7850 !
MRI.hasOneNonDBGUse(Logic->
getReg(0)) ||
7851 !
MRI.hasOneNonDBGUse(Cmp1->
getReg(0)) ||
7852 !
MRI.hasOneNonDBGUse(Cmp2->
getReg(0)) ||
7863 if (LHS0 == RHS1 && LHS1 == RHS0) {
7869 if (LHS0 == RHS0 && LHS1 == RHS1) {
7873 unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
7875 MatchInfo = [=](MachineIRBuilder &
B) {
7880 auto False =
B.buildConstant(CmpTy, 0);
7881 B.buildZExtOrTrunc(DestReg, False);
7888 B.buildZExtOrTrunc(DestReg, True);
7890 auto Cmp =
B.buildFCmp(Pred, CmpTy, LHS0, LHS1, Flags);
7891 B.buildZExtOrTrunc(DestReg, Cmp);
7903 if (tryFoldAndOrOrICmpsUsingRanges(
And, MatchInfo))
7906 if (tryFoldLogicOfFCmps(
And, MatchInfo))
7915 if (tryFoldAndOrOrICmpsUsingRanges(
Or, MatchInfo))
7918 if (tryFoldLogicOfFCmps(
Or, MatchInfo))
7933 bool IsSigned =
Add->isSigned();
7934 LLT DstTy =
MRI.getType(Dst);
7935 LLT CarryTy =
MRI.getType(Carry);
7938 if (
MRI.use_nodbg_empty(Carry) &&
7941 B.buildAdd(Dst, LHS, RHS);
7942 B.buildUndef(Carry);
7948 if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
7951 B.buildSAddo(Dst, Carry, RHS, LHS);
7957 B.buildUAddo(Dst, Carry, RHS, LHS);
7962 std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
7963 std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
7969 APInt Result = IsSigned ? MaybeLHS->sadd_ov(*MaybeRHS, Overflow)
7970 : MaybeLHS->uadd_ov(*MaybeRHS, Overflow);
7972 B.buildConstant(Dst, Result);
7973 B.buildConstant(Carry, Overflow);
7981 B.buildCopy(Dst, LHS);
7982 B.buildConstant(Carry, 0);
7991 if (MaybeRHS && AddLHS &&
MRI.hasOneNonDBGUse(
Add->getReg(0)) &&
7994 std::optional<APInt> MaybeAddRHS =
7995 getConstantOrConstantSplatVector(AddLHS->
getRHSReg());
7998 APInt NewC = IsSigned ? MaybeAddRHS->sadd_ov(*MaybeRHS, Overflow)
7999 : MaybeAddRHS->uadd_ov(*MaybeRHS, Overflow);
8003 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8004 B.buildSAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8010 auto ConstRHS =
B.buildConstant(DstTy, NewC);
8011 B.buildUAddo(Dst, Carry, AddLHS->
getLHSReg(), ConstRHS);
8036 B.buildConstant(Carry, 0);
8043 B.buildAdd(Dst, LHS, RHS);
8044 B.buildConstant(Carry, 1);
8056 if (
VT->computeNumSignBits(RHS) > 1 &&
VT->computeNumSignBits(LHS) > 1) {
8059 B.buildConstant(Carry, 0);
8075 B.buildConstant(Carry, 0);
8082 B.buildAdd(Dst, LHS, RHS);
8083 B.buildConstant(Carry, 1);
8101 bool OptForSize =
MI.getMF()->getFunction().hasOptSize();
8107 auto [Dst,
Base] =
MI.getFirst2Regs();
8108 LLT Ty =
MRI.getType(Dst);
8112 Builder.buildFConstant(Dst, 1.0);
8113 MI.removeFromParent();
8125 std::optional<SrcOp> Res;
8127 while (ExpVal > 0) {
8132 Res =
Builder.buildFMul(Ty, *Res, CurSquare);
8135 CurSquare =
Builder.buildFMul(Ty, CurSquare, CurSquare);
8142 Res =
Builder.buildFDiv(Ty,
Builder.buildFConstant(Ty, 1.0), *Res,
8146 MI.eraseFromParent();
8155 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8162 LLT DstTy =
MRI.getType(Dst);
8165 auto Const =
B.buildConstant(DstTy, C1 - C2);
8166 B.buildAdd(Dst,
Add->getLHSReg(), Const);
8178 if (!
MRI.hasOneNonDBGUse(
Add->getReg(0)))
8185 LLT DstTy =
MRI.getType(Dst);
8188 auto Const =
B.buildConstant(DstTy, C2 - C1);
8189 B.buildSub(Dst, Const,
Add->getLHSReg());
8201 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8208 LLT DstTy =
MRI.getType(Dst);
8211 auto Const =
B.buildConstant(DstTy, C1 + C2);
8224 if (!
MRI.hasOneNonDBGUse(Sub2->
getReg(0)))
8231 LLT DstTy =
MRI.getType(Dst);
8234 auto Const =
B.buildConstant(DstTy, C1 - C2);
8247 if (!
MRI.hasOneNonDBGUse(
Sub->getReg(0)))
8254 LLT DstTy =
MRI.getType(Dst);
8257 auto Const =
B.buildConstant(DstTy, C2 - C1);
8258 B.buildAdd(Dst,
Sub->getLHSReg(), Const);
8305 if (!
MRI.hasOneNonDBGUse(BV->getReg(0)))
8309 if (BV->getNumSources() % Unmerge->
getNumDefs() != 0)
8312 LLT BigBvTy =
MRI.getType(BV->getReg(0));
8313 LLT SmallBvTy = DstTy;
8317 {TargetOpcode::G_BUILD_VECTOR, {SmallBvTy, SmallBvElemenTy}}))
8322 {TargetOpcode::G_ANYEXT,
8334 auto AnyExt =
B.buildAnyExt(SmallBvElemenTy, SourceArray);
8335 Ops.push_back(AnyExt.getReg(0));
8353 const LLT SrcTy =
MRI.getType(Shuffle.getSrc1Reg());
8354 const unsigned NumSrcElems = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
8355 const unsigned NumDstElts = OrigMask.
size();
8356 for (
unsigned i = 0; i != NumDstElts; ++i) {
8357 int Idx = OrigMask[i];
8358 if (Idx >= (
int)NumSrcElems) {
8369 B.buildShuffleVector(
MI.getOperand(0),
MI.getOperand(1),
MI.getOperand(2),
8370 std::move(NewMask));
8377 const unsigned MaskSize = Mask.size();
8378 for (
unsigned I = 0;
I < MaskSize; ++
I) {
8383 if (Idx < (
int)NumElems)
8384 Mask[
I] = Idx + NumElems;
8386 Mask[
I] = Idx - NumElems;
8396 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(),
MRI))
8399 if (
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(),
MRI))
8402 const LLT DstTy =
MRI.getType(Shuffle.getReg(0));
8403 const LLT Src1Ty =
MRI.getType(Shuffle.getSrc1Reg());
8405 {TargetOpcode::G_SHUFFLE_VECTOR, {DstTy, Src1Ty}}))
8409 const unsigned NumSrcElems = Src1Ty.getNumElements();
8411 bool TouchesSrc1 =
false;
8412 bool TouchesSrc2 =
false;
8413 const unsigned NumElems = Mask.size();
8414 for (
unsigned Idx = 0; Idx < NumElems; ++Idx) {
8418 if (Mask[Idx] < (
int)NumSrcElems)
8424 if (TouchesSrc1 == TouchesSrc2)
8427 Register NewSrc1 = Shuffle.getSrc1Reg();
8430 NewSrc1 = Shuffle.getSrc2Reg();
8435 auto Undef =
B.buildUndef(Src1Ty);
8436 B.buildShuffleVector(Shuffle.getReg(0), NewSrc1, Undef, NewMask);
8450 LLT DstTy =
MRI.getType(Dst);
8451 LLT CarryTy =
MRI.getType(Carry);
8473 B.buildConstant(Carry, 0);
8480 B.buildSub(Dst, LHS, RHS);
8498 B.buildConstant(Carry, 0);
8505 B.buildSub(Dst, LHS, RHS);
8522 CtlzMI.
getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) &&
8523 "Expected G_CTLZ variant");
8528 LLT Ty =
MRI.getType(Dst);
8529 LLT SrcTy =
MRI.getType(Src);
8531 if (!(Ty.isValid() && Ty.isScalar()))
8540 switch (
LI->getAction(Query).Action) {
8551 bool NeedAdd =
true;
8559 unsigned BitWidth = Ty.getScalarSizeInBits();
8570 B.buildCTLS(Dst,
X);
8574 auto Ctls =
B.buildCTLS(Ty,
X);
8575 auto One =
B.buildConstant(Ty, 1);
8577 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 const fltSemantics & IEEEdouble()
static constexpr roundingMode rmNearestTiesToEven
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 matchOperandIsZero(MachineInstr &MI, unsigned OpIdx) const
Check if operand OpIdx is zero.
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...
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